@dooboostore/simple-web-component 1.0.26 → 1.0.28
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 +216 -3424
- package/dist/cjs/decorators/addEventListener.js +4 -0
- package/dist/cjs/decorators/addEventListener.js.map +2 -2
- package/dist/cjs/decorators/attribute.js +32 -43
- package/dist/cjs/decorators/attribute.js.map +3 -3
- package/dist/cjs/decorators/elementDefine.js +45 -19
- package/dist/cjs/decorators/elementDefine.js.map +2 -2
- package/dist/cjs/decorators/index.js +1 -0
- package/dist/cjs/decorators/index.js.map +2 -2
- package/dist/cjs/decorators/lifecycles.js +5 -5
- package/dist/cjs/decorators/lifecycles.js.map +2 -2
- package/dist/cjs/decorators/query.js +4 -4
- package/dist/cjs/decorators/query.js.map +2 -2
- package/dist/cjs/decorators/queryAll.js +4 -4
- package/dist/cjs/decorators/queryAll.js.map +2 -2
- package/dist/cjs/decorators/subscribeSwcAppRouteChange.js +59 -0
- package/dist/cjs/decorators/subscribeSwcAppRouteChange.js.map +7 -0
- package/dist/cjs/elements/SwcAppEngine.js +18 -63
- package/dist/cjs/elements/SwcAppEngine.js.map +3 -3
- package/dist/cjs/elements/SwcAppMixin.js +103 -24
- package/dist/cjs/elements/SwcAppMixin.js.map +2 -2
- package/dist/cjs/elements/register.js +0 -1
- package/dist/cjs/elements/register.js.map +2 -2
- package/dist/cjs/utils/Utils.js +18 -0
- package/dist/cjs/utils/Utils.js.map +3 -3
- package/dist/esm/decorators/addEventListener.js +4 -0
- package/dist/esm/decorators/addEventListener.js.map +2 -2
- package/dist/esm/decorators/attribute.js +32 -43
- package/dist/esm/decorators/attribute.js.map +3 -3
- package/dist/esm/decorators/elementDefine.js +46 -20
- package/dist/esm/decorators/elementDefine.js.map +2 -2
- package/dist/esm/decorators/index.js +1 -0
- package/dist/esm/decorators/index.js.map +2 -2
- package/dist/esm/decorators/lifecycles.js +5 -5
- package/dist/esm/decorators/lifecycles.js.map +2 -2
- package/dist/esm/decorators/query.js +4 -4
- package/dist/esm/decorators/query.js.map +2 -2
- package/dist/esm/decorators/queryAll.js +4 -4
- package/dist/esm/decorators/queryAll.js.map +2 -2
- package/dist/esm/decorators/subscribeSwcAppRouteChange.js +40 -0
- package/dist/esm/decorators/subscribeSwcAppRouteChange.js.map +7 -0
- package/dist/esm/elements/SwcAppEngine.js +18 -63
- package/dist/esm/elements/SwcAppEngine.js.map +2 -2
- package/dist/esm/elements/SwcAppMixin.js +103 -24
- package/dist/esm/elements/SwcAppMixin.js.map +2 -2
- package/dist/esm/elements/register.js +0 -1
- package/dist/esm/elements/register.js.map +2 -2
- package/dist/esm/utils/Utils.js +18 -0
- package/dist/esm/utils/Utils.js.map +3 -3
- package/dist/esm-bundle/dooboostore-simple-web-component.esm.js +177 -2477
- package/dist/esm-bundle/dooboostore-simple-web-component.esm.js.map +4 -4
- package/dist/types/decorators/addEventListener.d.ts +8 -1
- package/dist/types/decorators/addEventListener.d.ts.map +1 -1
- package/dist/types/decorators/attribute.d.ts +0 -1
- package/dist/types/decorators/attribute.d.ts.map +1 -1
- package/dist/types/decorators/elementDefine.d.ts.map +1 -1
- package/dist/types/decorators/index.d.ts +1 -0
- package/dist/types/decorators/index.d.ts.map +1 -1
- package/dist/types/decorators/lifecycles.d.ts +2 -2
- package/dist/types/decorators/lifecycles.d.ts.map +1 -1
- package/dist/types/decorators/query.d.ts +1 -1
- package/dist/types/decorators/query.d.ts.map +1 -1
- package/dist/types/decorators/queryAll.d.ts +1 -1
- package/dist/types/decorators/queryAll.d.ts.map +1 -1
- package/dist/types/decorators/subscribeSwcAppRouteChange.d.ts +18 -0
- package/dist/types/decorators/subscribeSwcAppRouteChange.d.ts.map +1 -0
- package/dist/types/elements/SwcAppEngine.d.ts +3 -5
- package/dist/types/elements/SwcAppEngine.d.ts.map +1 -1
- package/dist/types/elements/SwcAppMixin.d.ts +9 -0
- 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/utils/Utils.d.ts +3 -0
- package/dist/types/utils/Utils.d.ts.map +1 -1
- package/dist/umd-bundle/dooboostore-simple-web-component.umd.js +177 -2477
- package/dist/umd-bundle/dooboostore-simple-web-component.umd.js.map +4 -4
- package/package.json +2 -2
- package/src/decorators/addEventListener.ts +11 -1
- package/src/decorators/attribute.ts +62 -53
- package/src/decorators/elementDefine.ts +93 -30
- package/src/decorators/index.ts +1 -0
- package/src/decorators/lifecycles.ts +2 -2
- package/src/decorators/query.ts +5 -5
- package/src/decorators/queryAll.ts +8 -7
- package/src/decorators/subscribeSwcAppRouteChange.ts +71 -0
- package/src/elements/SwcAppEngine.ts +25 -81
- package/src/elements/SwcAppMixin.ts +143 -28
- package/src/elements/register.ts +0 -2
- package/src/utils/Utils.ts +33 -0
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.28",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/cjs/index.js",
|
|
@@ -92,9 +92,9 @@
|
|
|
92
92
|
"webpack": "^5.93.0",
|
|
93
93
|
"webpack-cli": "^5.1.4",
|
|
94
94
|
"webpack-dev-server": "^5.2.0",
|
|
95
|
-
"@dooboostore/core": "1.0.30",
|
|
96
95
|
"@dooboostore/core-node": "1.0.12",
|
|
97
96
|
"@dooboostore/core-web": "1.0.10",
|
|
97
|
+
"@dooboostore/core": "1.0.30",
|
|
98
98
|
"@dooboostore/simple-boot": "1.0.54"
|
|
99
99
|
},
|
|
100
100
|
"scripts": {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ReflectUtils } from '@dooboostore/core';
|
|
2
|
-
import { SpecialSelector, SwcQueryOptions } from '../types';
|
|
2
|
+
import { SpecialSelector, SwcQueryOptions, HelperHostSet } from '../types';
|
|
3
3
|
|
|
4
4
|
export interface AddEventListenerBaseOptions extends EventListenerOptions {
|
|
5
5
|
capture?: boolean;
|
|
@@ -10,6 +10,7 @@ export interface AddEventListenerBaseOptions extends EventListenerOptions {
|
|
|
10
10
|
preventDefault?: boolean;
|
|
11
11
|
removeOnDisconnected?: boolean;
|
|
12
12
|
delegate?: boolean;
|
|
13
|
+
filter?: (target: Event | CustomEvent, helper: HelperHostSet) => boolean;
|
|
13
14
|
}
|
|
14
15
|
|
|
15
16
|
export interface AddEventListenerMetadata {
|
|
@@ -53,3 +54,12 @@ export const getAddEventListenerMetadata = (target: any): AddEventListenerMetada
|
|
|
53
54
|
export function addEventListenerHost(type: string, options?: AddEventListenerBaseOptions & SwcQueryOptions): MethodDecorator {
|
|
54
55
|
return addEventListener(':host', type, options);
|
|
55
56
|
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* @addEventListenerAppHost decorator - simplified version of @addEventListener for :appHost selector
|
|
60
|
+
* Usage: @addEventListenerAppHost('click')
|
|
61
|
+
* Usage: @addEventListenerAppHost('click', { stopPropagation: true })
|
|
62
|
+
*/
|
|
63
|
+
export function addEventListenerAppHost(type: string, options?: AddEventListenerBaseOptions & SwcQueryOptions): MethodDecorator {
|
|
64
|
+
return addEventListener(':appHost', type, options);
|
|
65
|
+
}
|
|
@@ -2,10 +2,9 @@ import {ReflectUtils} from '@dooboostore/core';
|
|
|
2
2
|
import {ensureInit, getElementConfig} from './elementDefine';
|
|
3
3
|
import {SwcUtils} from '../utils/Utils';
|
|
4
4
|
import {SpecialSelector, SwcQueryOptions} from '../types';
|
|
5
|
-
|
|
6
5
|
export interface AttributeFieldOptions extends SwcQueryOptions {
|
|
7
6
|
name?: string;
|
|
8
|
-
connectedInitialize?: boolean;
|
|
7
|
+
// connectedInitialize?: boolean;
|
|
9
8
|
type?: typeof Number | typeof Boolean | typeof String;
|
|
10
9
|
}
|
|
11
10
|
|
|
@@ -81,9 +80,9 @@ export function attribute(selector: string, options: AttributeFieldOptions = {})
|
|
|
81
80
|
return (target: Object, propertyKey: string | symbol) => {
|
|
82
81
|
const constructor = target.constructor;
|
|
83
82
|
const privateKey = Symbol(String(propertyKey));
|
|
84
|
-
|
|
83
|
+
//
|
|
85
84
|
const designType = (Reflect as any).getMetadata('design:type', target, propertyKey);
|
|
86
|
-
|
|
85
|
+
//
|
|
87
86
|
let metaList = ReflectUtils.getOwnMetadata(ATTRIBUTE_FIELD_METADATA_KEY, constructor) as AttributeFieldMetadata[];
|
|
88
87
|
if (!metaList) {
|
|
89
88
|
metaList = [];
|
|
@@ -105,56 +104,65 @@ export function attribute(selector: string, options: AttributeFieldOptions = {})
|
|
|
105
104
|
});
|
|
106
105
|
};
|
|
107
106
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
return
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
return convertValue(this[privateKey], targetType);
|
|
131
|
-
},
|
|
132
|
-
set(this: any, nv: any) {
|
|
133
|
-
const attrName = options.name || String(propertyKey);
|
|
134
|
-
const conf = getElementConfig(this);
|
|
135
|
-
const currentWin = this._resolveWindow?.(conf) || ((typeof window !== 'undefined' ? window : undefined) as any);
|
|
107
|
+
try {
|
|
108
|
+
// Own property를 삭제하여 getter가 작동하도록 함
|
|
109
|
+
// delete target[propertyKey];
|
|
110
|
+
|
|
111
|
+
// const defineTarget = target instanceof Function ? target : (target as any).constructor;
|
|
112
|
+
|
|
113
|
+
Object.defineProperty(target, propertyKey, {
|
|
114
|
+
get(this: any) {
|
|
115
|
+
// try {
|
|
116
|
+
const attrName = options.name || String(propertyKey);
|
|
117
|
+
const conf = getElementConfig(this);
|
|
118
|
+
const currentWin = this._resolveWindow?.(conf) || ((typeof window !== 'undefined' ? window : undefined) as any);
|
|
119
|
+
const targetType = options.type || designType;
|
|
120
|
+
//
|
|
121
|
+
// connectedInitialize: true이면 privateKey 값만 반환 (DOM 무시)
|
|
122
|
+
// if (options.connectedInitialize === true && (this as any).__swc_syncing_init) {
|
|
123
|
+
// console.log('cccccccc2');
|
|
124
|
+
// return this[privateKey];
|
|
125
|
+
// // return convertValue(this[privateKey], targetType);
|
|
126
|
+
// }
|
|
136
127
|
|
|
137
|
-
if (this.__swc_syncing_init) {
|
|
138
|
-
if (options.connectedInitialize === true) {
|
|
139
128
|
const targets = resolveTargetEls(this, selector, options, currentWin);
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
129
|
+
const primaryTarget = targets[0];
|
|
130
|
+
|
|
131
|
+
if (primaryTarget && typeof (primaryTarget as any).hasAttribute === 'function') {
|
|
132
|
+
if ((primaryTarget as any).hasAttribute(attrName)) {
|
|
133
|
+
const domVal = (primaryTarget as any).getAttribute(attrName);
|
|
134
|
+
return convertValue(domVal, targetType);
|
|
135
|
+
}
|
|
136
|
+
return null;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
return convertValue(this[privateKey], targetType);
|
|
140
|
+
// } catch (err) {
|
|
141
|
+
// console.error('Error in getter:', err);
|
|
142
|
+
// throw err;
|
|
143
|
+
// }
|
|
144
|
+
},
|
|
145
|
+
set(this: any, nv: any) {
|
|
146
|
+
// this[propertyKey] = nv;
|
|
147
|
+
const attrName = options.name || String(propertyKey);
|
|
148
|
+
const conf = getElementConfig(this);
|
|
149
|
+
const currentWin = this._resolveWindow?.(conf) || ((typeof window !== 'undefined' ? window : undefined) as any);
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
// if (!this.__swc_connected) {
|
|
153
|
+
// this[privateKey] = nv;
|
|
154
|
+
// return;
|
|
155
|
+
// }
|
|
156
|
+
|
|
157
|
+
const targets = resolveTargetEls(this, selector, options, currentWin);
|
|
158
|
+
applySetAttribute(this, targets, attrName, nv);
|
|
159
|
+
},
|
|
160
|
+
enumerable: true,
|
|
161
|
+
configurable: true
|
|
162
|
+
});
|
|
163
|
+
} catch (err) {
|
|
164
|
+
console.error('[SWC] defineProperty error:', err);
|
|
165
|
+
}
|
|
158
166
|
};
|
|
159
167
|
}
|
|
160
168
|
|
|
@@ -187,5 +195,6 @@ export function attributeHost(targetOrAttrOrOptions?: any, propertyKeyOrOptions?
|
|
|
187
195
|
}
|
|
188
196
|
|
|
189
197
|
export const findAllAttributeMetadata = (target: any): AttributeFieldMetadata[] => {
|
|
190
|
-
|
|
198
|
+
const actualTarget = target instanceof Function ? target : target.constructor;
|
|
199
|
+
return ReflectUtils.findAllMetadata<AttributeFieldMetadata[]>(ATTRIBUTE_FIELD_METADATA_KEY, actualTarget).flat();
|
|
191
200
|
};
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { ReflectUtils } from '@dooboostore/core';
|
|
2
2
|
import { FunctionUtils } from '@dooboostore/core';
|
|
3
3
|
import { getAddEventListenerMetadata } from './addEventListener';
|
|
4
|
-
import {
|
|
4
|
+
import { ON_INITIALIZE_METADATA_KEY, ON_BEFORE_CONNECTED_METADATA_KEY, ON_AFTER_CONNECTED_METADATA_KEY, ON_BEFORE_DISCONNECTED_METADATA_KEY, ON_AFTER_DISCONNECTED_METADATA_KEY, ON_BEFORE_ADOPTED_METADATA_KEY, ON_AFTER_ADOPTED_METADATA_KEY, findAllLifecycleMetadata, getOnConnectedInnerHtmlMetadata } from './lifecycles';
|
|
5
5
|
import { getEmitCustomEventMetadataList } from './emitCustomEvent';
|
|
6
6
|
import { findAllAttributeChangedMetadata } from './changedAttributeHost';
|
|
7
7
|
import { findAllAttributeApplyMetadata } from './applyAttribute';
|
|
8
8
|
import { findAllAttributeMetadata } from './attribute';
|
|
9
|
+
import { getQueryMetadata } from './query';
|
|
10
|
+
import { getQueryAllMetadata } from './queryAll';
|
|
9
11
|
import { SwcUtils } from '../utils/Utils';
|
|
10
12
|
import { HTML_TAG_ENTRIES, DOM_EVENT_NAMES } from '../config/config';
|
|
11
13
|
import { SituationTypeContainer, SituationTypeContainers } from '@dooboostore/simple-boot/decorators/inject/Inject';
|
|
@@ -39,12 +41,60 @@ export const ensureInit = (inst: any) => {
|
|
|
39
41
|
inst._boundListeners = [];
|
|
40
42
|
inst.__swc_initialized = true;
|
|
41
43
|
|
|
44
|
+
// const attributeList = findAllQ(inst);
|
|
45
|
+
// attributeList.forEach(meta => {
|
|
46
|
+
// delete (inst as any)[meta.propertyKey];
|
|
47
|
+
// });
|
|
48
|
+
|
|
49
|
+
const target = inst instanceof Function ? inst : inst.constructor;
|
|
50
|
+
|
|
51
|
+
// ╔════════════════════════════════════════════════════════════════════════════════╗
|
|
52
|
+
// ║ decorator 필드의 own property 삭제 ║
|
|
53
|
+
// ║ ║
|
|
54
|
+
// ║ 이유: ║
|
|
55
|
+
// ║ 1. TypeScript는 초기값이 있는 필드를 constructor에서 own property로 생성 ║
|
|
56
|
+
// ║ @attributeHost('id') myId: string = "default" → this.myId = "default" ║
|
|
57
|
+
// ║ ║
|
|
58
|
+
// ║ 2. JavaScript의 property lookup은 own property를 먼저 찾음 ║
|
|
59
|
+
// ║ - this.myId 접근 ║
|
|
60
|
+
// ║ - 1순위: instance의 own property 있나? → 있으면 그것 반환 ║
|
|
61
|
+
// ║ - 2순위: prototype의 getter 있나? → 있으면 호출 ║
|
|
62
|
+
// ║ ║
|
|
63
|
+
// ║ 3. own property가 있으면 prototype의 getter는 절대 호출되지 않음 ║
|
|
64
|
+
// ║ 따라서 getter에서 정의된 DOM 동기화 로직이 작동하지 않음 ║
|
|
65
|
+
// ║ ║
|
|
66
|
+
// ║ 4. own property를 삭제하면 JavaScript가 prototype의 getter를 찾게 됨 ║
|
|
67
|
+
// ║ → getter 호출됨 → DOM 속성 값 동기화됨 ║
|
|
68
|
+
// ╚════════════════════════════════════════════════════════════════════════════════╝
|
|
69
|
+
|
|
70
|
+
// @attribute 필드의 own property 삭제 → getter/setter 작동
|
|
71
|
+
const attributeList = findAllAttributeMetadata(target);
|
|
72
|
+
attributeList.forEach(meta => {
|
|
73
|
+
delete (inst as any)[meta.propertyKey];
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
// @query 필드의 own property 삭제 → getter 작동
|
|
77
|
+
const queryList = getQueryMetadata(target);
|
|
78
|
+
if (queryList) {
|
|
79
|
+
queryList.forEach(meta => {
|
|
80
|
+
delete (inst as any)[meta.propertyKey];
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// @queryAll 필드의 own property 삭제 → getter 작동
|
|
85
|
+
const queryAllList = getQueryAllMetadata(target);
|
|
86
|
+
if (queryAllList) {
|
|
87
|
+
queryAllList.forEach(meta => {
|
|
88
|
+
delete (inst as any)[meta.propertyKey];
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
|
|
42
92
|
// Call constructor script if present
|
|
43
93
|
const hostSet = SwcUtils.getHostSet(inst);
|
|
44
94
|
inst._executeSwcScript?.('swc-on-constructor', hostSet);
|
|
45
95
|
|
|
46
|
-
// Call @
|
|
47
|
-
const cMethods = findAllLifecycleMetadata(inst,
|
|
96
|
+
// Call @onInitialize lifecycle methods
|
|
97
|
+
const cMethods = findAllLifecycleMetadata(inst, ON_INITIALIZE_METADATA_KEY);
|
|
48
98
|
if (cMethods) {
|
|
49
99
|
for (const m of cMethods) (inst)._invokeLifecycleMethod(m, hostSet);
|
|
50
100
|
}
|
|
@@ -79,9 +129,10 @@ function buildEnv(configWindow?: Window) {
|
|
|
79
129
|
const doc: Document = win?.document;
|
|
80
130
|
const builtInTagMap = new Map<any, string>();
|
|
81
131
|
for (const [cls, tag] of HTML_TAG_ENTRIES) {
|
|
82
|
-
if (win?.[cls]) builtInTagMap.set(win[cls], tag);
|
|
132
|
+
if ((win as any)?.[cls]) builtInTagMap.set((win as any)[cls], tag);
|
|
83
133
|
}
|
|
84
134
|
const domHelpers = SwcUtils.getHelperSet(win);
|
|
135
|
+
|
|
85
136
|
return { win, doc, builtInTagMap, domHelpers };
|
|
86
137
|
}
|
|
87
138
|
|
|
@@ -238,15 +289,16 @@ export const elementDefine =
|
|
|
238
289
|
|
|
239
290
|
// Collect all observed attributes from all decorators
|
|
240
291
|
const attributeApplyNames = Array.from(applyAttributeMap.values()).map(it => it.options.name).filter(Boolean) as string[];
|
|
241
|
-
const attributeListNames = attributeList.map(it => it.options.name || String(it.propertyKey));
|
|
242
|
-
|
|
292
|
+
// const attributeListNames = attributeList.map(it => it.options.name || String(it.propertyKey));
|
|
293
|
+
const hostAttributes = attributeList.filter(it => it.selector === ':host').map(it=>it.options.name || String(it.propertyKey));
|
|
294
|
+
|
|
243
295
|
const mergedObservedAttributes = [...new Set([
|
|
244
|
-
...(metadata.observedAttributes ?? []),
|
|
245
|
-
...attrChangeMap.keys(),
|
|
296
|
+
...(metadata.observedAttributes ?? []),
|
|
297
|
+
...attrChangeMap.keys(),
|
|
246
298
|
...attributeApplyNames,
|
|
247
|
-
...
|
|
248
|
-
...emitHostCustomEventList.map(it => (it.options as any).attributeName).filter(Boolean),
|
|
249
|
-
...swcLifecycleAttributes,
|
|
299
|
+
...hostAttributes,
|
|
300
|
+
...emitHostCustomEventList.map(it => (it.options as any).attributeName).filter(Boolean),
|
|
301
|
+
...swcLifecycleAttributes,
|
|
250
302
|
...swcOnEvents
|
|
251
303
|
])];
|
|
252
304
|
|
|
@@ -259,35 +311,21 @@ export const elementDefine =
|
|
|
259
311
|
proto.connectedCallback = function () {
|
|
260
312
|
ensureInit(this);
|
|
261
313
|
|
|
314
|
+
const hostSet = SwcUtils.getHostSet(this as any);
|
|
315
|
+
const appHost = hostSet.$appHost;
|
|
316
|
+
const conf = getElementConfig(this);
|
|
317
|
+
const currentWin = (this as any)._resolveWindow(conf);
|
|
318
|
+
|
|
262
319
|
if (connectedInnerHtmlList.some(it => it.options.useShadow === true) && !this.shadowRoot) {
|
|
263
320
|
this.attachShadow({ mode: 'open' });
|
|
264
321
|
}
|
|
265
322
|
|
|
266
|
-
const conf = getElementConfig(this);
|
|
267
|
-
const currentWin = (this as any)._resolveWindow(conf);
|
|
268
|
-
const hostSet = SwcUtils.getHostSet(this as any);
|
|
269
|
-
|
|
270
323
|
(this as any)._executeSwcScript('swc-on-before-connected', hostSet);
|
|
271
324
|
const bMethods = findAllLifecycleMetadata(this, ON_BEFORE_CONNECTED_METADATA_KEY);
|
|
272
325
|
if (bMethods) {
|
|
273
326
|
for (const m of bMethods) (this as any)._invokeLifecycleMethod(m, hostSet);
|
|
274
327
|
}
|
|
275
328
|
|
|
276
|
-
// Initialize @attribute fields
|
|
277
|
-
attributeList.forEach(meta => {
|
|
278
|
-
if (meta.options.connectedInitialize === true) {
|
|
279
|
-
(this as any).__swc_syncing_init = true;
|
|
280
|
-
try {
|
|
281
|
-
const memoryVal = (this as any)[meta.privateKey];
|
|
282
|
-
if (memoryVal !== undefined) {
|
|
283
|
-
(this as any)[meta.propertyKey] = memoryVal;
|
|
284
|
-
}
|
|
285
|
-
} finally {
|
|
286
|
-
(this as any).__swc_syncing_init = false;
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
|
-
});
|
|
290
|
-
|
|
291
329
|
if (connectedInnerHtmlList.length > 0) {
|
|
292
330
|
let sContent = '',
|
|
293
331
|
lContent = '';
|
|
@@ -358,6 +396,13 @@ export const elementDefine =
|
|
|
358
396
|
const { selector, options } = meta;
|
|
359
397
|
const matchedEl = (event.target as HTMLElement).closest(selector);
|
|
360
398
|
if (matchedEl && (br as any).contains(matchedEl)) {
|
|
399
|
+
// Apply filter if specified
|
|
400
|
+
if (options.filter) {
|
|
401
|
+
const helper = SwcUtils.getHelperAndHostSet(currentWin, matchedEl);
|
|
402
|
+
if (!options.filter(event, helper)) {
|
|
403
|
+
continue; // Skip this listener if filter returns false
|
|
404
|
+
}
|
|
405
|
+
}
|
|
361
406
|
if (options.stopPropagation) event.stopPropagation();
|
|
362
407
|
if (options.stopImmediatePropagation) event.stopImmediatePropagation();
|
|
363
408
|
if (options.preventDefault) event.preventDefault();
|
|
@@ -416,6 +461,13 @@ export const elementDefine =
|
|
|
416
461
|
|
|
417
462
|
bindTargets.forEach(t => {
|
|
418
463
|
const handler = async (event: Event) => {
|
|
464
|
+
// Apply filter if specified
|
|
465
|
+
if (options.filter) {
|
|
466
|
+
const helper = SwcUtils.getHelperAndHostSet(currentWin, t as HTMLElement);
|
|
467
|
+
if (!options.filter(event, helper)) {
|
|
468
|
+
return; // Skip if filter returns false
|
|
469
|
+
}
|
|
470
|
+
}
|
|
419
471
|
if (options.stopPropagation) event.stopPropagation();
|
|
420
472
|
if (options.stopImmediatePropagation) event.stopImmediatePropagation();
|
|
421
473
|
if (options.preventDefault) event.preventDefault();
|
|
@@ -439,6 +491,11 @@ export const elementDefine =
|
|
|
439
491
|
(this as any)._executeSwcScript('swc-on-connected', hostSet);
|
|
440
492
|
(this as any)._executeSwcScript('swc-on-after-connected', hostSet);
|
|
441
493
|
(this as any).__swc_connected = true;
|
|
494
|
+
|
|
495
|
+
// Register to appHost LAST when all lifecycle completed
|
|
496
|
+
if (appHost && typeof (appHost as any)._connected === 'function') {
|
|
497
|
+
(appHost as any)._connected(this);
|
|
498
|
+
}
|
|
442
499
|
};
|
|
443
500
|
|
|
444
501
|
const originalDisconnected = proto.disconnectedCallback;
|
|
@@ -464,6 +521,12 @@ export const elementDefine =
|
|
|
464
521
|
(this as any)._executeSwcScript('swc-on-disconnected', hostSet);
|
|
465
522
|
(this as any)._executeSwcScript('swc-on-after-disconnected', hostSet);
|
|
466
523
|
(this as any).__swc_connected = false;
|
|
524
|
+
|
|
525
|
+
// Remove from appHost LAST when disconnected
|
|
526
|
+
const appHost = hostSet.$appHost;
|
|
527
|
+
if (appHost && typeof (appHost as any)._disconnected === 'function') {
|
|
528
|
+
(appHost as any)._disconnected(this);
|
|
529
|
+
}
|
|
467
530
|
};
|
|
468
531
|
|
|
469
532
|
const originalAdopted = proto.adoptedCallback;
|
package/src/decorators/index.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ReflectUtils } from '@dooboostore/core';
|
|
2
2
|
|
|
3
|
-
export const
|
|
3
|
+
export const ON_INITIALIZE_METADATA_KEY = Symbol.for('simple-web-component:on-constructor');
|
|
4
4
|
export const ON_BEFORE_CONNECTED_METADATA_KEY = Symbol.for('simple-web-component:on-before-connected');
|
|
5
5
|
export const ON_AFTER_CONNECTED_METADATA_KEY = Symbol.for('simple-web-component:on-after-connected');
|
|
6
6
|
export const ON_BEFORE_DISCONNECTED_METADATA_KEY = Symbol.for('simple-web-component:on-before-disconnected');
|
|
@@ -33,7 +33,7 @@ function createLifecycleDecorator(metadataKey: symbol): MethodDecorator {
|
|
|
33
33
|
};
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
export const
|
|
36
|
+
export const onInitialize = createLifecycleDecorator(ON_INITIALIZE_METADATA_KEY);
|
|
37
37
|
export const onBeforeConnected = createLifecycleDecorator(ON_BEFORE_CONNECTED_METADATA_KEY);
|
|
38
38
|
export const onAfterConnected = createLifecycleDecorator(ON_AFTER_CONNECTED_METADATA_KEY);
|
|
39
39
|
export const onConnected = onAfterConnected;
|
package/src/decorators/query.ts
CHANGED
|
@@ -102,11 +102,6 @@ export function query(selectorOrTarget: string, options: any = {}): PropertyDeco
|
|
|
102
102
|
};
|
|
103
103
|
}
|
|
104
104
|
|
|
105
|
-
export const getQueryMetadata = (target: any): QueryMetadata[] | undefined => {
|
|
106
|
-
const constructor = target instanceof Function ? target : target.constructor;
|
|
107
|
-
return ReflectUtils.getMetadata(QUERY_METADATA_KEY, constructor);
|
|
108
|
-
};
|
|
109
|
-
|
|
110
105
|
/**
|
|
111
106
|
* @queryHost decorator - simplified version of @query for :host selector
|
|
112
107
|
* Usage: @queryHost testzzs: HTMLElement | undefined;
|
|
@@ -257,3 +252,8 @@ export function lastAppHost(targetOrOptions?: any, propertyKey?: string | symbol
|
|
|
257
252
|
return query(':lastAppHost', {});
|
|
258
253
|
}
|
|
259
254
|
}
|
|
255
|
+
|
|
256
|
+
export const getQueryMetadata = (target: any): QueryMetadata[] | undefined => {
|
|
257
|
+
const constructor = target instanceof Function ? target : target.constructor;
|
|
258
|
+
return ReflectUtils.getMetadata(QUERY_METADATA_KEY, constructor);
|
|
259
|
+
};
|
|
@@ -102,12 +102,6 @@ export function queryAll(selectorOrTarget: string, options: any = {}): PropertyD
|
|
|
102
102
|
});
|
|
103
103
|
};
|
|
104
104
|
}
|
|
105
|
-
|
|
106
|
-
export const getQueryAllMetadata = (target: any): QueryAllMetadata[] | undefined => {
|
|
107
|
-
const constructor = target instanceof Function ? target : target.constructor;
|
|
108
|
-
return ReflectUtils.getMetadata(QUERY_ALL_METADATA_KEY, constructor);
|
|
109
|
-
};
|
|
110
|
-
|
|
111
105
|
/**
|
|
112
106
|
* @hostQueryAll decorator - simplified version of @queryAll for :host selector
|
|
113
107
|
* Usage: @hostQueryAll()
|
|
@@ -261,4 +255,11 @@ export function allLastAppHost(targetOrOptions?: any, propertyKey?: string | sym
|
|
|
261
255
|
} else {
|
|
262
256
|
return queryAll(':lastAppHost', {});
|
|
263
257
|
}
|
|
264
|
-
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
export const getQueryAllMetadata = (target: any): QueryAllMetadata[] | undefined => {
|
|
262
|
+
const constructor = target instanceof Function ? target : target.constructor;
|
|
263
|
+
return ReflectUtils.getMetadata(QUERY_ALL_METADATA_KEY, constructor);
|
|
264
|
+
};
|
|
265
|
+
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { ReflectUtils } from '@dooboostore/core';
|
|
2
|
+
import { Router } from '@dooboostore/core-web';
|
|
3
|
+
|
|
4
|
+
export const SUBSCRIBE_SWC_APP_ROUTE_CHANGE_METADATA_KEY = Symbol.for('simple-web-component:subscribe-swc-app-route-change');
|
|
5
|
+
|
|
6
|
+
export interface SwcAppRouteChangeSubscriberMetadata {
|
|
7
|
+
propertyKey: string | symbol;
|
|
8
|
+
pathPattern?: string | string[];
|
|
9
|
+
filter?: (router: Router) => boolean;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface SwcAppRouteChangeOptions {
|
|
13
|
+
path?: string | string[];
|
|
14
|
+
filter?: (router: Router) => boolean;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function createSwcAppRouteChangeSubscriber(options?: SwcAppRouteChangeOptions): MethodDecorator {
|
|
18
|
+
return (target: Object, propertyKey: string | symbol, descriptor?: PropertyDescriptor) => {
|
|
19
|
+
const pathPattern = options?.path;
|
|
20
|
+
const filter = options?.filter;
|
|
21
|
+
|
|
22
|
+
const constructor = target.constructor;
|
|
23
|
+
let list = ReflectUtils.getOwnMetadata(SUBSCRIBE_SWC_APP_ROUTE_CHANGE_METADATA_KEY, constructor) as SwcAppRouteChangeSubscriberMetadata[];
|
|
24
|
+
if (!list) {
|
|
25
|
+
list = [];
|
|
26
|
+
ReflectUtils.defineMetadata(SUBSCRIBE_SWC_APP_ROUTE_CHANGE_METADATA_KEY, list, constructor);
|
|
27
|
+
}
|
|
28
|
+
list.push({ propertyKey, pathPattern, filter });
|
|
29
|
+
|
|
30
|
+
return descriptor;
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// 오버로드 시그니처 - 직접 사용 (괄호 없음)
|
|
35
|
+
export function subscribeSwcAppRouteChange(target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor): PropertyDescriptor | void;
|
|
36
|
+
// 오버로드 시그니처 - 함수 호출 (괄호 있음)
|
|
37
|
+
export function subscribeSwcAppRouteChange(): MethodDecorator;
|
|
38
|
+
export function subscribeSwcAppRouteChange(pathPattern: string): MethodDecorator;
|
|
39
|
+
export function subscribeSwcAppRouteChange(pathPatterns: string[]): MethodDecorator;
|
|
40
|
+
export function subscribeSwcAppRouteChange(options: SwcAppRouteChangeOptions): MethodDecorator;
|
|
41
|
+
|
|
42
|
+
// 실제 구현 (이중 모드)
|
|
43
|
+
export function subscribeSwcAppRouteChange(targetOrOptions?: any, propertyKey?: string | symbol, descriptor?: PropertyDescriptor): any {
|
|
44
|
+
// 직접 데코레이터로 사용된 경우 (괄호 없음): @subscribeSwcAppRouteChange
|
|
45
|
+
// propertyKey가 string | symbol이고 descriptor가 있으면 직접 사용
|
|
46
|
+
if (propertyKey && (typeof propertyKey === 'string' || typeof propertyKey === 'symbol')) {
|
|
47
|
+
return createSwcAppRouteChangeSubscriber({})(targetOrOptions, propertyKey, descriptor);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// 함수로 호출된 경우 (괄호 있음): @subscribeSwcAppRouteChange() / @subscribeSwcAppRouteChange('/path')
|
|
51
|
+
let options: SwcAppRouteChangeOptions = {};
|
|
52
|
+
|
|
53
|
+
if (Array.isArray(targetOrOptions)) {
|
|
54
|
+
// 배열: @subscribeSwcAppRouteChange(['/path1', '/path2'])
|
|
55
|
+
options.path = targetOrOptions;
|
|
56
|
+
} else if (typeof targetOrOptions === 'string') {
|
|
57
|
+
// 문자열: @subscribeSwcAppRouteChange('/path')
|
|
58
|
+
options.path = targetOrOptions;
|
|
59
|
+
} else if (targetOrOptions && typeof targetOrOptions === 'object') {
|
|
60
|
+
// 객체: @subscribeSwcAppRouteChange({ path: '/path', filter: ... })
|
|
61
|
+
options = targetOrOptions;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return createSwcAppRouteChangeSubscriber(options);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Helper function to retrieve route change subscribers metadata
|
|
68
|
+
export const getSubscribeSwcAppRouteChangeMetadata = (target: any): SwcAppRouteChangeSubscriberMetadata[] | undefined => {
|
|
69
|
+
const constructor = target instanceof Function ? target : target.constructor;
|
|
70
|
+
return ReflectUtils.getOwnMetadata(SUBSCRIBE_SWC_APP_ROUTE_CHANGE_METADATA_KEY, constructor);
|
|
71
|
+
};
|