lahama 4.0.0 → 6.0.0
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/dist/lahama.js +919 -6
- package/package.json +1 -1
package/dist/lahama.js
CHANGED
|
@@ -1,17 +1,158 @@
|
|
|
1
|
-
import 'vitest/dist/chunks/reporters.d.OXEK7y4s.d.ts';
|
|
2
|
-
|
|
3
1
|
function withoutNulls(arr) {
|
|
4
2
|
return arr.filter((item) => item != null)
|
|
5
3
|
}
|
|
4
|
+
function arraysDiff(oldArray, newArray) {
|
|
5
|
+
return {
|
|
6
|
+
added : newArray.filter(
|
|
7
|
+
(newItem) => !oldArray.includes(newItem)
|
|
8
|
+
),
|
|
9
|
+
removed : oldArray.filter(
|
|
10
|
+
(oldItem) => !newArray.includes(oldItem)
|
|
11
|
+
)
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
const ARRAY_DIFF_OP = {
|
|
15
|
+
ADD : 'add',
|
|
16
|
+
REMOVE : 'remove',
|
|
17
|
+
MOVE : 'move',
|
|
18
|
+
NOOP : 'noop'
|
|
19
|
+
};
|
|
6
20
|
const a = { };
|
|
7
21
|
const b = { };
|
|
8
22
|
console.log(a === b);
|
|
23
|
+
class ArrayWithOriginalIndices {
|
|
24
|
+
#array = []
|
|
25
|
+
#originalIndices = []
|
|
26
|
+
#equalsFn
|
|
27
|
+
constructor(array, equalsFn) {
|
|
28
|
+
this.#array = [...array];
|
|
29
|
+
this.#originalIndices = array.map((_, i) => i);
|
|
30
|
+
this.#equalsFn = equalsFn;
|
|
31
|
+
}
|
|
32
|
+
get length() {
|
|
33
|
+
return this.#array.length
|
|
34
|
+
}
|
|
35
|
+
isRemoval(index, newArray) {
|
|
36
|
+
if (index >= this.length) {
|
|
37
|
+
return false
|
|
38
|
+
}
|
|
39
|
+
const item = this.#array[index];
|
|
40
|
+
const indexInNewArray = newArray.findIndex((newItem) =>
|
|
41
|
+
this.#equalsFn(item, newItem)
|
|
42
|
+
);
|
|
43
|
+
return indexInNewArray === -1
|
|
44
|
+
}
|
|
45
|
+
removeItem(index) {
|
|
46
|
+
const operation = {
|
|
47
|
+
op : ARRAY_DIFF_OP.REMOVE,
|
|
48
|
+
index,
|
|
49
|
+
item : this.#array[index],
|
|
50
|
+
};
|
|
51
|
+
this.#array.splice(index, 1);
|
|
52
|
+
return operation
|
|
53
|
+
}
|
|
54
|
+
isNoop(index, newArray) {
|
|
55
|
+
if (index >= this.length) {
|
|
56
|
+
return false
|
|
57
|
+
}
|
|
58
|
+
const item = this.#array[index];
|
|
59
|
+
const newItem = newArray[index];
|
|
60
|
+
return this.#equalsFn(item, newItem)
|
|
61
|
+
}
|
|
62
|
+
originalIndexAt(index) {
|
|
63
|
+
return this.#originalIndices[index]
|
|
64
|
+
}
|
|
65
|
+
noopItem(index) {
|
|
66
|
+
return {
|
|
67
|
+
op : ARRAY_DIFF_OP.NOOP,
|
|
68
|
+
originalIndex : this.originalIndexAt(index),
|
|
69
|
+
item : this.#array[index],
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
isAddition(item, fromIdx) {
|
|
73
|
+
return this.findIndexFrom(item, fromIdx) === -1
|
|
74
|
+
}
|
|
75
|
+
findIndexFrom(item, fromIndex) {
|
|
76
|
+
for (let i = fromIndex; i < this.length; i++) {
|
|
77
|
+
if (this.#equalsFn(item, this.#array[i])) {
|
|
78
|
+
return i
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return -1
|
|
82
|
+
}
|
|
83
|
+
addItem(item, index) {
|
|
84
|
+
const operation = {
|
|
85
|
+
op : ARRAY_DIFF_OP.ADD,
|
|
86
|
+
index,
|
|
87
|
+
item
|
|
88
|
+
};
|
|
89
|
+
this.#array.splice(index, 0, item);
|
|
90
|
+
this.#originalIndices.splice(index, 0, -1);
|
|
91
|
+
return operation
|
|
92
|
+
}
|
|
93
|
+
moveItem(item, toIndex) {
|
|
94
|
+
const fromIndex = this.findIndexFrom(item, toIndex);
|
|
95
|
+
const operation = {
|
|
96
|
+
op : ARRAY_DIFF_OP.MOVE,
|
|
97
|
+
originalIndex : this.originalIndexAt(fromIndex),
|
|
98
|
+
from : fromIndex,
|
|
99
|
+
index : toIndex,
|
|
100
|
+
item : this.#array[fromIndex]
|
|
101
|
+
};
|
|
102
|
+
const [_item] = this.#array.splice(fromIndex, 1);
|
|
103
|
+
this.#array.splice(toIndex, 0 , _item);
|
|
104
|
+
const [originalIndex] =
|
|
105
|
+
this.#originalIndices.splice(fromIndex, 1);
|
|
106
|
+
this.#originalIndices.splice(toIndex, 0, originalIndex);
|
|
107
|
+
return operation
|
|
108
|
+
}
|
|
109
|
+
removeItemsAfter(index) {
|
|
110
|
+
const operations = [];
|
|
111
|
+
while (this.length > index) {
|
|
112
|
+
operations.push(this.removeItem(index));
|
|
113
|
+
}
|
|
114
|
+
return operations
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
function arraysDiffSequence(
|
|
118
|
+
oldArray,
|
|
119
|
+
newArray,
|
|
120
|
+
equalsFn = (a, b) => a === b
|
|
121
|
+
) {
|
|
122
|
+
const sequence = [];
|
|
123
|
+
const array = new ArrayWithOriginalIndices(oldArray, equalsFn);
|
|
124
|
+
for (let index = 0; index < newArray.length; index++) {
|
|
125
|
+
//!REMOVE CASE
|
|
126
|
+
if (array.isRemoval(index, newArray)) {
|
|
127
|
+
sequence.push(array.removeItem(index));
|
|
128
|
+
index--;
|
|
129
|
+
continue
|
|
130
|
+
}
|
|
131
|
+
//!noop case
|
|
132
|
+
if (array.isNoop(index, newArray)) {
|
|
133
|
+
sequence.push(array.noopItem(index));
|
|
134
|
+
continue
|
|
135
|
+
}
|
|
136
|
+
//!addition case
|
|
137
|
+
const item = newArray[index];
|
|
138
|
+
if (array.isAddition(item , index)) {
|
|
139
|
+
sequence.push(array.addItem(item, index));
|
|
140
|
+
continue
|
|
141
|
+
}
|
|
142
|
+
//!move case
|
|
143
|
+
sequence.push(array.moveItem(item, index));
|
|
144
|
+
}
|
|
145
|
+
//!remove extra items
|
|
146
|
+
sequence.push(...array.removeItemsAfter(newArray.length));
|
|
147
|
+
return sequence
|
|
148
|
+
}
|
|
9
149
|
|
|
10
150
|
const DOM_TYPES = {
|
|
11
151
|
TEXT : 'text',
|
|
12
152
|
ELEMENT : 'element',
|
|
13
153
|
FRAGMENT : 'fragment',
|
|
14
154
|
COMPONENT : 'component',
|
|
155
|
+
SLOT : 'slot'
|
|
15
156
|
};
|
|
16
157
|
function h(tag, props = {} , children = []) {
|
|
17
158
|
const type =
|
|
@@ -36,6 +177,17 @@ function hFragment(vNodes) {
|
|
|
36
177
|
children : mapTextNodes(withoutNulls(vNodes)),
|
|
37
178
|
}
|
|
38
179
|
}
|
|
180
|
+
let hSlotCalled = false;
|
|
181
|
+
function didCreateSlot() {
|
|
182
|
+
return hSlotCalled
|
|
183
|
+
}
|
|
184
|
+
function resetDidCreateSlot() {
|
|
185
|
+
hSlotCalled = false;
|
|
186
|
+
}
|
|
187
|
+
function hSlot(children = []) {
|
|
188
|
+
hSlotCalled = true;
|
|
189
|
+
return { type : DOM_TYPES.SLOT, children}
|
|
190
|
+
}
|
|
39
191
|
|
|
40
192
|
function addEventListener(
|
|
41
193
|
eventName,
|
|
@@ -100,6 +252,9 @@ function setClass(el, className) {
|
|
|
100
252
|
function setStyle(el, name, value) {
|
|
101
253
|
el.style[name] = value;
|
|
102
254
|
}
|
|
255
|
+
function removeStyle(el, name) {
|
|
256
|
+
el.style[name] = null;
|
|
257
|
+
}
|
|
103
258
|
function removeAttributeCustom(el, name) {
|
|
104
259
|
el[name] = null;
|
|
105
260
|
el.removeAttribute(name);
|
|
@@ -146,6 +301,13 @@ function processJobs() {
|
|
|
146
301
|
}
|
|
147
302
|
isScheduled = false;
|
|
148
303
|
}
|
|
304
|
+
function nextTick() {
|
|
305
|
+
scheduleUpdate();
|
|
306
|
+
return flushPromises()
|
|
307
|
+
}
|
|
308
|
+
function flushPromises() {
|
|
309
|
+
return new Promise((resolve) => setTimeout(resolve))
|
|
310
|
+
}
|
|
149
311
|
|
|
150
312
|
function mountDom(
|
|
151
313
|
vdom,
|
|
@@ -218,9 +380,11 @@ function createFragmentNodes(vdom, parentEl, index, hostComponent) {
|
|
|
218
380
|
children.forEach((child, i) => mountDom(child, parentEl, index ? index + i : null, hostComponent));
|
|
219
381
|
}
|
|
220
382
|
function createComponentNode(vdom, parentEl, index, hostComponent) {
|
|
221
|
-
const Component = vdom
|
|
383
|
+
const { tag : Component, children } = vdom;
|
|
222
384
|
const { props, events } = extractPropsAndEvents(vdom);
|
|
223
385
|
const component = new Component(props, events, hostComponent);
|
|
386
|
+
component.setExternalContent(children);
|
|
387
|
+
component.setAppContext(hostComponent?.appContext ?? {});
|
|
224
388
|
component.mount(parentEl, index);
|
|
225
389
|
vdom.component = component;
|
|
226
390
|
vdom.el = component.firstElement;
|
|
@@ -270,10 +434,253 @@ function removeFragmentNode(vdom) {
|
|
|
270
434
|
children.forEach(destroyDom);
|
|
271
435
|
}
|
|
272
436
|
|
|
273
|
-
function
|
|
437
|
+
function makeRouteMatcher(route) {
|
|
438
|
+
return routeHasParams(route)
|
|
439
|
+
? makeMatcherWithParams(route)
|
|
440
|
+
: makeMatcherWithoutParams(route)
|
|
441
|
+
}
|
|
442
|
+
function routeHasParams({ path }) {
|
|
443
|
+
return path.includes(':')
|
|
444
|
+
}
|
|
445
|
+
const CATCH_ALL_ROUTE = '*';
|
|
446
|
+
function makeRouteWithoutParamsRegex( { path }) {
|
|
447
|
+
if (path === CATCH_ALL_ROUTE) {
|
|
448
|
+
return new RegExp('^.*$')
|
|
449
|
+
}
|
|
450
|
+
return new RegExp(`^${path}`)
|
|
451
|
+
}
|
|
452
|
+
function makeMatcherWithoutParams(route) {
|
|
453
|
+
const regex = makeRouteWithoutParamsRegex(route);
|
|
454
|
+
const isRedirect = typeof route.redirect === 'string';
|
|
455
|
+
return {
|
|
456
|
+
route,
|
|
457
|
+
isRedirect,
|
|
458
|
+
checkMatch(path) {
|
|
459
|
+
return regex.test(path)
|
|
460
|
+
},
|
|
461
|
+
extractParams() {
|
|
462
|
+
return {}
|
|
463
|
+
},
|
|
464
|
+
extractQuery,
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
function extractQuery(path) {
|
|
468
|
+
const queryIndex = path.indexOf('?');
|
|
469
|
+
if (queryIndex === -1) {
|
|
470
|
+
return {}
|
|
471
|
+
}
|
|
472
|
+
const search = new URLSearchParams(path.slice(queryIndex + 1));
|
|
473
|
+
return Object.fromEntries(search.entries())
|
|
474
|
+
}
|
|
475
|
+
function makeRouteWithParamsRegex({ path }) {
|
|
476
|
+
const regex = path.replace(
|
|
477
|
+
/:([^/]+)/g,
|
|
478
|
+
(_, paramName) => `(?<${paramName}>[^/]+)`
|
|
479
|
+
);
|
|
480
|
+
return new RegExp(`^${regex}$`)
|
|
481
|
+
}
|
|
482
|
+
function makeMatcherWithParams(route) {
|
|
483
|
+
const regex = makeRouteWithParamsRegex(route);
|
|
484
|
+
const isRedirect = typeof route.redirect === 'string';
|
|
485
|
+
return {
|
|
486
|
+
route,
|
|
487
|
+
isRedirect,
|
|
488
|
+
checkMatch(path) {
|
|
489
|
+
return regex.test(path)
|
|
490
|
+
},
|
|
491
|
+
extractParams(path) {
|
|
492
|
+
const { groups } = regex.exec(path);
|
|
493
|
+
return groups
|
|
494
|
+
},
|
|
495
|
+
extractQuery,
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
class Dispatcher {
|
|
500
|
+
#subs = new Map()
|
|
501
|
+
#afterHandlers = []
|
|
502
|
+
subscribe(commandName, handler) {
|
|
503
|
+
if (!this.#subs.has(commandName)) {
|
|
504
|
+
this.#subs.set(commandName, []);
|
|
505
|
+
}
|
|
506
|
+
const handlersArray = this.#subs.get(commandName);
|
|
507
|
+
if (handlersArray.includes(handler)) {
|
|
508
|
+
return () => {
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
handlersArray.push(handler);
|
|
512
|
+
return () => {
|
|
513
|
+
const idx = handlersArray.indexOf(handler);
|
|
514
|
+
handlersArray.splice(idx, 1);
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
afterEveryCommand(handler) {
|
|
518
|
+
this.#afterHandlers.push(handler);
|
|
519
|
+
return () => {
|
|
520
|
+
const idx = this.#afterHandlers.indexOf(handler);
|
|
521
|
+
this.#afterHandlers.splice(idx, 1);
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
dispatch(commandName, payload) {
|
|
525
|
+
if (this.#subs.has(commandName)) {
|
|
526
|
+
this.#subs.get(commandName).forEach((handler) => handler(payload));
|
|
527
|
+
} else {
|
|
528
|
+
console.warn(`No handlers for command : ${commandName}`);
|
|
529
|
+
}
|
|
530
|
+
this.#afterHandlers.forEach((handler) => handler());
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
const ROUTER_EVENT = 'router-event';
|
|
535
|
+
class HashRouter {
|
|
536
|
+
#matchers = []
|
|
537
|
+
#isInitialized = false
|
|
538
|
+
#onPopState = () => this.#matchCurrentRoute()
|
|
539
|
+
#params = {}
|
|
540
|
+
#query = {}
|
|
541
|
+
#matchedRoute = null
|
|
542
|
+
#dispatcher = new Dispatcher()
|
|
543
|
+
#subscriptions = new WeakMap()
|
|
544
|
+
#subscriberFns = new Set()
|
|
545
|
+
get params() {
|
|
546
|
+
return this.#params
|
|
547
|
+
}
|
|
548
|
+
get query() {
|
|
549
|
+
return this.#query
|
|
550
|
+
}
|
|
551
|
+
get matchedRoute() {
|
|
552
|
+
return this.#matchedRoute
|
|
553
|
+
}
|
|
554
|
+
constructor(routes = []) {
|
|
555
|
+
this.#matchers = routes.map(makeRouteMatcher);
|
|
556
|
+
}
|
|
557
|
+
get #currentRouteHash() {
|
|
558
|
+
const hash = document.location.hash;
|
|
559
|
+
if (hash === '') {
|
|
560
|
+
return '/'
|
|
561
|
+
}
|
|
562
|
+
return hash.slice(1)
|
|
563
|
+
}
|
|
564
|
+
async init() {
|
|
565
|
+
if (this.#isInitialized) {
|
|
566
|
+
return
|
|
567
|
+
}
|
|
568
|
+
this.#isInitialized = true;
|
|
569
|
+
if (document.location.hash === '') {
|
|
570
|
+
window.history.replaceState({}, '', '#/');
|
|
571
|
+
}
|
|
572
|
+
window.addEventListener('popstate', this.#onPopState);
|
|
573
|
+
}
|
|
574
|
+
destroy() {
|
|
575
|
+
if (!this.#isInitialized) {
|
|
576
|
+
return
|
|
577
|
+
}
|
|
578
|
+
window.removeEventListener('popstate', this.#onPopState);
|
|
579
|
+
Array.from(this.#subscriberFns).forEach(this.unsubscribe, this);
|
|
580
|
+
this.#isInitialized = false;
|
|
581
|
+
}
|
|
582
|
+
#matchCurrentRoute() {
|
|
583
|
+
return this.navigateTo(this.#currentRouteHash)
|
|
584
|
+
}
|
|
585
|
+
async navigateTo(path) {
|
|
586
|
+
const matcher = this.#matchers.find((matcher) =>
|
|
587
|
+
matcher.checkMatch(path)
|
|
588
|
+
);
|
|
589
|
+
if (matcher == null) {
|
|
590
|
+
console.warn(`[Router] No route matches path "${path}"`);
|
|
591
|
+
this.#matchedRoute = null;
|
|
592
|
+
this.#params = {};
|
|
593
|
+
this.#query = {};
|
|
594
|
+
return
|
|
595
|
+
}
|
|
596
|
+
if (matcher.isRedirect) {
|
|
597
|
+
return this.navigateTo(matcher.route.redirect)
|
|
598
|
+
}
|
|
599
|
+
const from = this.#matchedRoute;
|
|
600
|
+
const to = matcher.route;
|
|
601
|
+
const { shouldNavigate, shouldRedirect, redirectPath } =
|
|
602
|
+
await this.#canChangeRoute(from, to);
|
|
603
|
+
if (shouldRedirect) {
|
|
604
|
+
return this.navigateTo(redirectPath)
|
|
605
|
+
}
|
|
606
|
+
if (shouldNavigate) {
|
|
607
|
+
this.#matchedRoute = matcher.route;
|
|
608
|
+
this.#params = matcher.extractParams(path);
|
|
609
|
+
this.#query = matcher.extractQuery(path);
|
|
610
|
+
this.#pushState(path);
|
|
611
|
+
this.#dispatcher.dispatch(ROUTER_EVENT, {from, to, router: this});
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
#pushState(path) {
|
|
615
|
+
window.history.pushState({}, '', `#${path}`);
|
|
616
|
+
}
|
|
617
|
+
back() {
|
|
618
|
+
window.history.back();
|
|
619
|
+
}
|
|
620
|
+
forward() {
|
|
621
|
+
window.history.forward();
|
|
622
|
+
}
|
|
623
|
+
subscribe(handler) {
|
|
624
|
+
const unsubscribe = this.#dispatcher.subscribe(ROUTER_EVENT, handler);
|
|
625
|
+
this.#subscriptions.set(handler, unsubscribe);
|
|
626
|
+
this.#subscriberFns.add(handler);
|
|
627
|
+
}
|
|
628
|
+
unsubscribe(handler) {
|
|
629
|
+
const unsubscribe = this.#subscriptions.get(handler);
|
|
630
|
+
if (unsubscribe) {
|
|
631
|
+
unsubscribe();
|
|
632
|
+
this.#subscriptions.delete(handler);
|
|
633
|
+
this.#subscriberFns.delete(handler);
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
async #canChangeRoute(from, to) {
|
|
637
|
+
const guard = to.beforeEnter;
|
|
638
|
+
if (typeof guard !== 'function') {
|
|
639
|
+
return {
|
|
640
|
+
shouldRedirect : false,
|
|
641
|
+
shouldNavigate : true,
|
|
642
|
+
redirectPath : null,
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
const result = await guard(from?.path, to?.path);
|
|
646
|
+
if (result === false) {
|
|
647
|
+
return {
|
|
648
|
+
shouldRedirect : false,
|
|
649
|
+
shouldNavigate : false,
|
|
650
|
+
redirectPath: null,
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
if (typeof result === 'string') {
|
|
654
|
+
return {
|
|
655
|
+
shouldRedirect : true,
|
|
656
|
+
shouldNavigate : true,
|
|
657
|
+
redirectPath: result,
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
return {
|
|
661
|
+
shouldRedirect : false,
|
|
662
|
+
shouldNavigate : true,
|
|
663
|
+
redirectPath : null,
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
class NoopRouter {
|
|
668
|
+
init() {}
|
|
669
|
+
destroy() {}
|
|
670
|
+
navigateTo() {}
|
|
671
|
+
back() {}
|
|
672
|
+
forward() {}
|
|
673
|
+
subscribe() {}
|
|
674
|
+
unsubscribe() {}
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
function createApp(RootComponent, props = {}, options = {}) {
|
|
274
678
|
let parentEl = null;
|
|
275
679
|
let isMounted = false;
|
|
276
680
|
let vdom = null;
|
|
681
|
+
const context = {
|
|
682
|
+
router : options.router || new NoopRouter(),
|
|
683
|
+
};
|
|
277
684
|
function reset() {
|
|
278
685
|
parentEl = null;
|
|
279
686
|
isMounted = false;
|
|
@@ -286,7 +693,8 @@ function createApp(RootComponent, props = {}) {
|
|
|
286
693
|
}
|
|
287
694
|
parentEl = _parentEl;
|
|
288
695
|
vdom = h(RootComponent, props);
|
|
289
|
-
mountDom(vdom, parentEl);
|
|
696
|
+
mountDom(vdom, parentEl, null, { appContext : context});
|
|
697
|
+
context.router.init();
|
|
290
698
|
isMounted = true;
|
|
291
699
|
},
|
|
292
700
|
unmount() {
|
|
@@ -294,9 +702,514 @@ function createApp(RootComponent, props = {}) {
|
|
|
294
702
|
throw new Error(`The application is not mounted`)
|
|
295
703
|
}
|
|
296
704
|
destroyDom(vdom);
|
|
705
|
+
context.router.destroy();
|
|
297
706
|
reset();
|
|
298
707
|
}
|
|
299
708
|
}
|
|
300
709
|
}
|
|
301
710
|
|
|
302
|
-
|
|
711
|
+
function areNodesEqual(nodeOne, nodeTwo) {
|
|
712
|
+
if (nodeOne.type !== nodeTwo.type) {
|
|
713
|
+
return false
|
|
714
|
+
}
|
|
715
|
+
if (nodeOne.type === DOM_TYPES.ELEMENT) {
|
|
716
|
+
const {
|
|
717
|
+
tag : tagOne,
|
|
718
|
+
props : { key : keyOne}
|
|
719
|
+
} = nodeOne;
|
|
720
|
+
const {
|
|
721
|
+
tag : tagTwo,
|
|
722
|
+
props : { key : keyTwo}
|
|
723
|
+
} = nodeTwo;
|
|
724
|
+
return tagOne === tagTwo && keyOne === keyTwo
|
|
725
|
+
}
|
|
726
|
+
if (nodeOne.type === DOM_TYPES.COMPONENT) {
|
|
727
|
+
const {
|
|
728
|
+
tag : componentOne,
|
|
729
|
+
props : { key : keyOne},
|
|
730
|
+
} = nodeOne;
|
|
731
|
+
const {
|
|
732
|
+
tag : componentTwo,
|
|
733
|
+
props : {key : keyTwo},
|
|
734
|
+
} = nodeTwo;
|
|
735
|
+
return componentOne === componentTwo && keyOne === keyTwo
|
|
736
|
+
}
|
|
737
|
+
return true
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
function objectsDiff(oldObj, newObj) {
|
|
741
|
+
const oldKeys = Object.keys(oldObj);
|
|
742
|
+
const newKeys = Object.keys(newObj);
|
|
743
|
+
return {
|
|
744
|
+
added : newKeys.filter((key) => !(key in oldObj)),
|
|
745
|
+
removed : oldKeys.filter((key) => !(key in newObj)),
|
|
746
|
+
updated : newKeys.filter(
|
|
747
|
+
(key) => key in oldObj && oldObj[key] !== newObj[key]
|
|
748
|
+
),
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
function hasOwnProperty(obj, prop) {
|
|
752
|
+
return Object.prototype.hasOwnProperty.call(obj, prop)
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
function isNotEmptyString(str) {
|
|
756
|
+
return str !== ''
|
|
757
|
+
}
|
|
758
|
+
function isNotBlankOrEmptyString(str) {
|
|
759
|
+
return isNotEmptyString(str.trim())
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
function patchDOM(oldVdom, newVdom, parentEl, hostComponent = null) {
|
|
763
|
+
if (!areNodesEqual(oldVdom, newVdom)) {
|
|
764
|
+
const index = findIndexInParent(parentEl, oldVdom.el);
|
|
765
|
+
destroyDom(oldVdom);
|
|
766
|
+
mountDom(newVdom, parentEl, index, hostComponent);
|
|
767
|
+
return newVdom
|
|
768
|
+
}
|
|
769
|
+
newVdom.el = oldVdom.el;
|
|
770
|
+
switch (newVdom.type) {
|
|
771
|
+
case DOM_TYPES.TEXT: {
|
|
772
|
+
patchText(oldVdom, newVdom);
|
|
773
|
+
return newVdom
|
|
774
|
+
}
|
|
775
|
+
case DOM_TYPES.ELEMENT: {
|
|
776
|
+
patchElement(oldVdom, newVdom, hostComponent);
|
|
777
|
+
break
|
|
778
|
+
}
|
|
779
|
+
case DOM_TYPES.COMPONENT: {
|
|
780
|
+
patchComponent(oldVdom, newVdom);
|
|
781
|
+
break
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
patchChildren(oldVdom, newVdom, hostComponent);
|
|
785
|
+
return newVdom
|
|
786
|
+
}
|
|
787
|
+
function patchText(oldVdom, newVdom) {
|
|
788
|
+
const el = oldVdom.el;
|
|
789
|
+
const { value : oldText} = oldVdom;
|
|
790
|
+
const { value : newText} = newVdom;
|
|
791
|
+
if (oldText !== newText) {
|
|
792
|
+
el.nodeValue = newText;
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
function findIndexInParent(parentEl, el) {
|
|
796
|
+
const index = Array.from(parentEl.childNodes).indexOf(el);
|
|
797
|
+
if (index < 0) {
|
|
798
|
+
return null
|
|
799
|
+
}
|
|
800
|
+
return index
|
|
801
|
+
}
|
|
802
|
+
function patchElement(oldVdom, newVdom, hostComponent) {
|
|
803
|
+
const el = oldVdom.el;
|
|
804
|
+
const {
|
|
805
|
+
class : oldClass,
|
|
806
|
+
style : oldStyle,
|
|
807
|
+
on: oldEvents,
|
|
808
|
+
...oldAttrs
|
|
809
|
+
} = oldVdom.props;
|
|
810
|
+
const {
|
|
811
|
+
class: newClass,
|
|
812
|
+
style: newStyle,
|
|
813
|
+
on: newEvents,
|
|
814
|
+
...newAttrs
|
|
815
|
+
} = newVdom.props;
|
|
816
|
+
const { listeners: oldListeners } = oldVdom;
|
|
817
|
+
patchAttrs(el, oldAttrs, newAttrs);
|
|
818
|
+
patchClasses(el, oldClass, newClass);
|
|
819
|
+
patchStyles(el, oldStyle, newStyle);
|
|
820
|
+
newVdom.listeners = patchEvents(
|
|
821
|
+
el,
|
|
822
|
+
oldListeners,
|
|
823
|
+
oldEvents,
|
|
824
|
+
newEvents,
|
|
825
|
+
hostComponent
|
|
826
|
+
);
|
|
827
|
+
}
|
|
828
|
+
function patchAttrs(el, oldAttrs, newAttrs) {
|
|
829
|
+
const { added, removed, updated } = objectsDiff(oldAttrs, newAttrs);
|
|
830
|
+
for (const attr of removed) {
|
|
831
|
+
removeAttributeCustom(el, attr);
|
|
832
|
+
}
|
|
833
|
+
for (const attr of added.concat(updated)) {
|
|
834
|
+
setAttribute(el, attr, newAttrs[attr]);
|
|
835
|
+
}
|
|
836
|
+
}
|
|
837
|
+
function patchClasses(el, oldClass, newClass) {
|
|
838
|
+
const oldClasses = toClassList(oldClass);
|
|
839
|
+
const newClasses = toClassList(newClass);
|
|
840
|
+
const {added, removed} =
|
|
841
|
+
arraysDiff(oldClasses, newClasses);
|
|
842
|
+
if (removed.length > 0) {
|
|
843
|
+
el.classList.remove(...removed);
|
|
844
|
+
}
|
|
845
|
+
if (added.length > 0) {
|
|
846
|
+
el.classList.add(...added);
|
|
847
|
+
}
|
|
848
|
+
}
|
|
849
|
+
function toClassList(classes = '') {
|
|
850
|
+
return Array.isArray(classes)
|
|
851
|
+
? classes.filter(isNotBlankOrEmptyString)
|
|
852
|
+
: classes.split(/(\s+)/)
|
|
853
|
+
.filter(isNotBlankOrEmptyString)
|
|
854
|
+
}
|
|
855
|
+
function patchStyles(el, oldStyle = {}, newStyle = {}) {
|
|
856
|
+
const {added, removed, updated } = objectsDiff(oldStyle, newStyle);
|
|
857
|
+
for (const style of removed) {
|
|
858
|
+
removeStyle(el, style);
|
|
859
|
+
}
|
|
860
|
+
for (const style of added.concat(updated)) {
|
|
861
|
+
setStyle(el, style, newStyle[style]);
|
|
862
|
+
}
|
|
863
|
+
}
|
|
864
|
+
function patchEvents(
|
|
865
|
+
el,
|
|
866
|
+
oldListeners = {},
|
|
867
|
+
oldEvents = {},
|
|
868
|
+
newEvents = {},
|
|
869
|
+
hostComponent
|
|
870
|
+
) {
|
|
871
|
+
const { removed, added, updated} =
|
|
872
|
+
objectsDiff(oldEvents, newEvents);
|
|
873
|
+
for (const eventName of removed.concat(updated)) {
|
|
874
|
+
el.removeEventListener(eventName, oldListeners[eventName]);
|
|
875
|
+
}
|
|
876
|
+
const addedListeners = {};
|
|
877
|
+
for (const eventName of added.concat(updated)) {
|
|
878
|
+
const listener = addEventListener(
|
|
879
|
+
eventName,
|
|
880
|
+
newEvents[eventName],
|
|
881
|
+
el,
|
|
882
|
+
hostComponent
|
|
883
|
+
);
|
|
884
|
+
addedListeners[eventName] = listener;
|
|
885
|
+
}
|
|
886
|
+
return addedListeners
|
|
887
|
+
}
|
|
888
|
+
function patchComponent(oldVdom, newVdom) {
|
|
889
|
+
const { component } = oldVdom;
|
|
890
|
+
const { children } = newVdom;
|
|
891
|
+
const { props } = extractPropsAndEvents(newVdom);
|
|
892
|
+
component.setExternalContent(children);
|
|
893
|
+
component.updateProps(props);
|
|
894
|
+
newVdom.component = component;
|
|
895
|
+
newVdom.el = component.firstElement;
|
|
896
|
+
}
|
|
897
|
+
function extractChildren(vdom) {
|
|
898
|
+
if (vdom.children == null) {
|
|
899
|
+
return []
|
|
900
|
+
}
|
|
901
|
+
const children = [];
|
|
902
|
+
for (const child of vdom.children) {
|
|
903
|
+
if (child.type === DOM_TYPES.FRAGMENT) {
|
|
904
|
+
children.push(...extractChildren(child));
|
|
905
|
+
} else {
|
|
906
|
+
children.push(child);
|
|
907
|
+
}
|
|
908
|
+
}
|
|
909
|
+
return children
|
|
910
|
+
}
|
|
911
|
+
function patchChildren(oldVdom, newVdom, hostComponent) {
|
|
912
|
+
const oldChildren = extractChildren(oldVdom);
|
|
913
|
+
const newChildren = extractChildren(newVdom);
|
|
914
|
+
const parentEl = oldVdom.el;
|
|
915
|
+
const diffSeq = arraysDiffSequence(oldChildren, newChildren, areNodesEqual);
|
|
916
|
+
for (const operation of diffSeq) {
|
|
917
|
+
const { originalIndex, index, item} = operation;
|
|
918
|
+
const offset = hostComponent?.offset ?? 0;
|
|
919
|
+
switch (operation.op) {
|
|
920
|
+
case ARRAY_DIFF_OP.ADD: {
|
|
921
|
+
mountDom(item, parentEl, index + offset, hostComponent);
|
|
922
|
+
break
|
|
923
|
+
}
|
|
924
|
+
case ARRAY_DIFF_OP.REMOVE: {
|
|
925
|
+
destroyDom(item);
|
|
926
|
+
break
|
|
927
|
+
}
|
|
928
|
+
case ARRAY_DIFF_OP.MOVE: {
|
|
929
|
+
const oldChild = oldChildren[originalIndex];
|
|
930
|
+
const newChild = newChildren[index];
|
|
931
|
+
const el = oldChild.el;
|
|
932
|
+
const elAtTargetIndex = parentEl.childNodes[index + offset];
|
|
933
|
+
parentEl.insertBefore(el, elAtTargetIndex);
|
|
934
|
+
patchDOM(oldChildren[originalIndex], newChild, parentEl, hostComponent);
|
|
935
|
+
break
|
|
936
|
+
}
|
|
937
|
+
case ARRAY_DIFF_OP.NOOP : {
|
|
938
|
+
patchDOM(oldChildren[originalIndex], newChildren[index], parentEl, hostComponent);
|
|
939
|
+
break
|
|
940
|
+
}
|
|
941
|
+
}
|
|
942
|
+
}
|
|
943
|
+
}
|
|
944
|
+
|
|
945
|
+
function getDefaultExportFromCjs (x) {
|
|
946
|
+
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
|
|
947
|
+
}
|
|
948
|
+
|
|
949
|
+
var fastDeepEqual;
|
|
950
|
+
var hasRequiredFastDeepEqual;
|
|
951
|
+
function requireFastDeepEqual () {
|
|
952
|
+
if (hasRequiredFastDeepEqual) return fastDeepEqual;
|
|
953
|
+
hasRequiredFastDeepEqual = 1;
|
|
954
|
+
fastDeepEqual = function equal(a, b) {
|
|
955
|
+
if (a === b) return true;
|
|
956
|
+
if (a && b && typeof a == 'object' && typeof b == 'object') {
|
|
957
|
+
if (a.constructor !== b.constructor) return false;
|
|
958
|
+
var length, i, keys;
|
|
959
|
+
if (Array.isArray(a)) {
|
|
960
|
+
length = a.length;
|
|
961
|
+
if (length != b.length) return false;
|
|
962
|
+
for (i = length; i-- !== 0;)
|
|
963
|
+
if (!equal(a[i], b[i])) return false;
|
|
964
|
+
return true;
|
|
965
|
+
}
|
|
966
|
+
if (a.constructor === RegExp) return a.source === b.source && a.flags === b.flags;
|
|
967
|
+
if (a.valueOf !== Object.prototype.valueOf) return a.valueOf() === b.valueOf();
|
|
968
|
+
if (a.toString !== Object.prototype.toString) return a.toString() === b.toString();
|
|
969
|
+
keys = Object.keys(a);
|
|
970
|
+
length = keys.length;
|
|
971
|
+
if (length !== Object.keys(b).length) return false;
|
|
972
|
+
for (i = length; i-- !== 0;)
|
|
973
|
+
if (!Object.prototype.hasOwnProperty.call(b, keys[i])) return false;
|
|
974
|
+
for (i = length; i-- !== 0;) {
|
|
975
|
+
var key = keys[i];
|
|
976
|
+
if (!equal(a[key], b[key])) return false;
|
|
977
|
+
}
|
|
978
|
+
return true;
|
|
979
|
+
}
|
|
980
|
+
return a!==a && b!==b;
|
|
981
|
+
};
|
|
982
|
+
return fastDeepEqual;
|
|
983
|
+
}
|
|
984
|
+
|
|
985
|
+
var fastDeepEqualExports = requireFastDeepEqual();
|
|
986
|
+
var equal = /*@__PURE__*/getDefaultExportFromCjs(fastDeepEqualExports);
|
|
987
|
+
|
|
988
|
+
function traverseDFS(
|
|
989
|
+
vdom,
|
|
990
|
+
processNode,
|
|
991
|
+
shouldSkipBranch = () => false,
|
|
992
|
+
parentNode,
|
|
993
|
+
index = null
|
|
994
|
+
) {
|
|
995
|
+
if (shouldSkipBranch(vdom)) return
|
|
996
|
+
processNode(vdom, parentNode, index);
|
|
997
|
+
if (vdom.children) {
|
|
998
|
+
vdom.children.forEach((child, i) =>
|
|
999
|
+
traverseDFS(child, processNode, shouldSkipBranch, vdom, i)
|
|
1000
|
+
);
|
|
1001
|
+
}
|
|
1002
|
+
}
|
|
1003
|
+
|
|
1004
|
+
function fillSlots(vdom, externalContent = []) {
|
|
1005
|
+
function processNode(node, parent, index) {
|
|
1006
|
+
insertViewInSlot(node, parent, index, externalContent);
|
|
1007
|
+
}
|
|
1008
|
+
traverseDFS(vdom, processNode, shouldSkipBranch);
|
|
1009
|
+
}
|
|
1010
|
+
function insertViewInSlot(node, parent, index, externalContent) {
|
|
1011
|
+
if (node.type !== DOM_TYPES.SLOT) return
|
|
1012
|
+
const defaultContent = node.children;
|
|
1013
|
+
const views = externalContent.length > 0 ? externalContent : defaultContent;
|
|
1014
|
+
const hasContent = views.length > 0;
|
|
1015
|
+
if (hasContent) {
|
|
1016
|
+
parent.children.splice(index, 1, hFragment(views));
|
|
1017
|
+
} else {
|
|
1018
|
+
parent.children(index, 1);
|
|
1019
|
+
}
|
|
1020
|
+
}
|
|
1021
|
+
function shouldSkipBranch(node) {
|
|
1022
|
+
return node.type === DOM_TYPES.COMPONENT
|
|
1023
|
+
}
|
|
1024
|
+
|
|
1025
|
+
const emptyFn = () => {};
|
|
1026
|
+
function defineComponent({
|
|
1027
|
+
render,
|
|
1028
|
+
state,
|
|
1029
|
+
onMounted = emptyFn,
|
|
1030
|
+
onUnmounted = emptyFn,
|
|
1031
|
+
...methods
|
|
1032
|
+
}) {
|
|
1033
|
+
class Component {
|
|
1034
|
+
#isMounted = false
|
|
1035
|
+
#vdom = null
|
|
1036
|
+
#hostEl = null
|
|
1037
|
+
#eventHandlers = null
|
|
1038
|
+
#parentComponent = null
|
|
1039
|
+
#dispatcher = new Dispatcher()
|
|
1040
|
+
#subscriptions = []
|
|
1041
|
+
#appContext = null
|
|
1042
|
+
#children = []
|
|
1043
|
+
setExternalContent(children) {
|
|
1044
|
+
this.#children = children;
|
|
1045
|
+
}
|
|
1046
|
+
constructor(
|
|
1047
|
+
props = {},
|
|
1048
|
+
eventHandlers = {},
|
|
1049
|
+
parentComponent = null
|
|
1050
|
+
) {
|
|
1051
|
+
this.props = props;
|
|
1052
|
+
this.state = state ? state(props) : {};
|
|
1053
|
+
this.#eventHandlers = eventHandlers;
|
|
1054
|
+
this.#parentComponent = parentComponent;
|
|
1055
|
+
}
|
|
1056
|
+
onMounted() {
|
|
1057
|
+
return Promise.resolve(onMounted.call(this))
|
|
1058
|
+
}
|
|
1059
|
+
onUnMounted() {
|
|
1060
|
+
return Promise.resolve(onUnmounted.call(this))
|
|
1061
|
+
}
|
|
1062
|
+
setAppContext(appContext) {
|
|
1063
|
+
this.#appContext = appContext;
|
|
1064
|
+
}
|
|
1065
|
+
get appContext() {
|
|
1066
|
+
return this.#appContext
|
|
1067
|
+
}
|
|
1068
|
+
get elements() {
|
|
1069
|
+
if (this.#vdom == null) {
|
|
1070
|
+
return []
|
|
1071
|
+
}
|
|
1072
|
+
if (this.#vdom.type === DOM_TYPES.FRAGMENT) {
|
|
1073
|
+
return extractChildren(this.#vdom).flatMap((child) => {
|
|
1074
|
+
if (child.type === DOM_TYPES.COMPONENT) ;
|
|
1075
|
+
return [child.el]
|
|
1076
|
+
})
|
|
1077
|
+
}
|
|
1078
|
+
return [this.#vdom.el]
|
|
1079
|
+
}
|
|
1080
|
+
get firstElement() {
|
|
1081
|
+
return this.elements[0]
|
|
1082
|
+
}
|
|
1083
|
+
get offset() {
|
|
1084
|
+
if (this.#vdom.type === DOM_TYPES.ELEMENT) {
|
|
1085
|
+
return Array.from(this.#hostEl.children).indexOf(this.firstElement)
|
|
1086
|
+
}
|
|
1087
|
+
return 0
|
|
1088
|
+
}
|
|
1089
|
+
emit(eventName, payload) {
|
|
1090
|
+
this.#dispatcher.dispatch(eventName, payload);
|
|
1091
|
+
}
|
|
1092
|
+
updateProps(props) {
|
|
1093
|
+
//! creates a new props object by merging the old and new props
|
|
1094
|
+
const newProps = { ...this.props, ...props};
|
|
1095
|
+
if (equal(this.props, newProps)) {
|
|
1096
|
+
return
|
|
1097
|
+
}
|
|
1098
|
+
this.props = newProps;
|
|
1099
|
+
this.#patch();
|
|
1100
|
+
}
|
|
1101
|
+
updateState(state) {
|
|
1102
|
+
this.state = { ...this.state, ...state};
|
|
1103
|
+
this.#patch();
|
|
1104
|
+
}
|
|
1105
|
+
render() {
|
|
1106
|
+
const vdom = render.call(this);
|
|
1107
|
+
if (didCreateSlot()) {
|
|
1108
|
+
fillSlots(vdom, this.#children);
|
|
1109
|
+
resetDidCreateSlot();
|
|
1110
|
+
}
|
|
1111
|
+
return vdom
|
|
1112
|
+
}
|
|
1113
|
+
mount(hostEl, index = null) {
|
|
1114
|
+
if (this.#isMounted) {
|
|
1115
|
+
throw new Error('Component is already mounted')
|
|
1116
|
+
}
|
|
1117
|
+
this.#vdom = this.render();
|
|
1118
|
+
mountDom(this.#vdom, hostEl, index, this); //!this - passes the component reference to the mountDOM fucntion
|
|
1119
|
+
this.#wireEventHandlers();
|
|
1120
|
+
this.#hostEl = hostEl;
|
|
1121
|
+
this.#isMounted = true;
|
|
1122
|
+
}
|
|
1123
|
+
#patch() {
|
|
1124
|
+
if (!this.#isMounted) {
|
|
1125
|
+
throw new Error('Component is not mounted')
|
|
1126
|
+
}
|
|
1127
|
+
const vdom = this.render();
|
|
1128
|
+
this.#vdom = patchDOM(this.#vdom, vdom, this.#hostEl, this);
|
|
1129
|
+
}
|
|
1130
|
+
unmount() {
|
|
1131
|
+
if (!this.#isMounted) {
|
|
1132
|
+
throw new Error(`Component is not mounted`)
|
|
1133
|
+
}
|
|
1134
|
+
destroyDom(this.#vdom);
|
|
1135
|
+
this.#subscriptions.forEach((unsubscribe) => unsubscribe());
|
|
1136
|
+
this.#vdom = null;
|
|
1137
|
+
this.#hostEl = null;
|
|
1138
|
+
this.#isMounted = false;
|
|
1139
|
+
this.#subscriptions = [];
|
|
1140
|
+
}
|
|
1141
|
+
#wireEventHandlers() {
|
|
1142
|
+
this.#subscriptions = Object.entries(this.#eventHandlers).map(
|
|
1143
|
+
([eventName, handler]) => {
|
|
1144
|
+
this.#wireEventHandlers(eventName, handler);
|
|
1145
|
+
}
|
|
1146
|
+
);
|
|
1147
|
+
}
|
|
1148
|
+
#wireEventHandler(eventName, handler) {
|
|
1149
|
+
return this.#dispatcher.subscribe(eventName, (payload) => {
|
|
1150
|
+
if (this.#parentComponent) {
|
|
1151
|
+
handler.call(this.#parentComponent, payload);
|
|
1152
|
+
} else {
|
|
1153
|
+
handler(payload);
|
|
1154
|
+
}
|
|
1155
|
+
})
|
|
1156
|
+
}
|
|
1157
|
+
}
|
|
1158
|
+
for (const methodName in methods) {
|
|
1159
|
+
if (hasOwnProperty(Component, methodName)) {
|
|
1160
|
+
throw new Error(
|
|
1161
|
+
`Method "${methodName}()" already exists in the component.`
|
|
1162
|
+
)
|
|
1163
|
+
}
|
|
1164
|
+
Component.prototype[methodName] = methods[methodName];
|
|
1165
|
+
}
|
|
1166
|
+
return Component;
|
|
1167
|
+
}
|
|
1168
|
+
|
|
1169
|
+
const RouterLink = defineComponent({
|
|
1170
|
+
render() {
|
|
1171
|
+
const { to } = this.props;
|
|
1172
|
+
return h(
|
|
1173
|
+
'a',
|
|
1174
|
+
{
|
|
1175
|
+
href : to,
|
|
1176
|
+
on : {
|
|
1177
|
+
click : (e) => {
|
|
1178
|
+
e.preventDefault();
|
|
1179
|
+
this.appContext.router.navigateTo(to);
|
|
1180
|
+
},
|
|
1181
|
+
},
|
|
1182
|
+
},
|
|
1183
|
+
[hSlot()]
|
|
1184
|
+
)
|
|
1185
|
+
},
|
|
1186
|
+
});
|
|
1187
|
+
const RouterOutlet = defineComponent({
|
|
1188
|
+
state() {
|
|
1189
|
+
return {
|
|
1190
|
+
matchedRoute: null,
|
|
1191
|
+
subscription : null,
|
|
1192
|
+
}
|
|
1193
|
+
},
|
|
1194
|
+
onMounted() {
|
|
1195
|
+
const subscription = this.appContext.router.subscribe(({ to }) => {
|
|
1196
|
+
this.handleRouteChange(to);
|
|
1197
|
+
});
|
|
1198
|
+
this.updateState({ subscription });
|
|
1199
|
+
},
|
|
1200
|
+
onUnmounted() {
|
|
1201
|
+
const { subscription } = this.state();
|
|
1202
|
+
this.appContext.router.unsubscribe(subscription);
|
|
1203
|
+
},
|
|
1204
|
+
handleRouteChange(matchedRoute) {
|
|
1205
|
+
this.updateState({ matchedRoute});
|
|
1206
|
+
},
|
|
1207
|
+
render() {
|
|
1208
|
+
const { matchedRoute } = this.state;
|
|
1209
|
+
return h('div', {id : 'router-outlet'}, [
|
|
1210
|
+
matchedRoute ? h(matchedRoute.component) : null,
|
|
1211
|
+
])
|
|
1212
|
+
}
|
|
1213
|
+
});
|
|
1214
|
+
|
|
1215
|
+
export { DOM_TYPES, HashRouter, RouterLink, RouterOutlet, createApp, defineComponent, h, hFragment, hSlot, hString, nextTick };
|