@dooboostore/simple-web-component 1.0.47 → 1.0.49
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 +223 -27
- package/dist/cjs/config/config.js +1 -1
- package/dist/cjs/config/config.js.map +2 -2
- package/dist/cjs/decorators/addEventListener.js +412 -16
- package/dist/cjs/decorators/addEventListener.js.map +3 -3
- package/dist/cjs/decorators/applyAttribute.js +25 -0
- package/dist/cjs/decorators/applyAttribute.js.map +2 -2
- package/dist/cjs/decorators/applyClass.js +49 -18
- package/dist/cjs/decorators/applyClass.js.map +3 -3
- package/dist/cjs/decorators/applyNode.js +67 -1
- package/dist/cjs/decorators/applyNode.js.map +3 -3
- package/dist/cjs/decorators/applyProperty.js +101 -3
- package/dist/cjs/decorators/applyProperty.js.map +2 -2
- package/dist/cjs/decorators/applyStyle.js +36 -5
- package/dist/cjs/decorators/applyStyle.js.map +2 -2
- package/dist/cjs/decorators/changedAttribute.js +39 -0
- package/dist/cjs/decorators/changedAttribute.js.map +2 -2
- package/dist/cjs/decorators/elementDefine.js +244 -225
- package/dist/cjs/decorators/elementDefine.js.map +3 -3
- package/dist/cjs/decorators/emitCustomEvent.js +55 -0
- package/dist/cjs/decorators/emitCustomEvent.js.map +2 -2
- package/dist/cjs/decorators/index.js +5 -1
- package/dist/cjs/decorators/index.js.map +2 -2
- package/dist/cjs/decorators/intersectionObserver.js +209 -0
- package/dist/cjs/decorators/intersectionObserver.js.map +7 -0
- package/dist/cjs/decorators/mutationObserver.js +244 -0
- package/dist/cjs/decorators/mutationObserver.js.map +7 -0
- package/dist/cjs/decorators/query.js +129 -102
- package/dist/cjs/decorators/query.js.map +2 -2
- package/dist/cjs/decorators/resizeObserver.js +191 -0
- package/dist/cjs/decorators/resizeObserver.js.map +7 -0
- package/dist/cjs/decorators/setInterval.js +82 -0
- package/dist/cjs/decorators/setInterval.js.map +7 -0
- package/dist/cjs/decorators/setTimeout.js +82 -0
- package/dist/cjs/decorators/setTimeout.js.map +7 -0
- package/dist/cjs/decorators/subscribeSwcAppMessageWhileConnected.js +9 -0
- package/dist/cjs/decorators/subscribeSwcAppMessageWhileConnected.js.map +2 -2
- package/dist/cjs/decorators/subscribeSwcAppRouteChangeWhileConnected.js +9 -0
- package/dist/cjs/decorators/subscribeSwcAppRouteChangeWhileConnected.js.map +2 -2
- package/dist/cjs/examples/RxJSOperatorsExample.js +285 -0
- package/dist/cjs/examples/RxJSOperatorsExample.js.map +7 -0
- package/dist/cjs/types/index.js.map +1 -1
- package/dist/esm/config/config.js +1 -1
- package/dist/esm/config/config.js.map +2 -2
- package/dist/esm/decorators/addEventListener.js +413 -16
- package/dist/esm/decorators/addEventListener.js.map +3 -3
- package/dist/esm/decorators/applyAttribute.js +25 -0
- package/dist/esm/decorators/applyAttribute.js.map +2 -2
- package/dist/esm/decorators/applyClass.js +49 -18
- package/dist/esm/decorators/applyClass.js.map +3 -3
- package/dist/esm/decorators/applyNode.js +67 -1
- package/dist/esm/decorators/applyNode.js.map +3 -3
- package/dist/esm/decorators/applyProperty.js +101 -3
- package/dist/esm/decorators/applyProperty.js.map +2 -2
- package/dist/esm/decorators/applyStyle.js +36 -5
- package/dist/esm/decorators/applyStyle.js.map +2 -2
- package/dist/esm/decorators/changedAttribute.js +40 -0
- package/dist/esm/decorators/changedAttribute.js.map +2 -2
- package/dist/esm/decorators/elementDefine.js +249 -230
- package/dist/esm/decorators/elementDefine.js.map +3 -3
- package/dist/esm/decorators/emitCustomEvent.js +55 -0
- package/dist/esm/decorators/emitCustomEvent.js.map +2 -2
- package/dist/esm/decorators/index.js +5 -1
- package/dist/esm/decorators/index.js.map +2 -2
- package/dist/esm/decorators/intersectionObserver.js +191 -0
- package/dist/esm/decorators/intersectionObserver.js.map +7 -0
- package/dist/esm/decorators/mutationObserver.js +226 -0
- package/dist/esm/decorators/mutationObserver.js.map +7 -0
- package/dist/esm/decorators/query.js +129 -102
- package/dist/esm/decorators/query.js.map +2 -2
- package/dist/esm/decorators/resizeObserver.js +173 -0
- package/dist/esm/decorators/resizeObserver.js.map +7 -0
- package/dist/esm/decorators/setInterval.js +64 -0
- package/dist/esm/decorators/setInterval.js.map +7 -0
- package/dist/esm/decorators/setTimeout.js +64 -0
- package/dist/esm/decorators/setTimeout.js.map +7 -0
- package/dist/esm/decorators/subscribeSwcAppMessageWhileConnected.js +9 -0
- package/dist/esm/decorators/subscribeSwcAppMessageWhileConnected.js.map +2 -2
- package/dist/esm/decorators/subscribeSwcAppRouteChangeWhileConnected.js +9 -0
- package/dist/esm/decorators/subscribeSwcAppRouteChangeWhileConnected.js.map +2 -2
- package/dist/esm/examples/RxJSOperatorsExample.js +266 -0
- package/dist/esm/examples/RxJSOperatorsExample.js.map +7 -0
- package/dist/esm/types/index.js.map +1 -1
- package/dist/esm-bundle/dooboostore-simple-web-component.esm.js +2413 -889
- package/dist/esm-bundle/dooboostore-simple-web-component.esm.js.map +4 -4
- package/dist/types/config/config.d.ts.map +1 -1
- package/dist/types/decorators/addEventListener.d.ts +93 -23
- package/dist/types/decorators/addEventListener.d.ts.map +1 -1
- package/dist/types/decorators/applyAttribute.d.ts +22 -34
- package/dist/types/decorators/applyAttribute.d.ts.map +1 -1
- package/dist/types/decorators/applyClass.d.ts +34 -34
- package/dist/types/decorators/applyClass.d.ts.map +1 -1
- package/dist/types/decorators/applyNode.d.ts +30 -20
- package/dist/types/decorators/applyNode.d.ts.map +1 -1
- package/dist/types/decorators/applyProperty.d.ts +57 -34
- package/dist/types/decorators/applyProperty.d.ts.map +1 -1
- package/dist/types/decorators/applyStyle.d.ts +25 -12
- package/dist/types/decorators/applyStyle.d.ts.map +1 -1
- package/dist/types/decorators/changedAttribute.d.ts +11 -0
- package/dist/types/decorators/changedAttribute.d.ts.map +1 -1
- package/dist/types/decorators/elementDefine.d.ts.map +1 -1
- package/dist/types/decorators/emitCustomEvent.d.ts +28 -4
- package/dist/types/decorators/emitCustomEvent.d.ts.map +1 -1
- package/dist/types/decorators/index.d.ts +5 -1
- package/dist/types/decorators/index.d.ts.map +1 -1
- package/dist/types/decorators/intersectionObserver.d.ts +49 -0
- package/dist/types/decorators/intersectionObserver.d.ts.map +1 -0
- package/dist/types/decorators/mutationObserver.d.ts +46 -0
- package/dist/types/decorators/mutationObserver.d.ts.map +1 -0
- package/dist/types/decorators/query.d.ts +63 -8
- package/dist/types/decorators/query.d.ts.map +1 -1
- package/dist/types/decorators/resizeObserver.d.ts +48 -0
- package/dist/types/decorators/resizeObserver.d.ts.map +1 -0
- package/dist/types/decorators/setInterval.d.ts +29 -0
- package/dist/types/decorators/setInterval.d.ts.map +1 -0
- package/dist/types/decorators/setTimeout.d.ts +29 -0
- package/dist/types/decorators/setTimeout.d.ts.map +1 -0
- package/dist/types/decorators/subscribeSwcAppMessageWhileConnected.d.ts +7 -1
- package/dist/types/decorators/subscribeSwcAppMessageWhileConnected.d.ts.map +1 -1
- package/dist/types/decorators/subscribeSwcAppRouteChangeWhileConnected.d.ts +6 -0
- package/dist/types/decorators/subscribeSwcAppRouteChangeWhileConnected.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/types/index.d.ts +104 -0
- package/dist/types/types/index.d.ts.map +1 -1
- package/dist/umd-bundle/dooboostore-simple-web-component.umd.js +2413 -889
- package/dist/umd-bundle/dooboostore-simple-web-component.umd.js.map +4 -4
- package/package.json +8 -6
- package/src/config/config.ts +1 -1
- package/src/decorators/addEventListener.ts +426 -23
- package/src/decorators/applyAttribute.ts +50 -36
- package/src/decorators/applyClass.ts +76 -26
- package/src/decorators/applyNode.ts +114 -36
- package/src/decorators/applyProperty.ts +152 -40
- package/src/decorators/applyStyle.ts +64 -17
- package/src/decorators/changedAttribute.ts +46 -0
- package/src/decorators/elementDefine.ts +301 -317
- package/src/decorators/emitCustomEvent.ts +73 -5
- package/src/decorators/index.ts +5 -1
- package/src/decorators/intersectionObserver.ts +259 -0
- package/src/decorators/mutationObserver.ts +304 -0
- package/src/decorators/query.ts +182 -117
- package/src/decorators/resizeObserver.ts +235 -0
- package/src/decorators/setInterval.ts +80 -0
- package/src/decorators/setTimeout.ts +80 -0
- package/src/decorators/subscribeSwcAppMessageWhileConnected.ts +17 -0
- package/src/decorators/subscribeSwcAppRouteChangeWhileConnected.ts +19 -0
- package/src/examples/RxJSOperatorsExample.ts +279 -0
- package/src/types/index.ts +141 -0
- package/dist/cjs/decorators/queryAll.js +0 -181
- package/dist/cjs/decorators/queryAll.js.map +0 -7
- package/dist/cjs/elements/tt/SwcAppMixin.js +0 -1
- package/dist/cjs/elements/tt/SwcAppMixin.js.map +0 -7
- package/dist/cjs/elements/tt/SwcAsync.js +0 -1
- package/dist/cjs/elements/tt/SwcAsync.js.map +0 -7
- package/dist/cjs/elements/tt/SwcAsyncTemplate.js +0 -1
- package/dist/cjs/elements/tt/SwcAsyncTemplate.js.map +0 -7
- package/dist/cjs/elements/tt/SwcChoose.js +0 -1
- package/dist/cjs/elements/tt/SwcChoose.js.map +0 -7
- package/dist/cjs/elements/tt/SwcChooseTemplate.js +0 -1
- package/dist/cjs/elements/tt/SwcChooseTemplate.js.map +0 -7
- package/dist/cjs/elements/tt/SwcIf.js +0 -1
- package/dist/cjs/elements/tt/SwcIf.js.map +0 -7
- package/dist/cjs/elements/tt/SwcIfTemplate.js +0 -1
- package/dist/cjs/elements/tt/SwcIfTemplate.js.map +0 -7
- package/dist/cjs/elements/tt/SwcLoop.js +0 -1
- package/dist/cjs/elements/tt/SwcLoop.js.map +0 -7
- package/dist/cjs/elements/tt/SwcLoopTemplate.js +0 -1
- package/dist/cjs/elements/tt/SwcLoopTemplate.js.map +0 -7
- package/dist/cjs/elements/tt/SwcSubTemplates.js +0 -1
- package/dist/cjs/elements/tt/SwcSubTemplates.js.map +0 -7
- package/dist/cjs/elements/tt/register.js +0 -1
- package/dist/cjs/elements/tt/register.js.map +0 -7
- package/dist/esm/decorators/queryAll.js +0 -162
- package/dist/esm/decorators/queryAll.js.map +0 -7
- package/dist/esm/elements/tt/SwcAppMixin.js +0 -1
- package/dist/esm/elements/tt/SwcAppMixin.js.map +0 -7
- package/dist/esm/elements/tt/SwcAsync.js +0 -1
- package/dist/esm/elements/tt/SwcAsync.js.map +0 -7
- package/dist/esm/elements/tt/SwcAsyncTemplate.js +0 -1
- package/dist/esm/elements/tt/SwcAsyncTemplate.js.map +0 -7
- package/dist/esm/elements/tt/SwcChoose.js +0 -1
- package/dist/esm/elements/tt/SwcChoose.js.map +0 -7
- package/dist/esm/elements/tt/SwcChooseTemplate.js +0 -1
- package/dist/esm/elements/tt/SwcChooseTemplate.js.map +0 -7
- package/dist/esm/elements/tt/SwcIf.js +0 -1
- package/dist/esm/elements/tt/SwcIf.js.map +0 -7
- package/dist/esm/elements/tt/SwcIfTemplate.js +0 -1
- package/dist/esm/elements/tt/SwcIfTemplate.js.map +0 -7
- package/dist/esm/elements/tt/SwcLoop.js +0 -1
- package/dist/esm/elements/tt/SwcLoop.js.map +0 -7
- package/dist/esm/elements/tt/SwcLoopTemplate.js +0 -1
- package/dist/esm/elements/tt/SwcLoopTemplate.js.map +0 -7
- package/dist/esm/elements/tt/SwcSubTemplates.js +0 -1
- package/dist/esm/elements/tt/SwcSubTemplates.js.map +0 -7
- package/dist/esm/elements/tt/register.js +0 -1
- package/dist/esm/elements/tt/register.js.map +0 -7
- package/dist/types/decorators/queryAll.d.ts +0 -22
- package/dist/types/decorators/queryAll.d.ts.map +0 -1
- package/dist/types/elements/tt/SwcAppMixin.d.ts +0 -1
- package/dist/types/elements/tt/SwcAppMixin.d.ts.map +0 -1
- package/dist/types/elements/tt/SwcAsync.d.ts +0 -1
- package/dist/types/elements/tt/SwcAsync.d.ts.map +0 -1
- package/dist/types/elements/tt/SwcAsyncTemplate.d.ts +0 -1
- package/dist/types/elements/tt/SwcAsyncTemplate.d.ts.map +0 -1
- package/dist/types/elements/tt/SwcChoose.d.ts +0 -1
- package/dist/types/elements/tt/SwcChoose.d.ts.map +0 -1
- package/dist/types/elements/tt/SwcChooseTemplate.d.ts +0 -1
- package/dist/types/elements/tt/SwcChooseTemplate.d.ts.map +0 -1
- package/dist/types/elements/tt/SwcIf.d.ts +0 -1
- package/dist/types/elements/tt/SwcIf.d.ts.map +0 -1
- package/dist/types/elements/tt/SwcIfTemplate.d.ts +0 -1
- package/dist/types/elements/tt/SwcIfTemplate.d.ts.map +0 -1
- package/dist/types/elements/tt/SwcLoop.d.ts +0 -1
- package/dist/types/elements/tt/SwcLoop.d.ts.map +0 -1
- package/dist/types/elements/tt/SwcLoopTemplate.d.ts +0 -1
- package/dist/types/elements/tt/SwcLoopTemplate.d.ts.map +0 -1
- package/dist/types/elements/tt/SwcSubTemplates.d.ts +0 -1
- package/dist/types/elements/tt/SwcSubTemplates.d.ts.map +0 -1
- package/dist/types/elements/tt/register.d.ts +0 -1
- package/dist/types/elements/tt/register.d.ts.map +0 -1
- package/src/decorators/queryAll.ts +0 -186
- package/src/elements/tt/SwcAppMixin.ts +0 -13
- package/src/elements/tt/SwcAsync.ts +0 -139
- package/src/elements/tt/SwcAsyncTemplate.ts +0 -126
- package/src/elements/tt/SwcChoose.ts +0 -182
- package/src/elements/tt/SwcChooseTemplate.ts +0 -229
- package/src/elements/tt/SwcIf.ts +0 -145
- package/src/elements/tt/SwcIfTemplate.ts +0 -158
- package/src/elements/tt/SwcLoop.ts +0 -222
- package/src/elements/tt/SwcLoopTemplate.ts +0 -255
- package/src/elements/tt/SwcSubTemplates.ts +0 -6
- package/src/elements/tt/register.ts +0 -720
|
@@ -1,20 +1,25 @@
|
|
|
1
|
-
import {ActionExpression, FunctionUtils, ReflectUtils
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import {ActionExpression, FunctionUtils, ReflectUtils} from '@dooboostore/core';
|
|
2
|
+
import {EventListenerLifeCycler} from './addEventListener';
|
|
3
|
+
import {MutationObserverLifeCycler} from './mutationObserver';
|
|
4
|
+
import {ResizeObserverLifeCycler} from './resizeObserver';
|
|
5
|
+
import {IntersectionObserverLifeCycler} from './intersectionObserver';
|
|
4
6
|
import {findAllLifecycleMetadata, findAllOnConnectedAfterMetadata, findAllOnConnectedBeforeMetadata, findAllOnConnectedMetadata, ON_AFTER_ADOPTED_METADATA_KEY, ON_AFTER_DISCONNECTED_METADATA_KEY, ON_BEFORE_ADOPTED_METADATA_KEY, ON_BEFORE_DISCONNECTED_METADATA_KEY, ON_CONNECTED_COMPLETED_METADATA_KEY, ON_INITIALIZE_METADATA_KEY} from './lifecycles';
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {findAllAttributeApplyMetadata, findAllAttributeMetadata
|
|
8
|
-
import {getQueryMetadata} from './query';
|
|
9
|
-
import {getQueryAllMetadata} from './queryAll';
|
|
7
|
+
import {EmitCustomEventLifeCycler} from './emitCustomEvent';
|
|
8
|
+
import {ChangedAttributeLifeCycler} from './changedAttribute';
|
|
9
|
+
import {findAllAttributeApplyMetadata, findAllAttributeMetadata} from './applyAttribute';
|
|
10
|
+
import {getQueryMetadata, getQueryAllMetadata} from './query';
|
|
10
11
|
import {SwcUtils} from '../utils/Utils';
|
|
11
12
|
import {DOM_EVENT_NAMES, HTML_TAG_ENTRIES} from '../config/config';
|
|
12
13
|
import {SituationTypeContainer, SituationTypeContainers} from '@dooboostore/simple-boot/decorators/inject/Inject';
|
|
13
|
-
import {HelperHostSet, HostSet, InjectSituationType} from '../types';
|
|
14
|
+
import {ElementDefineLifeCycler, HelperHostSet, HostSet, InjectSituationType, IntersectionObserverSet, MutationObserverSet, OnConnectedResult, ResizeObserverSet, ResizeObserverSetEntry, SwcRootType} from '../types';
|
|
14
15
|
import {ConvertUtils, ElementApply} from '@dooboostore/core-web';
|
|
15
16
|
import {isSSR} from "../elements/SwcAppMixin";
|
|
16
17
|
import {findAllStateMetadata} from "./state";
|
|
17
18
|
import {findAllPropertyMetadata} from "./applyProperty";
|
|
19
|
+
import {MessageSubscribeLifeCycler} from "./subscribeSwcAppMessageWhileConnected";
|
|
20
|
+
import {RouteSubscribeLifeCycler} from "./subscribeSwcAppRouteChangeWhileConnected";
|
|
21
|
+
import {SetIntervalLifeCycler} from "./setInterval";
|
|
22
|
+
import {SetTimeoutLifeCycler} from "./setTimeout";
|
|
18
23
|
|
|
19
24
|
// --- Core Interfaces & Types ---
|
|
20
25
|
|
|
@@ -42,7 +47,6 @@ export const ensureInit = (inst: any) => { // HTMLElement
|
|
|
42
47
|
if (!inst.__swc_initialized) {
|
|
43
48
|
inst._swcId = inst?.getAttribute?.('swc-use-ssr') ?? 's' + Math.random().toString(36).substring(2, 11).toLowerCase();
|
|
44
49
|
inst._emitHandlers = new Map();
|
|
45
|
-
inst._boundListeners = [];
|
|
46
50
|
inst.__swc_initialized = true;
|
|
47
51
|
// const attributeList = findAllQ(inst);
|
|
48
52
|
// attributeList.forEach(meta => {
|
|
@@ -318,8 +322,8 @@ const setupPrototype = (proto: any, win: Window) => {
|
|
|
318
322
|
export const elementDefine =
|
|
319
323
|
(name: string, config: Partial<ElementConfig> = {}): ClassDecorator =>
|
|
320
324
|
(constructor: any) => {
|
|
321
|
-
const {win, doc, builtInTagMap: BUILT_IN_TAG_MAP, domHelpers: SWC_DOM_HELPERS} = buildEnv(config.window);
|
|
322
|
-
const metadata: ElementMetadata = {...config, name, window: win};
|
|
325
|
+
const { win, doc, builtInTagMap: BUILT_IN_TAG_MAP, domHelpers: SWC_DOM_HELPERS } = buildEnv(config.window);
|
|
326
|
+
const metadata: ElementMetadata = { ...config, name, window: win };
|
|
323
327
|
|
|
324
328
|
if (!metadata.window) {
|
|
325
329
|
throw new Error('window is required');
|
|
@@ -337,10 +341,6 @@ export const elementDefine =
|
|
|
337
341
|
metadata.extends = extendsTagName;
|
|
338
342
|
}
|
|
339
343
|
|
|
340
|
-
const emitCustomEventList = getEmitCustomEventMetadataList(constructor) || [];
|
|
341
|
-
const emitHostCustomEventList = emitCustomEventList.filter(meta => meta.selector === '$this' || meta.selector === '');
|
|
342
|
-
const addEventListenerList = getAddEventListenerMetadata(constructor) || [];
|
|
343
|
-
const attrChangeMap = findAllAttributeChangedMetadata(constructor);
|
|
344
344
|
const attributeList = findAllAttributeMetadata(constructor);
|
|
345
345
|
const applyAttributeMap = findAllAttributeApplyMetadata(constructor);
|
|
346
346
|
|
|
@@ -353,24 +353,256 @@ export const elementDefine =
|
|
|
353
353
|
const hostAttributes = attributeList.filter(it => it.selector === '$this').map(it => it.propertyKey || String(it.propertyKey));
|
|
354
354
|
// Get original static observedAttributes before they're overwritten by Object.defineProperty
|
|
355
355
|
const originalStaticObservedAttributes = (constructor.observedAttributes ?? []) as string[];
|
|
356
|
-
const mergedObservedAttributes = [...new Set([...(metadata.observedAttributes ?? []), ...originalStaticObservedAttributes, ...attrChangeMap.keys(), ...attributeApplyNames, ...hostAttributes, ...emitHostCustomEventList.map(it => (it.options as any).attributeName).filter(Boolean), ...swcLifecycleAttributes, ...swcOnEvents])];
|
|
357
|
-
// const connectedInnerHtmlList = getOnConnectedInnerHtmlMetadata(constructor) || [];
|
|
358
356
|
|
|
359
357
|
const proto = constructor.prototype;
|
|
360
358
|
setupPrototype(proto, win);
|
|
361
359
|
|
|
362
360
|
// 값을 기대하지않는다.
|
|
363
361
|
let helperHostSet: HelperHostSet | null = null;
|
|
362
|
+
// ── cyclers: 데코레이터별 라이프사이클 위임 클래스 (elementDefine 시 1회 생성, 계속 재사용) ──
|
|
363
|
+
const eventCycler = new EventListenerLifeCycler();
|
|
364
|
+
const cyclers: ElementDefineLifeCycler[] = [
|
|
365
|
+
eventCycler,
|
|
366
|
+
new ChangedAttributeLifeCycler(),
|
|
367
|
+
new EmitCustomEventLifeCycler(),
|
|
368
|
+
new ResizeObserverLifeCycler(),
|
|
369
|
+
new IntersectionObserverLifeCycler(),
|
|
370
|
+
new MutationObserverLifeCycler(),
|
|
371
|
+
new MessageSubscribeLifeCycler(),
|
|
372
|
+
new RouteSubscribeLifeCycler(),
|
|
373
|
+
new SetIntervalLifeCycler(),
|
|
374
|
+
new SetTimeoutLifeCycler(),
|
|
375
|
+
];
|
|
376
|
+
|
|
377
|
+
// observedAttributes 기여 cycler (define-time, constructor 기반)
|
|
378
|
+
const cyclerObservedAttributes = cyclers.flatMap(c => c.getObservedAttributeNames?.(constructor) ?? []);
|
|
379
|
+
const mergedObservedAttributes = [...new Set([...(metadata.observedAttributes ?? []), ...originalStaticObservedAttributes, ...cyclerObservedAttributes, ...attributeApplyNames, ...hostAttributes, ...swcLifecycleAttributes, ...swcOnEvents])];
|
|
380
|
+
|
|
381
|
+
// 렌더 후 모든 시클러 onConnected 호출 → Set 수집 후 observer 생성
|
|
382
|
+
const buildObservers = async (helperHostSet: HelperHostSet): Promise<void> => {
|
|
383
|
+
const inst = helperHostSet.$this;
|
|
384
|
+
const observers: Array<MutationObserver | ResizeObserver | IntersectionObserver> = [];
|
|
385
|
+
let resizeObserverSet: ResizeObserverSet = [];
|
|
386
|
+
let mutationObserverSet: MutationObserverSet = [];
|
|
387
|
+
let intersectionObserverSet: IntersectionObserverSet = [];
|
|
388
|
+
|
|
389
|
+
// delegate 추적 root 해석: shadow/light/auto/all → 실제 root 목록
|
|
390
|
+
const resolveDelegateRoots = (delegateRoot: SwcRootType | undefined): (HTMLElement | ShadowRoot)[] => {
|
|
391
|
+
const r = delegateRoot || 'auto';
|
|
392
|
+
const roots: (HTMLElement | ShadowRoot)[] = [];
|
|
393
|
+
if (r === 'auto') roots.push(inst.shadowRoot || inst);
|
|
394
|
+
else if (r === 'light') roots.push(inst);
|
|
395
|
+
else if (r === 'shadow' && inst.shadowRoot) roots.push(inst.shadowRoot);
|
|
396
|
+
else if (r === 'all') { roots.push(inst); if (inst.shadowRoot) roots.push(inst.shadowRoot); }
|
|
397
|
+
return roots;
|
|
398
|
+
};
|
|
399
|
+
|
|
400
|
+
// 1. 모든 시클러 onConnected → observer Set 수집 (여러 시클러가 반환한 Set 을 전부 누적)
|
|
401
|
+
for (const c of cyclers) {
|
|
402
|
+
const result = (await c.onConnected?.(helperHostSet, resizeObserverSet)) as OnConnectedResult | void;
|
|
403
|
+
if (!result) continue;
|
|
404
|
+
if (result.resizeObserverSet?.length) resizeObserverSet = [...resizeObserverSet, ...result.resizeObserverSet];
|
|
405
|
+
if (result.mutationObserverSet?.length) mutationObserverSet = [...mutationObserverSet, ...result.mutationObserverSet];
|
|
406
|
+
if (result.intersectionObserverSet?.length) intersectionObserverSet = [...intersectionObserverSet, ...result.intersectionObserverSet];
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
// 2. 타입별로 observer 생성
|
|
410
|
+
// ResizeObserver 먼저: mutation callback 이 observe/unobserve 를 주입받아야 함
|
|
411
|
+
// observeTargets 중 delegate 항목은 셀렉터 문자열이라 초기 observe 하지 않는다 (동적 추적 전용).
|
|
412
|
+
// 동적 observe/unobserve 는 중복 호출을 막기 위해 observe 대상 WeakSet 으로 추적한다.
|
|
413
|
+
const resizeDelegates = (resizeObserverSet ?? []).filter(t => t.delegate && typeof t.target === 'string') as Array<ResizeObserverSetEntry & { target: string }>;
|
|
414
|
+
let resizeObserve: ((el: Element, opts?: ResizeObserverOptions) => void) | undefined;
|
|
415
|
+
let resizeUnobserve: ((el: Element) => void) | undefined;
|
|
416
|
+
const resizeObserved = new WeakSet<Element>();
|
|
417
|
+
if (resizeObserverSet?.length) {
|
|
418
|
+
const roCallbacks = [...new Set(resizeObserverSet.map(e => e.callback))];
|
|
419
|
+
const ro = new (win as any).ResizeObserver((entries, obs) => {
|
|
420
|
+
for (const cb of roCallbacks) cb(entries, obs);
|
|
421
|
+
});
|
|
422
|
+
for (const e of resizeObserverSet) {
|
|
423
|
+
if (e.delegate) continue;
|
|
424
|
+
if (typeof e.target === 'string') {
|
|
425
|
+
// 문자열(non-delegate)이면 root 에서 검색된 요소들을 observe 대상으로 추가한다.
|
|
426
|
+
const scope = resolveDelegateRoots(e.delegateRoot);
|
|
427
|
+
for (const sr of scope) {
|
|
428
|
+
sr.querySelectorAll(e.target).forEach(el => {
|
|
429
|
+
if (!resizeObserved.has(el)) { ro.observe(el, e.options); resizeObserved.add(el); }
|
|
430
|
+
});
|
|
431
|
+
}
|
|
432
|
+
continue;
|
|
433
|
+
}
|
|
434
|
+
ro.observe(e.target as Element, e.options);
|
|
435
|
+
if (e.target instanceof Element) resizeObserved.add(e.target);
|
|
436
|
+
}
|
|
437
|
+
resizeObserve = (el, opts) => {
|
|
438
|
+
if (resizeObserved.has(el)) return;
|
|
439
|
+
ro.observe(el, opts);
|
|
440
|
+
resizeObserved.add(el);
|
|
441
|
+
};
|
|
442
|
+
resizeUnobserve = (el) => {
|
|
443
|
+
if (!resizeObserved.has(el)) return;
|
|
444
|
+
ro.unobserve(el);
|
|
445
|
+
resizeObserved.delete(el);
|
|
446
|
+
};
|
|
447
|
+
observers.push(ro);
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
// IntersectionObserver: 옵션 그룹별로 1개씩 생성.
|
|
451
|
+
// delegate 항목은 동적 추적용 셀렉터이므로 observe/unobserve 함수를 MutationObserver 콜백에 넘긴다.
|
|
452
|
+
// 동적 observe/unobserve 중복 방지를 위해 그룹별 WeakSet 으로 추적한다.
|
|
453
|
+
const intersectionDelegates: Array<{ target: string; delegateRoot?: SwcRootType; observe: (el: Element) => void; unobserve: (el: Element) => void }> = [];
|
|
454
|
+
for (const group of intersectionObserverSet) {
|
|
455
|
+
const ioCallbacks = [...new Set(group.observeTargets.map(e => e.callback))];
|
|
456
|
+
const io = new (win as any).IntersectionObserver((entries, obs) => {
|
|
457
|
+
for (const cb of ioCallbacks) cb(entries, obs);
|
|
458
|
+
}, group.options);
|
|
459
|
+
const ioObserved = new WeakSet<Element>();
|
|
460
|
+
for (const e of group.observeTargets) {
|
|
461
|
+
if (e.delegate) {
|
|
462
|
+
const target = e.target as string;
|
|
463
|
+
const observe = (el: Element) => {
|
|
464
|
+
if (ioObserved.has(el)) return;
|
|
465
|
+
io.observe(el);
|
|
466
|
+
ioObserved.add(el);
|
|
467
|
+
};
|
|
468
|
+
const unobserve = (el: Element) => {
|
|
469
|
+
if (!ioObserved.has(el)) return;
|
|
470
|
+
io.unobserve(el);
|
|
471
|
+
ioObserved.delete(el);
|
|
472
|
+
};
|
|
473
|
+
intersectionDelegates.push({ target, delegateRoot: e.delegateRoot, observe, unobserve });
|
|
474
|
+
continue;
|
|
475
|
+
}
|
|
476
|
+
if (typeof e.target === 'string') {
|
|
477
|
+
// 문자열(non-delegate)이면 root 에서 검색된 요소들을 observe 대상으로 추가한다.
|
|
478
|
+
const scope = resolveDelegateRoots(e.delegateRoot);
|
|
479
|
+
for (const sr of scope) {
|
|
480
|
+
sr.querySelectorAll(e.target).forEach(el => {
|
|
481
|
+
if (!ioObserved.has(el)) { io.observe(el); ioObserved.add(el); }
|
|
482
|
+
});
|
|
483
|
+
}
|
|
484
|
+
continue;
|
|
485
|
+
}
|
|
486
|
+
io.observe(e.target as Element);
|
|
487
|
+
if (e.target instanceof Element) ioObserved.add(e.target);
|
|
488
|
+
}
|
|
489
|
+
observers.push(io);
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
// resize/intersection delegate 동적 추적 — MutationObserver 콜백에서 추가/제거된 요소를 observe/unobserve 한다.
|
|
493
|
+
const handleResizeDelegate = (n: Node, observe: boolean) => {
|
|
494
|
+
if (!resizeObserve || !resizeUnobserve || n.nodeType !== 1) return;
|
|
495
|
+
const el = n as HTMLElement;
|
|
496
|
+
for (const d of resizeDelegates) {
|
|
497
|
+
const isThis = d.target === '$this' || d.target === '';
|
|
498
|
+
const matchesSel = (node: any) => {
|
|
499
|
+
if (!node || node.nodeType !== 1) return false;
|
|
500
|
+
if (isThis) return true;
|
|
501
|
+
return (node as HTMLElement).matches?.(d.target) || !!(node as HTMLElement).closest?.(d.target);
|
|
502
|
+
};
|
|
503
|
+
if (matchesSel(el)) {
|
|
504
|
+
observe ? resizeObserve(el, d.options)
|
|
505
|
+
: resizeUnobserve(el);
|
|
506
|
+
} else if (!isThis) {
|
|
507
|
+
el.querySelectorAll(d.target).forEach(sub => {
|
|
508
|
+
observe ? resizeObserve(sub as HTMLElement, d.options)
|
|
509
|
+
: resizeUnobserve(sub as HTMLElement);
|
|
510
|
+
});
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
};
|
|
514
|
+
const handleIntersectionDelegate = (n: Node, observe: boolean) => {
|
|
515
|
+
if (n.nodeType !== 1) return;
|
|
516
|
+
const el = n as HTMLElement;
|
|
517
|
+
for (const d of intersectionDelegates) {
|
|
518
|
+
const isThis = d.target === '$this' || d.target === '';
|
|
519
|
+
const matchesSel = (node: any) => {
|
|
520
|
+
if (!node || node.nodeType !== 1) return false;
|
|
521
|
+
if (isThis) return true;
|
|
522
|
+
return (node as HTMLElement).matches?.(d.target) || !!(node as HTMLElement).closest?.(d.target);
|
|
523
|
+
};
|
|
524
|
+
if (matchesSel(el)) {
|
|
525
|
+
observe ? d.observe(el) : d.unobserve(el);
|
|
526
|
+
} else if (!isThis) {
|
|
527
|
+
el.querySelectorAll(d.target).forEach(sub => {
|
|
528
|
+
observe ? d.observe(sub as HTMLElement) : d.unobserve(sub as HTMLElement);
|
|
529
|
+
});
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
};
|
|
533
|
+
|
|
534
|
+
if (mutationObserverSet?.length || resizeDelegates.length > 0 || intersectionDelegates.length > 0) {
|
|
535
|
+
// 하나의 MutationObserver 로 resize/intersection delegate 동적 추적 + mutation 콜백을 함께 처리
|
|
536
|
+
const callbacks = [...new Set((mutationObserverSet ?? []).map(e => e.callback))];
|
|
537
|
+
const mo = new (win as any).MutationObserver((mutations, obs) => {
|
|
538
|
+
for (const mut of mutations) {
|
|
539
|
+
Array.from(mut.addedNodes || []).forEach(n => { handleResizeDelegate(n as Node, true); handleIntersectionDelegate(n as Node, true); });
|
|
540
|
+
Array.from(mut.removedNodes || []).forEach(n => { handleResizeDelegate(n as Node, false); handleIntersectionDelegate(n as Node, false); });
|
|
541
|
+
}
|
|
542
|
+
for (const cb of callbacks) cb(mutations, obs);
|
|
543
|
+
});
|
|
544
|
+
|
|
545
|
+
// observe 대상 전체(엔트리 + delegate 추적 root)를 하나로 모아 중복 observe 를 제거한다.
|
|
546
|
+
// 같은 target 이 여러 소스에서 지정되면 MutationObserverInit 을 합집합(최대 감지범위)으로 병합한다.
|
|
547
|
+
const moObserveTargets = new Map<Element | ShadowRoot, MutationObserverInit>();
|
|
548
|
+
const mergeMutationInit = (existing: MutationObserverInit | undefined, next: MutationObserverInit): MutationObserverInit => {
|
|
549
|
+
if (!existing) return next;
|
|
550
|
+
const mergedFilter = existing.attributeFilter || next.attributeFilter
|
|
551
|
+
? [...new Set([...(existing.attributeFilter ?? []), ...(next.attributeFilter ?? [])])]
|
|
552
|
+
: undefined;
|
|
553
|
+
return {
|
|
554
|
+
childList: existing.childList || next.childList,
|
|
555
|
+
attributes: existing.attributes || next.attributes,
|
|
556
|
+
characterData: existing.characterData || next.characterData,
|
|
557
|
+
subtree: existing.subtree || next.subtree,
|
|
558
|
+
attributeOldValue: existing.attributeOldValue || next.attributeOldValue,
|
|
559
|
+
characterDataOldValue: existing.characterDataOldValue || next.characterDataOldValue,
|
|
560
|
+
attributeFilter: mergedFilter,
|
|
561
|
+
};
|
|
562
|
+
};
|
|
563
|
+
const addObserveTarget = (target: Element | ShadowRoot, options: MutationObserverInit) => {
|
|
564
|
+
moObserveTargets.set(target, mergeMutationInit(moObserveTargets.get(target), options));
|
|
565
|
+
};
|
|
566
|
+
|
|
567
|
+
// 1) mutationObserverSet 엔트리
|
|
568
|
+
for (const e of mutationObserverSet ?? []) {
|
|
569
|
+
if (e.delegate) continue;
|
|
570
|
+
const init = e.options ?? { childList: true };
|
|
571
|
+
if (typeof e.target === 'string') {
|
|
572
|
+
// 문자열(non-delegate)이면 root 에서 검색된 요소들을 observe 대상으로 추가한다.
|
|
573
|
+
const scope = resolveDelegateRoots(e.delegateRoot);
|
|
574
|
+
for (const sr of scope) {
|
|
575
|
+
sr.querySelectorAll(e.target).forEach(el => addObserveTarget(el, init));
|
|
576
|
+
}
|
|
577
|
+
continue;
|
|
578
|
+
}
|
|
579
|
+
addObserveTarget(e.target, init);
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
// 2) delegate 추적 root: shadow/light/all/auto 로 해석해 전부 observe
|
|
583
|
+
for (const d of resizeDelegates) {
|
|
584
|
+
for (const r of resolveDelegateRoots(d.delegateRoot)) addObserveTarget(r, { childList: true, subtree: true });
|
|
585
|
+
}
|
|
586
|
+
for (const d of intersectionDelegates) {
|
|
587
|
+
for (const r of resolveDelegateRoots(d.delegateRoot)) addObserveTarget(r, { childList: true, subtree: true });
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
for (const [target, options] of moObserveTargets) {
|
|
591
|
+
mo.observe(target, options);
|
|
592
|
+
}
|
|
593
|
+
observers.push(mo);
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
inst.__swc_observers = observers;
|
|
597
|
+
};
|
|
598
|
+
|
|
364
599
|
const originalConnected = proto.connectedCallback;
|
|
365
600
|
proto.connectedCallback = async function () {
|
|
366
601
|
ensureInit(this);
|
|
367
|
-
//
|
|
602
|
+
// 재연결 시 누적 방지 — cycler 내부 리소스 초기화
|
|
368
603
|
helperHostSet = SwcUtils.getHelperAndHostSet(win, this as any);
|
|
369
604
|
const appHost = helperHostSet.$appHost;
|
|
370
605
|
const useSsr = isSSR(this);
|
|
371
|
-
// console.log('isSsr', useSsr, this);
|
|
372
|
-
// console.log('----helperHostSet--->', this, helperHostSet, useSsr)
|
|
373
|
-
// let connectedApp: SwcAppInterface |undefined;
|
|
374
606
|
try {
|
|
375
607
|
if (appHost && typeof (appHost as any)._connected === 'function') {
|
|
376
608
|
await (appHost as any)._connected(this);
|
|
@@ -379,56 +611,42 @@ export const elementDefine =
|
|
|
379
611
|
(appHost as any)._connected_safari_and_standby.push(this);
|
|
380
612
|
}
|
|
381
613
|
|
|
382
|
-
// const hostSet = SwcUtils.getHostSet(this as any);
|
|
383
614
|
const conf = getElementConfig(this);
|
|
384
615
|
const currentWin = (this as any)._resolveWindow(conf);
|
|
385
616
|
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
for (const m of bMethods) await (this as any)._invokeLifecycleMethod(m.propertyKey, helperHostSet);
|
|
617
|
+
// before-connected 라이프사이클 메서드 (@onConnectedBefore)
|
|
618
|
+
for (const m of findAllOnConnectedBeforeMetadata(this)) await (this as any)._invokeLifecycleMethod(m.propertyKey, helperHostSet);
|
|
389
619
|
(this as any)._executeSwcScript('swc-on-before-connected', helperHostSet);
|
|
390
620
|
|
|
391
|
-
//
|
|
392
|
-
// // ssr 처리라서 이미 내려준거그대로 상요하면된다 따라서 호출안한다
|
|
393
|
-
// const targetConnectedList = findAllOnConnectedMetadata(constructor).filter(it => useSsr ? !it.options.ssrFirst : true);
|
|
621
|
+
// ── 렌더 (@onConnected / @onConnectedBody*) — elementDefine 책임 ──
|
|
394
622
|
const targetConnectedList = useSsr ? [] : findAllOnConnectedMetadata(constructor);
|
|
395
623
|
const shadowMode = conf?.useShadow || targetConnectedList.find(it => it.options.useShadow)?.options.useShadow;
|
|
396
|
-
// console.log('--------->', this.tagName, shadowMode && !this.shadowRoot)
|
|
397
624
|
if (shadowMode && !this.shadowRoot) {
|
|
398
625
|
const mode = shadowMode === true ? 'open' : shadowMode;
|
|
399
|
-
|
|
400
|
-
// if (this.tagName!=='INDEX-ROUTER') {
|
|
401
|
-
this.attachShadow({mode: mode as ShadowRootMode});
|
|
402
|
-
// }
|
|
626
|
+
this.attachShadow({ mode: mode as ShadowRootMode });
|
|
403
627
|
}
|
|
404
628
|
|
|
405
|
-
const stateContext: any = {...helperHostSet};
|
|
629
|
+
const stateContext: any = { ...helperHostSet };
|
|
406
630
|
findAllStateMetadata(this).forEach(it => {
|
|
407
|
-
stateContext[it.name] = this[it.propertyKey]
|
|
408
|
-
})
|
|
631
|
+
stateContext[it.name] = this[it.propertyKey];
|
|
632
|
+
});
|
|
409
633
|
|
|
410
634
|
const shadowChildren: Node[] = [];
|
|
411
635
|
const lightChildren: Node[] = [];
|
|
412
636
|
|
|
413
|
-
console.log('targetConnectList', this.tagName, targetConnectedList.length)
|
|
414
637
|
if (targetConnectedList.length > 0) {
|
|
415
|
-
// let sContent = '',
|
|
416
|
-
// lContent = '';
|
|
417
638
|
for (const meta of targetConnectedList) {
|
|
418
|
-
// const res = (this as any)[meta.propertyKey]();
|
|
419
639
|
let res = await (this as any)._invokeLifecycleMethod(meta.propertyKey, helperHostSet);
|
|
420
|
-
// res = SwcUtils.projectProcessHtml(this, res);
|
|
421
640
|
if (typeof res === 'string') {
|
|
422
641
|
const htmlTemplateElement = doc.createElement('template');
|
|
423
|
-
htmlTemplateElement.innerHTML = res
|
|
642
|
+
htmlTemplateElement.innerHTML = res;
|
|
424
643
|
res = htmlTemplateElement.content;
|
|
425
644
|
}
|
|
426
|
-
|
|
427
645
|
if (res) {
|
|
428
646
|
const nodes = Array.isArray(res) ? res : [res];
|
|
429
647
|
if (meta.options.useShadow || conf?.useShadow) {
|
|
430
648
|
shadowChildren.push(...nodes);
|
|
431
|
-
}else {
|
|
649
|
+
} else {
|
|
432
650
|
lightChildren.push(...nodes);
|
|
433
651
|
}
|
|
434
652
|
}
|
|
@@ -436,23 +654,22 @@ export const elementDefine =
|
|
|
436
654
|
try {
|
|
437
655
|
if (this.shadowRoot) {
|
|
438
656
|
const applyShadowChildren = SwcUtils.projectProcessHtml(this._swcId, shadowChildren, doc);
|
|
439
|
-
this.shadowRoot.replaceChildren(...applyShadowChildren)
|
|
657
|
+
this.shadowRoot.replaceChildren(...applyShadowChildren);
|
|
440
658
|
}
|
|
441
659
|
if (lightChildren.length) {
|
|
442
660
|
const applyLightChildren = SwcUtils.projectProcessHtml(this._swcId, lightChildren, doc);
|
|
443
|
-
this.replaceChildren(...applyLightChildren)
|
|
661
|
+
this.replaceChildren(...applyLightChildren);
|
|
444
662
|
}
|
|
445
|
-
|
|
446
663
|
} catch (e) {
|
|
447
664
|
console.error('[ElementDefine] innerHTML setting error:', e);
|
|
448
665
|
}
|
|
449
|
-
new ElementApply(this, {id: this._swcId}).apply({context: stateContext, bind: this});
|
|
666
|
+
new ElementApply(this, { id: this._swcId }).apply({ context: stateContext, bind: this });
|
|
450
667
|
} else {
|
|
451
|
-
new ElementApply(this, {id: this._swcId}).apply({exclude: {html: true, text: true, attribute: true}, context: stateContext, bind: this});
|
|
668
|
+
new ElementApply(this, { id: this._swcId }).apply({ exclude: { html: true, text: true, attribute: true }, context: stateContext, bind: this });
|
|
452
669
|
}
|
|
453
670
|
|
|
454
671
|
// global delegate event
|
|
455
|
-
const root = this.getRootNode()
|
|
672
|
+
const root = this.getRootNode();
|
|
456
673
|
if (!globalDelegatedRoots.has(root)) {
|
|
457
674
|
DOM_EVENT_NAMES.forEach(type => {
|
|
458
675
|
root.addEventListener(type, handleGlobalSwcEvent);
|
|
@@ -460,271 +677,51 @@ export const elementDefine =
|
|
|
460
677
|
globalDelegatedRoots.add(root);
|
|
461
678
|
}
|
|
462
679
|
|
|
680
|
+
// ── cycler 실행 (렌더 후): 모든 시클러 onConnected → observer Set 수집 → observer 생성 ──
|
|
681
|
+
// helperHostSet 은 클로저 변수라 async 흐름에서 다른 인스턴스로 덮어써질 수 있다.
|
|
682
|
+
// 반드시 현재 인스턴스(this)로 재계산한 값을 사용한다.
|
|
683
|
+
await buildObservers(SwcUtils.getHelperAndHostSet(win, this as any));
|
|
463
684
|
|
|
464
|
-
|
|
465
|
-
const delegateListeners: typeof addEventListenerList = [];
|
|
466
|
-
const nonDelegateListeners: typeof addEventListenerList = [];
|
|
467
|
-
|
|
468
|
-
addEventListenerList.forEach(meta => {
|
|
469
|
-
// Function-based selectors cannot be used with delegate listeners
|
|
470
|
-
const isStringSelector = typeof meta.selector === 'string';
|
|
471
|
-
if (meta.options.delegate && isStringSelector && meta.selector !== '$window' && meta.selector !== '$document' && meta.selector !== '$host' && meta.selector !== '$appHost' && meta.selector !== '$firstHost' && meta.selector !== '$lastHost' && meta.selector !== '$firstAppHost' && meta.selector !== '$lastAppHost' && meta.selector !== '$hosts' && meta.selector !== '$appHosts' && meta.selector !== '$this' && meta.selector !== '') {
|
|
472
|
-
delegateListeners.push(meta);
|
|
473
|
-
} else {
|
|
474
|
-
nonDelegateListeners.push(meta);
|
|
475
|
-
}
|
|
476
|
-
});
|
|
477
|
-
|
|
478
|
-
const delegatesByTypeAndRoot = new Map<string, any[]>();
|
|
479
|
-
delegateListeners.forEach(meta => {
|
|
480
|
-
const r = meta.options.root || 'auto';
|
|
481
|
-
const rootKey = `${meta.type}:${r}`;
|
|
482
|
-
if (!delegatesByTypeAndRoot.has(rootKey)) {
|
|
483
|
-
delegatesByTypeAndRoot.set(rootKey, []);
|
|
484
|
-
}
|
|
485
|
-
delegatesByTypeAndRoot.get(rootKey)!.push(meta);
|
|
486
|
-
});
|
|
487
|
-
|
|
488
|
-
delegatesByTypeAndRoot.forEach((metaList, typeRootKey) => {
|
|
489
|
-
const [type, rStr] = typeRootKey.split(':');
|
|
490
|
-
const r = rStr === 'auto' ? 'auto' : rStr;
|
|
491
|
-
const opts = {capture: metaList[0].options.capture, once: metaList[0].options.once, passive: metaList[0].options.passive};
|
|
492
|
-
|
|
493
|
-
const bindRoots: (HTMLElement | ShadowRoot)[] = [];
|
|
494
|
-
if (r === 'auto') bindRoots.push(this.shadowRoot || (this as any));
|
|
495
|
-
else if (r === 'light') bindRoots.push(this as any);
|
|
496
|
-
else if (r === 'shadow' && this.shadowRoot) bindRoots.push(this.shadowRoot);
|
|
497
|
-
else if (r === 'all') {
|
|
498
|
-
bindRoots.push(this as any);
|
|
499
|
-
if (this.shadowRoot) bindRoots.push(this.shadowRoot);
|
|
500
|
-
}
|
|
501
|
-
|
|
502
|
-
bindRoots.forEach(br => {
|
|
503
|
-
const sortedMetaList = [...metaList].sort((a, b) => {
|
|
504
|
-
const aStop = a.options.stopPropagation ? 1 : 0;
|
|
505
|
-
const bStop = b.options.stopPropagation ? 1 : 0;
|
|
506
|
-
return bStop - aStop;
|
|
507
|
-
});
|
|
508
|
-
|
|
509
|
-
const unifiedHandler = async (event: Event) => {
|
|
510
|
-
for (const meta of sortedMetaList) {
|
|
511
|
-
const {selector, options} = meta;
|
|
512
|
-
const matchedEl = (event.target as HTMLElement)?.closest(selector);
|
|
513
|
-
if (matchedEl && (br as any).contains(matchedEl)) {
|
|
514
|
-
// Apply filter if specified
|
|
515
|
-
if (options.filter) {
|
|
516
|
-
const helper = SwcUtils.getHelperAndHostSet(currentWin, matchedEl);
|
|
517
|
-
if (!options.filter(event, helper)) {
|
|
518
|
-
continue; // Skip this listener if filter returns false
|
|
519
|
-
}
|
|
520
|
-
}
|
|
521
|
-
if (options.stopPropagation) event.stopPropagation();
|
|
522
|
-
if (options.stopImmediatePropagation) event.stopImmediatePropagation();
|
|
523
|
-
if (options.preventDefault) event.preventDefault();
|
|
524
|
-
const currentHostSet = SwcUtils.getHostSet(this as any);
|
|
525
|
-
const args = {event, ...currentHostSet, $el: matchedEl, $root: br};
|
|
526
|
-
await (this as any)[meta.propertyKey](event, {...currentHostSet, $matchedElement: matchedEl}, args);
|
|
527
|
-
if ((event as any).cancelBubble) break;
|
|
528
|
-
}
|
|
529
|
-
}
|
|
530
|
-
};
|
|
531
|
-
br.addEventListener(type, unifiedHandler, opts);
|
|
532
|
-
(this as any)._boundListeners.push({target: br, type, handler: unifiedHandler, options: opts});
|
|
533
|
-
});
|
|
534
|
-
});
|
|
685
|
+
if (originalConnected) await originalConnected.apply(this);
|
|
535
686
|
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
const opts = {capture: options.capture, once: options.once, passive: options.passive};
|
|
539
|
-
const bindTargets: EventTarget[] = [];
|
|
540
|
-
const r = options.root || 'auto';
|
|
541
|
-
|
|
542
|
-
// Resolve selector if it's a function
|
|
543
|
-
let resolvedSelector: string | null = null;
|
|
544
|
-
if (typeof selector === 'function') {
|
|
545
|
-
const hostSet = SwcUtils.getHelperAndHostSet(currentWin, this);
|
|
546
|
-
const result = selector(this, hostSet);
|
|
547
|
-
if (typeof result === 'string') {
|
|
548
|
-
resolvedSelector = result;
|
|
549
|
-
} else if (result instanceof currentWin.Element) {
|
|
550
|
-
bindTargets.push(result as EventTarget);
|
|
551
|
-
} else if (result instanceof currentWin.NodeList) {
|
|
552
|
-
bindTargets.push(...Array.from(result as EventTarget[]));
|
|
553
|
-
} else if (Array.isArray(result)) {
|
|
554
|
-
bindTargets.push(...(result as EventTarget[]));
|
|
555
|
-
}
|
|
556
|
-
} else {
|
|
557
|
-
resolvedSelector = selector;
|
|
558
|
-
}
|
|
559
|
-
|
|
560
|
-
const applyRootOption = (target: any) => {
|
|
561
|
-
if (!target) return;
|
|
562
|
-
if (r === 'auto') {
|
|
563
|
-
bindTargets.push(target.shadowRoot || target);
|
|
564
|
-
} else {
|
|
565
|
-
if (r === 'light' || r === 'all') bindTargets.push(target);
|
|
566
|
-
if ((r === 'shadow' || r === 'all') && target.shadowRoot) bindTargets.push(target.shadowRoot);
|
|
567
|
-
}
|
|
568
|
-
};
|
|
569
|
-
|
|
570
|
-
if (resolvedSelector) {
|
|
571
|
-
if (resolvedSelector === '$window') bindTargets.push(currentWin);
|
|
572
|
-
else if (resolvedSelector === '$document') bindTargets.push(currentWin.document);
|
|
573
|
-
else if (resolvedSelector === '$host') applyRootOption(helperHostSet.$host);
|
|
574
|
-
else if (resolvedSelector === '$parentHost') applyRootOption(helperHostSet.$parentHost);
|
|
575
|
-
else if (resolvedSelector === '$appHost') applyRootOption(helperHostSet.$appHost);
|
|
576
|
-
else if (resolvedSelector === '$firstHost') applyRootOption(helperHostSet.$firstHost);
|
|
577
|
-
else if (resolvedSelector === '$lastHost') applyRootOption(helperHostSet.$lastHost);
|
|
578
|
-
else if (resolvedSelector === '$firstAppHost') applyRootOption(helperHostSet.$firstAppHost);
|
|
579
|
-
else if (resolvedSelector === '$lastAppHost') applyRootOption(helperHostSet.$lastAppHost);
|
|
580
|
-
else if (resolvedSelector === '$hosts') helperHostSet.$hosts.forEach(applyRootOption);
|
|
581
|
-
else if (resolvedSelector === '$appHosts') helperHostSet.$appHosts.forEach(applyRootOption);
|
|
582
|
-
else if (resolvedSelector === '$this' || !resolvedSelector) applyRootOption(this);
|
|
583
|
-
else {
|
|
584
|
-
const searchRoots: (HTMLElement | ShadowRoot)[] = [];
|
|
585
|
-
if (r === 'auto') searchRoots.push(this.shadowRoot || (this as any));
|
|
586
|
-
else if (r === 'light') searchRoots.push(this as any);
|
|
587
|
-
else if (r === 'shadow' && this.shadowRoot) searchRoots.push(this.shadowRoot);
|
|
588
|
-
else if (r === 'all') {
|
|
589
|
-
searchRoots.push(this as any);
|
|
590
|
-
if (this.shadowRoot) searchRoots.push(this.shadowRoot);
|
|
591
|
-
}
|
|
592
|
-
|
|
593
|
-
searchRoots.forEach(sr => {
|
|
594
|
-
sr.querySelectorAll(resolvedSelector).forEach(el => bindTargets.push(el));
|
|
595
|
-
});
|
|
596
|
-
}
|
|
597
|
-
}
|
|
598
|
-
|
|
599
|
-
bindTargets.forEach(t => {
|
|
600
|
-
const handler = async (event: Event) => {
|
|
601
|
-
// Apply filter if specified
|
|
602
|
-
if (options.filter) {
|
|
603
|
-
const helper = SwcUtils.getHelperAndHostSet(currentWin, t as HTMLElement);
|
|
604
|
-
if (!options.filter(event, {currentThis: this, helper})) {
|
|
605
|
-
return; // Skip if filter returns false
|
|
606
|
-
}
|
|
607
|
-
}
|
|
608
|
-
if (options.stopPropagation) event.stopPropagation();
|
|
609
|
-
if (options.stopImmediatePropagation) event.stopImmediatePropagation();
|
|
610
|
-
if (options.preventDefault) event.preventDefault();
|
|
611
|
-
const currentHostSet = SwcUtils.getHostSet(this as any);
|
|
612
|
-
const args = {event, ...currentHostSet, $el: t, $root: t};
|
|
613
|
-
await (this as any)[meta.propertyKey](event, {currentHostSet, $matchedElement: event.currentTarget}, args);
|
|
614
|
-
};
|
|
615
|
-
|
|
616
|
-
// Create event stream with Observable-based operators
|
|
617
|
-
const eventSubject = new Subject<Event>();
|
|
618
|
-
let eventStream = eventSubject as any;
|
|
619
|
-
|
|
620
|
-
// Apply operators from @dooboostore/core/operators
|
|
621
|
-
if (options.debounceTime !== undefined && options.debounceTime > 0) {
|
|
622
|
-
eventStream = eventStream.pipe(debounceTime(options.debounceTime));
|
|
623
|
-
}
|
|
624
|
-
|
|
625
|
-
if (options.throttleTime !== undefined && options.throttleTime > 0) {
|
|
626
|
-
eventStream = eventStream.pipe(throttleTime(options.throttleTime));
|
|
627
|
-
}
|
|
628
|
-
|
|
629
|
-
if (options.distinctUntilChanged !== undefined && options.distinctUntilChanged !== false) {
|
|
630
|
-
if (typeof options.distinctUntilChanged === 'function') {
|
|
631
|
-
eventStream = eventStream.pipe(distinctUntilChanged(options.distinctUntilChanged));
|
|
632
|
-
} else {
|
|
633
|
-
eventStream = eventStream.pipe(distinctUntilChanged());
|
|
634
|
-
}
|
|
635
|
-
}
|
|
636
|
-
|
|
637
|
-
// Subscribe to the event stream
|
|
638
|
-
const subscription = eventStream.subscribe({
|
|
639
|
-
next: (event: Event) => {
|
|
640
|
-
handler(event).catch((err: any) => console.error('Event handler error:', err));
|
|
641
|
-
},
|
|
642
|
-
error: (err: any) => console.error('Event stream error:', err)
|
|
643
|
-
});
|
|
644
|
-
|
|
645
|
-
// Create wrapper handler that emits to the subject
|
|
646
|
-
const wrappedHandler = (event: Event) => {
|
|
647
|
-
eventSubject.next(event);
|
|
648
|
-
};
|
|
649
|
-
|
|
650
|
-
t.addEventListener(type, wrappedHandler, opts);
|
|
651
|
-
(this as any)._boundListeners.push({target: t, type, handler: wrappedHandler, options: opts, subscription});
|
|
652
|
-
});
|
|
653
|
-
});
|
|
654
|
-
|
|
655
|
-
if (originalConnected) await (originalConnected.apply(this));
|
|
656
|
-
|
|
657
|
-
const aMethods = findAllOnConnectedAfterMetadata(this); //.filter(it => { return useSsr ? !it.options.ssrFirst : true; });
|
|
658
|
-
// console.log('afterConnected', this.tagName, aMethods, getOnConnectedAfterMetadata(this))
|
|
659
|
-
for (const m of aMethods) await (this as any)._invokeLifecycleMethod(m.propertyKey, helperHostSet);
|
|
687
|
+
// after-connected 라이프사이클 메서드 (@onConnectedAfter)
|
|
688
|
+
for (const m of findAllOnConnectedAfterMetadata(this)) await (this as any)._invokeLifecycleMethod(m.propertyKey, helperHostSet);
|
|
660
689
|
(this as any)._executeSwcScript('swc-on-connected', helperHostSet);
|
|
661
690
|
(this as any)._executeSwcScript('swc-on-after-connected', helperHostSet);
|
|
662
691
|
(this as any).__swc_connected = true;
|
|
663
|
-
|
|
664
|
-
// Trigger @changedAttributeThis with while: 'connected'
|
|
665
|
-
for (let [name, metaList] of Array.from(attrChangeMap)) {
|
|
666
|
-
for (const meta of metaList) {
|
|
667
|
-
if (meta.options.while === 'connected') {
|
|
668
|
-
const val = getAttributeValue(this, name, {type: meta.options.type});
|
|
669
|
-
if (val !== null) {
|
|
670
|
-
await ((this as any)[meta.propertyKey](val, null, name, helperHostSet));
|
|
671
|
-
}
|
|
672
|
-
}
|
|
673
|
-
}
|
|
674
|
-
}
|
|
675
692
|
} finally {
|
|
676
|
-
for (
|
|
677
|
-
await (this as any)._invokeLifecycleMethod(m.propertyKey, helperHostSet);
|
|
678
|
-
}
|
|
693
|
+
for (const m of findAllLifecycleMetadata(this, ON_CONNECTED_COMPLETED_METADATA_KEY)) await (this as any)._invokeLifecycleMethod(m.propertyKey, helperHostSet);
|
|
679
694
|
if (appHost && typeof (appHost as any)._connectedDone === 'function') {
|
|
680
695
|
await (appHost as any)._connectedDone(this);
|
|
681
696
|
}
|
|
682
697
|
}
|
|
683
698
|
};
|
|
684
699
|
|
|
700
|
+
/////////////////////////////////////////////////
|
|
701
|
+
// disconnectedCallback
|
|
702
|
+
////////////////////////////////////////////////
|
|
685
703
|
const originalDisconnected = proto.disconnectedCallback;
|
|
686
704
|
proto.disconnectedCallback = function () {
|
|
687
|
-
|
|
688
|
-
// Remove from appHost LAST when disconnected
|
|
689
|
-
// console.log('disconnnnnnnnnnnnnnnnnnn', helperHostSet, this)
|
|
690
|
-
const appHost = helperHostSet.$appHost;
|
|
705
|
+
const appHost = helperHostSet?.$appHost;
|
|
691
706
|
if (appHost && typeof (appHost as any)._disconnected === 'function') {
|
|
692
707
|
(appHost as any)._disconnected(this);
|
|
693
708
|
}
|
|
694
709
|
|
|
695
710
|
(this as any)._executeSwcScript('swc-on-before-disconnected', helperHostSet);
|
|
696
|
-
const
|
|
697
|
-
for (const
|
|
698
|
-
|
|
699
|
-
if ((this as any)._boundListeners) {
|
|
700
|
-
(this as any)._boundListeners.forEach((l: any) => {
|
|
701
|
-
l.target.removeEventListener(l.type, l.handler, l.options);
|
|
702
|
-
// Cleanup Observable subscription if present
|
|
703
|
-
if (l.subscription && typeof l.subscription.unsubscribe === 'function') {
|
|
704
|
-
l.subscription.unsubscribe();
|
|
705
|
-
}
|
|
706
|
-
});
|
|
707
|
-
(this as any)._boundListeners = [];
|
|
708
|
-
}
|
|
711
|
+
for (const m of findAllLifecycleMetadata(this, ON_BEFORE_DISCONNECTED_METADATA_KEY)) (this as any)._invokeLifecycleMethod(m.propertyKey, helperHostSet);
|
|
712
|
+
for (const c of cyclers) c.onDisconnected?.(helperHostSet!);
|
|
709
713
|
|
|
710
|
-
|
|
714
|
+
for (const o of (this as any).__swc_observers ?? []) {
|
|
715
|
+
try { (o as any)?.disconnect?.(); } catch (e) { console.error('[SWC] observer disconnect error:', e); }
|
|
716
|
+
}
|
|
717
|
+
(this as any).__swc_observers = [];
|
|
711
718
|
|
|
712
|
-
//
|
|
713
|
-
|
|
714
|
-
// if (this.shadowRoot) {
|
|
715
|
-
// roots.push(this.shadowRoot);
|
|
716
|
-
// }
|
|
717
|
-
// roots.forEach(root => {
|
|
718
|
-
// DOM_EVENT_NAMES.forEach(type => {
|
|
719
|
-
// root.removeEventListener(type, handleGlobalSwcEvent);
|
|
720
|
-
// });
|
|
721
|
-
// }
|
|
722
|
-
// )
|
|
719
|
+
// elementApply event listener 정리
|
|
720
|
+
new ElementApply(this, { id: this._swcId }).removeAllEventListener();
|
|
723
721
|
|
|
724
722
|
if (originalDisconnected) originalDisconnected.apply(this);
|
|
725
723
|
|
|
726
|
-
const
|
|
727
|
-
for (const m of aMethods) (this as any)._invokeLifecycleMethod(m.propertyKey, helperHostSet);
|
|
724
|
+
for (const m of findAllLifecycleMetadata(this, ON_AFTER_DISCONNECTED_METADATA_KEY)) (this as any)._invokeLifecycleMethod(m.propertyKey, helperHostSet);
|
|
728
725
|
(this as any)._executeSwcScript('swc-on-disconnected', helperHostSet);
|
|
729
726
|
(this as any)._executeSwcScript('swc-on-after-disconnected', helperHostSet);
|
|
730
727
|
(this as any).__swc_connected = false;
|
|
@@ -734,13 +731,12 @@ export const elementDefine =
|
|
|
734
731
|
proto.adoptedCallback = function () {
|
|
735
732
|
const hostSet = SwcUtils.getHostSet(this as any);
|
|
736
733
|
(this as any)._executeSwcScript('swc-on-before-adopted', hostSet);
|
|
737
|
-
const
|
|
738
|
-
for (const
|
|
734
|
+
for (const m of findAllLifecycleMetadata(this, ON_BEFORE_ADOPTED_METADATA_KEY)) (this as any)._invokeLifecycleMethod(m.propertyKey, hostSet);
|
|
735
|
+
for (const c of cyclers) c.onAdopted?.(helperHostSet!);
|
|
739
736
|
|
|
740
737
|
if (originalAdopted) originalAdopted.apply(this);
|
|
741
738
|
|
|
742
|
-
const
|
|
743
|
-
for (const m of aMethods) (this as any)._invokeLifecycleMethod(m.propertyKey, hostSet);
|
|
739
|
+
for (const m of findAllLifecycleMetadata(this, ON_AFTER_ADOPTED_METADATA_KEY)) (this as any)._invokeLifecycleMethod(m.propertyKey, hostSet);
|
|
744
740
|
(this as any)._executeSwcScript('swc-on-adopted', hostSet);
|
|
745
741
|
(this as any)._executeSwcScript('swc-on-after-adopted', hostSet);
|
|
746
742
|
};
|
|
@@ -749,7 +745,9 @@ export const elementDefine =
|
|
|
749
745
|
proto.attributeChangedCallback = function (name: string, old: string | null, newVal: string | null) {
|
|
750
746
|
if (originalAttributeChanged) originalAttributeChanged.apply(this, [name, old, newVal]);
|
|
751
747
|
|
|
752
|
-
|
|
748
|
+
// attributeChangedCallback 은 connected 이전에도 호출될 수 있으므로
|
|
749
|
+
// 클로저의 helperHostSet(null 가능) 대신 이 시점에 새로 계산한다.
|
|
750
|
+
const helperAndHostSet = SwcUtils.getHelperAndHostSet(win, this as any);
|
|
753
751
|
|
|
754
752
|
// Process expression directive before passing to handlers
|
|
755
753
|
let processedVal: any = newVal;
|
|
@@ -758,18 +756,17 @@ export const elementDefine =
|
|
|
758
756
|
const expr = ae.getFirstExpression('callReturn');
|
|
759
757
|
if (expr) {
|
|
760
758
|
const win = (this as any)._resolveWindow?.() || ((typeof window !== 'undefined' ? window : undefined) as any);
|
|
761
|
-
const
|
|
759
|
+
const exprHelperAndHostSet = SwcUtils.getHelperAndHostSet(win, this as any);
|
|
762
760
|
const script = ConvertUtils.decodeHtmlEntity(expr.script, win.document);
|
|
763
761
|
try {
|
|
764
762
|
const result = FunctionUtils.executeReturn({
|
|
765
763
|
script: script,
|
|
766
764
|
context: this,
|
|
767
|
-
args:
|
|
765
|
+
args: exprHelperAndHostSet
|
|
768
766
|
});
|
|
769
|
-
// Pass the result object directly without serialization
|
|
770
767
|
processedVal = result;
|
|
771
768
|
} catch (e) {
|
|
772
|
-
console.error(`[SWC] Failed to execute directive {{= ${expr.script} }} on attribute ${name}: ${
|
|
769
|
+
console.error(`[SWC] Failed to execute directive {{= ${expr.script} }} on attribute ${name}: ${exprHelperAndHostSet}`, e);
|
|
773
770
|
processedVal = newVal;
|
|
774
771
|
}
|
|
775
772
|
}
|
|
@@ -782,21 +779,8 @@ export const elementDefine =
|
|
|
782
779
|
}
|
|
783
780
|
}
|
|
784
781
|
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
(this as any)._bindAttributeEvent(this as any, name, newVal, hostCustomEventMeta.type);
|
|
788
|
-
}
|
|
789
|
-
|
|
790
|
-
const metaList = attrChangeMap.get(name);
|
|
791
|
-
if (metaList && Array.isArray(metaList)) {
|
|
792
|
-
for (const meta of metaList) {
|
|
793
|
-
if (meta.options.while === 'connected' && !(this as any).__swc_connected) {
|
|
794
|
-
continue;
|
|
795
|
-
}
|
|
796
|
-
const convertedVal = convertAttributeValue(processedVal, meta.options.type);
|
|
797
|
-
(this as any)[meta.propertyKey](convertedVal, old, name, hSet);
|
|
798
|
-
}
|
|
799
|
-
}
|
|
782
|
+
// cycler 위임: attribute 옵저빙(@emitCustomEvent(attributeName) / @changedAttribute 등)
|
|
783
|
+
for (const c of cyclers) c.onAttributeChanged?.(helperAndHostSet, name, old, processedVal);
|
|
800
784
|
};
|
|
801
785
|
|
|
802
786
|
Object.defineProperty(constructor, 'observedAttributes', {
|
|
@@ -807,7 +791,7 @@ export const elementDefine =
|
|
|
807
791
|
ReflectUtils.defineMetadata(ELEMENT_CONFIG_KEY, metadata, constructor);
|
|
808
792
|
const registry = metadata.customElementRegistry || (win as any)?.customElements;
|
|
809
793
|
if (registry && !registry.get(metadata.name)) {
|
|
810
|
-
registry.define(metadata.name, constructor as any, metadata.extends ? {extends: metadata.extends} : undefined);
|
|
794
|
+
registry.define(metadata.name, constructor as any, metadata.extends ? { extends: metadata.extends } : undefined);
|
|
811
795
|
}
|
|
812
796
|
return constructor;
|
|
813
797
|
};
|