@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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dooboostore/simple-web-component",
3
- "version": "1.0.9",
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
- // swc-on-* 핸들러에 공통 주입되는 DOM 단축 헬퍼
24
- const $d = document;
25
- const $w = window;
26
- const $q = (sel: string, root?: Element | Document | ShadowRoot) => (root ?? document).querySelector(sel);
27
- const $qa = (sel: string, root?: Element | Document | ShadowRoot) => Array.from((root ?? document).querySelectorAll(sel));
28
- const $qi = (id: string, root?: Document | ShadowRoot) => (root ?? document).getElementById(id);
29
- const SWC_DOM_HELPERS = { $d, $w, $q, $qa, $qi } as const;
30
- const SWC_DOM_HELPER_KEYS = Object.keys(SWC_DOM_HELPERS) as (keyof typeof SWC_DOM_HELPERS)[];
31
- const SWC_DOM_HELPER_VALS = () => SWC_DOM_HELPER_KEYS.map(k => SWC_DOM_HELPERS[k]);
32
-
33
- const BUILT_IN_TAG_MAP = new Map<any, string>();
34
-
35
- const registerTag = (className: string, tagName: string) => {
36
- if (typeof globalThis !== 'undefined' && (globalThis as any)[className]) {
37
- BUILT_IN_TAG_MAP.set((globalThis as any)[className], tagName);
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
- ['HTMLAnchorElement', 'a'],
43
- ['HTMLAreaElement', 'area'],
44
- ['HTMLAudioElement', 'audio'],
45
- ['HTMLBaseElement', 'base'],
46
- ['HTMLButtonElement', 'button'],
47
- ['HTMLCanvasElement', 'canvas'],
48
- ['HTMLDataElement', 'data'],
49
- ['HTMLDataListElement', 'datalist'],
50
- ['HTMLDetailsElement', 'details'],
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 = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_TEXT);
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) { cur = SWC_NOT_FOUND; break; }
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
- this._observer = new MutationObserver(() => (this as any)._syncDecorators());
705
- this._observer.observe(this.shadowRoot || this, { childList: true, subtree: true });
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 customElements !== 'undefined' ? customElements : undefined);
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
+ }