@dooboostore/simple-web-component 1.0.9 → 1.0.10
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 +946 -63
- package/dist/cjs/decorators/elementDefine.js +47 -20
- package/dist/cjs/decorators/elementDefine.js.map +2 -2
- package/dist/cjs/decorators/lifecycles.js +27 -1
- package/dist/cjs/decorators/lifecycles.js.map +2 -2
- package/dist/cjs/index.js +45 -0
- package/dist/cjs/index.js.map +2 -2
- package/dist/esm/decorators/elementDefine.js +48 -21
- package/dist/esm/decorators/elementDefine.js.map +2 -2
- package/dist/esm/decorators/lifecycles.js +27 -1
- package/dist/esm/decorators/lifecycles.js.map +2 -2
- package/dist/esm/index.js +41 -0
- package/dist/esm/index.js.map +2 -2
- package/dist/esm-bundle/dooboostore-simple-web-component.esm.js +5618 -22
- package/dist/esm-bundle/dooboostore-simple-web-component.esm.js.map +4 -4
- package/dist/types/decorators/elementDefine.d.ts +1 -0
- package/dist/types/decorators/elementDefine.d.ts.map +1 -1
- package/dist/types/decorators/lifecycles.d.ts +26 -0
- package/dist/types/decorators/lifecycles.d.ts.map +1 -1
- package/dist/types/index.d.ts +18 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/umd-bundle/dooboostore-simple-web-component.umd.js +5618 -22
- package/dist/umd-bundle/dooboostore-simple-web-component.umd.js.map +4 -4
- package/package.json +3 -2
- package/src/decorators/elementDefine.ts +87 -87
- package/src/decorators/lifecycles.ts +61 -0
- package/src/index.ts +57 -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.10",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/cjs/index.js",
|
|
@@ -81,7 +81,8 @@
|
|
|
81
81
|
"reflect-metadata": "^0.2.2",
|
|
82
82
|
"@dooboostore/core": "1.0.28",
|
|
83
83
|
"@dooboostore/core-web": "1.0.9",
|
|
84
|
-
"@dooboostore/core-node": "1.0.10"
|
|
84
|
+
"@dooboostore/core-node": "1.0.10",
|
|
85
|
+
"@dooboostore/simple-boot": "1.0.53"
|
|
85
86
|
},
|
|
86
87
|
"scripts": {
|
|
87
88
|
"clean": "rm -rf dist",
|
|
@@ -3,7 +3,7 @@ import { getInnerHtmlMetadataList } from './innerHtml';
|
|
|
3
3
|
import { getQueryMetadata } from './query';
|
|
4
4
|
import { getQueryAllMetadata } from './queryAll';
|
|
5
5
|
import { getAddEventListenerMetadata } from './addEventListener';
|
|
6
|
-
import { getLifecycleMetadata, 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, ON_ADD_EVENT_LISTENER_METADATA_KEY, ON_ATTRIBUTE_CHANGED_METADATA_KEY, ATTRIBUTE_CHANGED_WILDCARD } from './lifecycles';
|
|
6
|
+
import { getLifecycleMetadata, 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, ON_ADD_EVENT_LISTENER_METADATA_KEY, ON_ATTRIBUTE_CHANGED_METADATA_KEY, ATTRIBUTE_CHANGED_WILDCARD, getMutationSubscribeMetadataList } from './lifecycles';
|
|
7
7
|
import { getAttributeMetadataList } from './attribute';
|
|
8
8
|
import { getStateMetadataList } from './state';
|
|
9
9
|
import { getEmitCustomEventMetadataList } from './emitCustomEvent';
|
|
@@ -15,92 +15,63 @@ export interface ElementConfig {
|
|
|
15
15
|
observedAttributes?: string[];
|
|
16
16
|
customElementRegistry?: CustomElementRegistry;
|
|
17
17
|
autoRemoveEventListeners?: boolean;
|
|
18
|
+
window?: Window;
|
|
18
19
|
}
|
|
19
20
|
|
|
20
21
|
export const ELEMENT_CONFIG_KEY = Symbol('simple-web-component:element-config');
|
|
21
22
|
export const STATE_CHANGE_EVENT = 'swc:state-change';
|
|
22
23
|
|
|
23
|
-
//
|
|
24
|
-
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
24
|
+
// --- 환경 초기화 헬퍼 ---
|
|
25
|
+
|
|
26
|
+
const HTML_TAG_ENTRIES: [string, string][] = [
|
|
27
|
+
['HTMLAnchorElement', 'a'], ['HTMLAreaElement', 'area'], ['HTMLAudioElement', 'audio'],
|
|
28
|
+
['HTMLBaseElement', 'base'], ['HTMLButtonElement', 'button'], ['HTMLCanvasElement', 'canvas'],
|
|
29
|
+
['HTMLDataElement', 'data'], ['HTMLDataListElement', 'datalist'], ['HTMLDetailsElement', 'details'],
|
|
30
|
+
['HTMLDialogElement', 'dialog'], ['HTMLDivElement', 'div'], ['HTMLDListElement', 'dl'],
|
|
31
|
+
['HTMLEmbedElement', 'embed'], ['HTMLFieldSetElement', 'fieldset'], ['HTMLFormElement', 'form'],
|
|
32
|
+
['HTMLHRElement', 'hr'], ['HTMLIFrameElement', 'iframe'], ['HTMLImageElement', 'img'],
|
|
33
|
+
['HTMLInputElement', 'input'], ['HTMLLabelElement', 'label'], ['HTMLLegendElement', 'legend'],
|
|
34
|
+
['HTMLLIElement', 'li'], ['HTMLLinkElement', 'link'], ['HTMLMapElement', 'map'],
|
|
35
|
+
['HTMLMetaElement', 'meta'], ['HTMLMeterElement', 'meter'], ['HTMLModElement', 'del'],
|
|
36
|
+
['HTMLObjectElement', 'object'], ['HTMLOListElement', 'ol'], ['HTMLOptGroupElement', 'optgroup'],
|
|
37
|
+
['HTMLOptionElement', 'option'], ['HTMLOutputElement', 'output'], ['HTMLParagraphElement', 'p'],
|
|
38
|
+
['HTMLParamElement', 'param'], ['HTMLPictureElement', 'picture'], ['HTMLPreElement', 'pre'],
|
|
39
|
+
['HTMLProgressElement', 'progress'], ['HTMLQuoteElement', 'blockquote'], ['HTMLScriptElement', 'script'],
|
|
40
|
+
['HTMLSelectElement', 'select'], ['HTMLSlotElement', 'slot'], ['HTMLSourceElement', 'source'],
|
|
41
|
+
['HTMLSpanElement', 'span'], ['HTMLStyleElement', 'style'], ['HTMLTableElement', 'table'],
|
|
42
|
+
['HTMLTableSectionElement', 'tbody'], ['HTMLTableCellElement', 'td'], ['HTMLTemplateElement', 'template'],
|
|
43
|
+
['HTMLTextAreaElement', 'textarea'], ['HTMLTimeElement', 'time'], ['HTMLTitleElement', 'title'],
|
|
44
|
+
['HTMLTableRowElement', 'tr'], ['HTMLTrackElement', 'track'], ['HTMLUListElement', 'ul'],
|
|
45
|
+
['HTMLVideoElement', 'video'], ['HTMLHeadingElement', 'h1'],
|
|
46
|
+
];
|
|
47
|
+
|
|
48
|
+
function buildEnv(configWindow?: Window) {
|
|
49
|
+
const win: any = configWindow || (typeof window !== 'undefined' ? window : undefined);
|
|
50
|
+
const doc: Document = win?.document;
|
|
51
|
+
|
|
52
|
+
const builtInTagMap = new Map<any, string>();
|
|
53
|
+
for (const [cls, tag] of HTML_TAG_ENTRIES) {
|
|
54
|
+
if (win?.[cls]) builtInTagMap.set(win[cls], tag);
|
|
38
55
|
}
|
|
39
|
-
};
|
|
40
56
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
['HTMLDialogElement', 'dialog'],
|
|
52
|
-
['HTMLDivElement', 'div'],
|
|
53
|
-
['HTMLDListElement', 'dl'],
|
|
54
|
-
['HTMLEmbedElement', 'embed'],
|
|
55
|
-
['HTMLFieldSetElement', 'fieldset'],
|
|
56
|
-
['HTMLFormElement', 'form'],
|
|
57
|
-
['HTMLHRElement', 'hr'],
|
|
58
|
-
['HTMLIFrameElement', 'iframe'],
|
|
59
|
-
['HTMLImageElement', 'img'],
|
|
60
|
-
['HTMLInputElement', 'input'],
|
|
61
|
-
['HTMLLabelElement', 'label'],
|
|
62
|
-
['HTMLLegendElement', 'legend'],
|
|
63
|
-
['HTMLLIElement', 'li'],
|
|
64
|
-
['HTMLLinkElement', 'link'],
|
|
65
|
-
['HTMLMapElement', 'map'],
|
|
66
|
-
['HTMLMetaElement', 'meta'],
|
|
67
|
-
['HTMLMeterElement', 'meter'],
|
|
68
|
-
['HTMLModElement', 'del'],
|
|
69
|
-
['HTMLObjectElement', 'object'],
|
|
70
|
-
['HTMLOListElement', 'ol'],
|
|
71
|
-
['HTMLOptGroupElement', 'optgroup'],
|
|
72
|
-
['HTMLOptionElement', 'option'],
|
|
73
|
-
['HTMLOutputElement', 'output'],
|
|
74
|
-
['HTMLParagraphElement', 'p'],
|
|
75
|
-
['HTMLParamElement', 'param'],
|
|
76
|
-
['HTMLPictureElement', 'picture'],
|
|
77
|
-
['HTMLPreElement', 'pre'],
|
|
78
|
-
['HTMLProgressElement', 'progress'],
|
|
79
|
-
['HTMLQuoteElement', 'blockquote'],
|
|
80
|
-
['HTMLScriptElement', 'script'],
|
|
81
|
-
['HTMLSelectElement', 'select'],
|
|
82
|
-
['HTMLSlotElement', 'slot'],
|
|
83
|
-
['HTMLSourceElement', 'source'],
|
|
84
|
-
['HTMLSpanElement', 'span'],
|
|
85
|
-
['HTMLStyleElement', 'style'],
|
|
86
|
-
['HTMLTableElement', 'table'],
|
|
87
|
-
['HTMLTableSectionElement', 'tbody'],
|
|
88
|
-
['HTMLTableCellElement', 'td'],
|
|
89
|
-
['HTMLTemplateElement', 'template'],
|
|
90
|
-
['HTMLTextAreaElement', 'textarea'],
|
|
91
|
-
['HTMLTimeElement', 'time'],
|
|
92
|
-
['HTMLTitleElement', 'title'],
|
|
93
|
-
['HTMLTableRowElement', 'tr'],
|
|
94
|
-
['HTMLTrackElement', 'track'],
|
|
95
|
-
['HTMLUListElement', 'ul'],
|
|
96
|
-
['HTMLVideoElement', 'video'],
|
|
97
|
-
['HTMLHeadingElement', 'h1']
|
|
98
|
-
].forEach(([cls, tag]) => registerTag(cls, tag));
|
|
57
|
+
const domHelpers = {
|
|
58
|
+
$d: doc,
|
|
59
|
+
$w: win,
|
|
60
|
+
$q: (sel: string, root?: Element | Document | ShadowRoot) => (root ?? doc).querySelector(sel),
|
|
61
|
+
$qa: (sel: string, root?: Element | Document | ShadowRoot) => Array.from((root ?? doc).querySelectorAll(sel)),
|
|
62
|
+
$qi: (id: string, root?: Document | ShadowRoot) => (root ?? doc).getElementById(id),
|
|
63
|
+
} as const;
|
|
64
|
+
|
|
65
|
+
return { win, doc, builtInTagMap, domHelpers };
|
|
66
|
+
}
|
|
99
67
|
|
|
100
68
|
export const elementDefine =
|
|
101
69
|
(inConfig: ElementConfig | string): ClassDecorator =>
|
|
102
70
|
(constructor: any) => {
|
|
103
71
|
const config: ElementConfig = typeof inConfig === 'string' ? { name: inConfig } : inConfig;
|
|
72
|
+
const { win, doc, builtInTagMap: BUILT_IN_TAG_MAP, domHelpers: SWC_DOM_HELPERS } = buildEnv(config.window);
|
|
73
|
+
const SWC_DOM_HELPER_KEYS = Object.keys(SWC_DOM_HELPERS) as (keyof typeof SWC_DOM_HELPERS)[];
|
|
74
|
+
const SWC_DOM_HELPER_VALS = () => SWC_DOM_HELPER_KEYS.map(k => (SWC_DOM_HELPERS as any)[k]);
|
|
104
75
|
|
|
105
76
|
let extendsTagName = config.extends;
|
|
106
77
|
if (!extendsTagName) {
|
|
@@ -123,6 +94,7 @@ export const elementDefine =
|
|
|
123
94
|
const NewClass = class extends (constructor as any) {
|
|
124
95
|
private _swcId = Math.random().toString(36).substring(2, 11);
|
|
125
96
|
private _observer: MutationObserver | null = null;
|
|
97
|
+
private _shadowObserver: MutationObserver | null = null;
|
|
126
98
|
private _boundElements = new WeakMap<Element, Set<string | symbol>>();
|
|
127
99
|
private _activeListeners: Array<{ el: Element | HTMLElement; type: string; handler: EventListener; options?: any }> = [];
|
|
128
100
|
private _emitHandlers = new Map<string, EventListener>();
|
|
@@ -352,7 +324,7 @@ export const elementDefine =
|
|
|
352
324
|
|
|
353
325
|
private _buildStateMap() {
|
|
354
326
|
const scan = (root: Node) => {
|
|
355
|
-
const walker =
|
|
327
|
+
const walker = doc.createTreeWalker(root, (win as any).NodeFilter.SHOW_ELEMENT | (win as any).NodeFilter.SHOW_TEXT);
|
|
356
328
|
let node: Node | null = null;
|
|
357
329
|
while ((node = walker.nextNode())) {
|
|
358
330
|
if (node.nodeType === Node.TEXT_NODE) this._parseAndBind(node, 'text');
|
|
@@ -417,8 +389,7 @@ export const elementDefine =
|
|
|
417
389
|
const $firstHost = $hosts[0] || null;
|
|
418
390
|
const $lastHost = $hosts[$hosts.length - 1] || null;
|
|
419
391
|
const $host = $lastHost;
|
|
420
|
-
new Function('event', '$data', '$host', '$hosts', '$firstHost', '$lastHost', ...SWC_DOM_HELPER_KEYS, rawScript)
|
|
421
|
-
.call(el, event, (event as CustomEvent).detail, $host, $hosts, $firstHost, $lastHost, ...SWC_DOM_HELPER_VALS());
|
|
392
|
+
new Function('event', '$data', '$host', '$hosts', '$firstHost', '$lastHost', ...SWC_DOM_HELPER_KEYS, rawScript).call(el, event, (event as CustomEvent).detail, $host, $hosts, $firstHost, $lastHost, ...SWC_DOM_HELPER_VALS());
|
|
422
393
|
} catch (e) {
|
|
423
394
|
console.error(`[SWC] Failed to execute ${attr.name} script:`, e);
|
|
424
395
|
}
|
|
@@ -435,9 +406,7 @@ export const elementDefine =
|
|
|
435
406
|
|
|
436
407
|
// --- Scope Protection: Don't scan inside child SWC components ---
|
|
437
408
|
// is 어트리뷰트 방식 커스텀 엘리먼트도 포함 (swc-for-of-*, swc-if-* 등)
|
|
438
|
-
const isSwcChild = (el as any)._swcId
|
|
439
|
-
|| getElementConfig(el.constructor)
|
|
440
|
-
|| (el.getAttribute('is')?.startsWith('swc-') ?? false);
|
|
409
|
+
const isSwcChild = (el as any)._swcId || getElementConfig(el.constructor) || (el.getAttribute('is')?.startsWith('swc-') ?? false);
|
|
441
410
|
if (isSwcChild) {
|
|
442
411
|
const next = walker.nextSibling();
|
|
443
412
|
if (!next) break;
|
|
@@ -536,7 +505,10 @@ export const elementDefine =
|
|
|
536
505
|
const parts = subPath.split('.');
|
|
537
506
|
let cur = rootVal;
|
|
538
507
|
for (const p of parts) {
|
|
539
|
-
if (cur === null || cur === undefined) {
|
|
508
|
+
if (cur === null || cur === undefined) {
|
|
509
|
+
cur = SWC_NOT_FOUND;
|
|
510
|
+
break;
|
|
511
|
+
}
|
|
540
512
|
cur = cur[p];
|
|
541
513
|
}
|
|
542
514
|
if (cur !== undefined && cur !== SWC_NOT_FOUND) val = cur;
|
|
@@ -589,6 +561,7 @@ export const elementDefine =
|
|
|
589
561
|
if (typeof (this as any)[m] === 'function') (this as any)[m]();
|
|
590
562
|
});
|
|
591
563
|
if (this._observer) this._observer.disconnect();
|
|
564
|
+
if (this._shadowObserver) this._shadowObserver.disconnect();
|
|
592
565
|
if (config.autoRemoveEventListeners) {
|
|
593
566
|
this._activeListeners.forEach(({ el, type, handler, options }) => el.removeEventListener(type, handler, options));
|
|
594
567
|
this._activeListeners = [];
|
|
@@ -685,8 +658,7 @@ export const elementDefine =
|
|
|
685
658
|
const $firstHost = $hosts[0] || null;
|
|
686
659
|
const $lastHost = $hosts[$hosts.length - 1] || null;
|
|
687
660
|
const $host = $lastHost;
|
|
688
|
-
new Function('event', '$data', '$host', '$hosts', '$firstHost', '$lastHost', ...SWC_DOM_HELPER_KEYS, script)
|
|
689
|
-
.call(this, event, (event as CustomEvent).detail, $host, $hosts, $firstHost, $lastHost, ...SWC_DOM_HELPER_VALS());
|
|
661
|
+
new Function('event', '$data', '$host', '$hosts', '$firstHost', '$lastHost', ...SWC_DOM_HELPER_KEYS, script).call(this, event, (event as CustomEvent).detail, $host, $hosts, $firstHost, $lastHost, ...SWC_DOM_HELPER_VALS());
|
|
690
662
|
} catch (e) {
|
|
691
663
|
console.error(`[SWC] Failed to execute ${attr.name} script:`, e);
|
|
692
664
|
}
|
|
@@ -701,8 +673,36 @@ export const elementDefine =
|
|
|
701
673
|
});
|
|
702
674
|
}
|
|
703
675
|
|
|
704
|
-
|
|
705
|
-
|
|
676
|
+
const mutationMetaList = getMutationSubscribeMetadataList(this);
|
|
677
|
+
|
|
678
|
+
const fireMutationCallbacks = (mutationList: MutationRecord[], observer: MutationObserver, root: 'light' | 'shadow') => {
|
|
679
|
+
mutationMetaList?.forEach(meta => {
|
|
680
|
+
const r = meta.options.root ?? 'auto';
|
|
681
|
+
const matches =
|
|
682
|
+
r === 'all' ||
|
|
683
|
+
r === root ||
|
|
684
|
+
(r === 'auto' && (this.shadowRoot ? root === 'shadow' : root === 'light'));
|
|
685
|
+
if (matches && typeof (this as any)[meta.propertyKey] === 'function') {
|
|
686
|
+
(this as any)[meta.propertyKey](mutationList, observer, root);
|
|
687
|
+
}
|
|
688
|
+
});
|
|
689
|
+
};
|
|
690
|
+
|
|
691
|
+
this._observer = new (win as any).MutationObserver((mutationList: MutationRecord[], observer: MutationObserver) => {
|
|
692
|
+
(this as any)._syncDecorators();
|
|
693
|
+
fireMutationCallbacks(mutationList, observer, 'light');
|
|
694
|
+
});
|
|
695
|
+
// @ts-ignore
|
|
696
|
+
this._observer.observe(this as any, { childList: true, subtree: true });
|
|
697
|
+
|
|
698
|
+
if (this.shadowRoot) {
|
|
699
|
+
this._shadowObserver = new (win as any).MutationObserver((mutationList: MutationRecord[], observer: MutationObserver) => {
|
|
700
|
+
(this as any)._syncDecorators();
|
|
701
|
+
fireMutationCallbacks(mutationList, observer, 'shadow');
|
|
702
|
+
});
|
|
703
|
+
// @ts-ignore
|
|
704
|
+
this._shadowObserver.observe(this.shadowRoot, { childList: true, subtree: true });
|
|
705
|
+
}
|
|
706
706
|
if (super.connectedCallback) await super.connectedCallback();
|
|
707
707
|
const aMethods = getLifecycleMetadata<(string | symbol)[]>(this, ON_AFTER_CONNECTED_METADATA_KEY);
|
|
708
708
|
aMethods?.forEach(m => {
|
|
@@ -756,7 +756,7 @@ export const elementDefine =
|
|
|
756
756
|
}
|
|
757
757
|
};
|
|
758
758
|
|
|
759
|
-
const registry = config.customElementRegistry || (typeof
|
|
759
|
+
const registry = config.customElementRegistry || (typeof win !== 'undefined' ? win.customElements : undefined);
|
|
760
760
|
if (registry && !registry.get(config.name)) {
|
|
761
761
|
const options = config.extends ? { extends: config.extends } : undefined;
|
|
762
762
|
registry.define(config.name, NewClass as any, options);
|
|
@@ -8,6 +8,7 @@ export const ON_BEFORE_ADOPTED_METADATA_KEY = Symbol('simple-web-component:on-be
|
|
|
8
8
|
export const ON_AFTER_ADOPTED_METADATA_KEY = Symbol('simple-web-component:on-after-adopted');
|
|
9
9
|
export const ON_ADD_EVENT_LISTENER_METADATA_KEY = Symbol('simple-web-component:on-add-event-listener');
|
|
10
10
|
export const ON_ATTRIBUTE_CHANGED_METADATA_KEY = Symbol('simple-web-component:on-attribute-changed');
|
|
11
|
+
export const ON_MUTATION_SUBSCRIBE_METADATA_KEY = Symbol('simple-web-component:on-mutation-observed');
|
|
11
12
|
|
|
12
13
|
export const ATTRIBUTE_CHANGED_WILDCARD = '*';
|
|
13
14
|
|
|
@@ -75,3 +76,63 @@ export const getLifecycleMetadata = <T = (string | symbol)[]>(target: any, metad
|
|
|
75
76
|
const constructor = target instanceof Function ? target : target.constructor;
|
|
76
77
|
return ReflectUtils.getMetadata(metadataKey, constructor);
|
|
77
78
|
};
|
|
79
|
+
|
|
80
|
+
// ─── @onMutationSubscribe ─────────────────────────────────────────────────────
|
|
81
|
+
|
|
82
|
+
export interface MutationSubscribeOptions {
|
|
83
|
+
root?: 'light' | 'shadow' | 'all' | 'auto'; // default: 'auto'
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export interface MutationSubscribeMetadata {
|
|
87
|
+
propertyKey: string | symbol;
|
|
88
|
+
options: MutationSubscribeOptions;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Called when MutationObserver detects DOM changes inside the component.
|
|
93
|
+
*
|
|
94
|
+
* @example
|
|
95
|
+
* // Parameterless — observes auto (shadow if exists, otherwise light)
|
|
96
|
+
* @onMutationObserved
|
|
97
|
+
* onMutation(mutationList: MutationRecord[], observer: MutationObserver) { ... }
|
|
98
|
+
*
|
|
99
|
+
* // With options
|
|
100
|
+
* @onMutationObserved({ root: 'shadow' })
|
|
101
|
+
* onShadowMutation(mutationList: MutationRecord[], observer: MutationObserver) { ... }
|
|
102
|
+
*
|
|
103
|
+
* @onMutationObserved({ root: 'all' })
|
|
104
|
+
* onAllMutation(mutationList: MutationRecord[], observer: MutationObserver) { ... }
|
|
105
|
+
*/
|
|
106
|
+
export function onMutationSubscribe(options: MutationSubscribeOptions): MethodDecorator;
|
|
107
|
+
export function onMutationSubscribe(target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor): void;
|
|
108
|
+
export function onMutationSubscribe(
|
|
109
|
+
arg1: MutationSubscribeOptions | Object,
|
|
110
|
+
arg2?: string | symbol,
|
|
111
|
+
arg3?: PropertyDescriptor
|
|
112
|
+
): MethodDecorator | void {
|
|
113
|
+
const register = (options: MutationSubscribeOptions, target: Object, propertyKey: string | symbol) => {
|
|
114
|
+
const constructor = target.constructor;
|
|
115
|
+
let list = ReflectUtils.getMetadata<MutationSubscribeMetadata[]>(ON_MUTATION_SUBSCRIBE_METADATA_KEY, constructor);
|
|
116
|
+
if (!list) {
|
|
117
|
+
list = [];
|
|
118
|
+
ReflectUtils.defineMetadata(ON_MUTATION_SUBSCRIBE_METADATA_KEY, list, constructor);
|
|
119
|
+
}
|
|
120
|
+
list.push({ propertyKey, options });
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
// Used as @onMutationObserved (no parentheses)
|
|
124
|
+
if (arg2 !== undefined) {
|
|
125
|
+
register({ root: 'auto' }, arg1 as Object, arg2);
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Used as @onMutationObserved({ root: 'shadow' })
|
|
130
|
+
return (target: Object, propertyKey: string | symbol) => {
|
|
131
|
+
register((arg1 as MutationSubscribeOptions) || { root: 'auto' }, target, propertyKey);
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
export const getMutationSubscribeMetadataList = (target: any): MutationSubscribeMetadata[] | undefined => {
|
|
136
|
+
const constructor = target instanceof Function ? target : target.constructor;
|
|
137
|
+
return ReflectUtils.getMetadata(ON_MUTATION_SUBSCRIBE_METADATA_KEY, constructor);
|
|
138
|
+
};
|
package/src/index.ts
CHANGED
|
@@ -1,4 +1,11 @@
|
|
|
1
1
|
import 'reflect-metadata';
|
|
2
|
+
import {HashRouter, PathRouter, Router} from "@dooboostore/core-web";
|
|
3
|
+
import {RouterEventType} from '@dooboostore/core-web/routers/Router'
|
|
4
|
+
import {ConstructorType, Optional} from "@dooboostore/core/types";
|
|
5
|
+
import {SimConfig} from "@dooboostore/simple-boot/decorators/SimDecorator";
|
|
6
|
+
import {SimpleApplication} from "@dooboostore/simple-boot/SimpleApplication";
|
|
7
|
+
import {SimOption} from "@dooboostore/simple-boot/SimOption";
|
|
8
|
+
|
|
2
9
|
export * from './decorators/elementDefine';
|
|
3
10
|
export * from './decorators/innerHtml';
|
|
4
11
|
export * from './decorators/attribute';
|
|
@@ -579,3 +586,53 @@ export * from './is/SwcChooseChildrenHeading';
|
|
|
579
586
|
export * from './is/SwcChooseHeading';
|
|
580
587
|
export * from './is/SwcWhenHeading';
|
|
581
588
|
export * from './is/SwcOtherHeading';
|
|
589
|
+
|
|
590
|
+
|
|
591
|
+
export type SwcConfigType = { rootRouter: ConstructorType<any>, routeType: 'path' | 'hash', window: Window };
|
|
592
|
+
|
|
593
|
+
export class Swc {
|
|
594
|
+
private _config: SwcConfigType;
|
|
595
|
+
private _router: Router;
|
|
596
|
+
private simpleApplication: SimpleApplication;
|
|
597
|
+
|
|
598
|
+
|
|
599
|
+
get config() {
|
|
600
|
+
return this._config;
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
get router() {
|
|
604
|
+
return this._router;
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
constructor(config: Optional<SwcConfigType, 'routeType' | 'window'>) {
|
|
608
|
+
this._config = {
|
|
609
|
+
routeType: 'path',
|
|
610
|
+
window: window,
|
|
611
|
+
...config,
|
|
612
|
+
};
|
|
613
|
+
this._router = this._config.routeType === 'path' ? new PathRouter({window: this._config.window}) : new HashRouter({window: this._config.window});
|
|
614
|
+
const option = new SimOption({excludeProxys: [Node], rootRouter: this._config.rootRouter});
|
|
615
|
+
this.simpleApplication = new SimpleApplication(option);
|
|
616
|
+
|
|
617
|
+
this._router.observable.subscribe((route: RouterEventType) => {
|
|
618
|
+
if (route.triggerPoint === 'start') {
|
|
619
|
+
this.routingProcess(route.path);
|
|
620
|
+
}
|
|
621
|
+
})
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
run() {
|
|
625
|
+
const otherInstanceSim = new Map<ConstructorType<any> | Function | SimConfig | Symbol, any>();
|
|
626
|
+
otherInstanceSim.set(Router, this._router);
|
|
627
|
+
this.simpleApplication.run(otherInstanceSim);
|
|
628
|
+
return this.simpleApplication.sim(this._config.rootRouter);
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
async routing(path: string) {
|
|
632
|
+
await this._router.go(path);
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
private async routingProcess(path: string) {
|
|
636
|
+
await this.simpleApplication.routing(path);
|
|
637
|
+
}
|
|
638
|
+
}
|