@geektech/tsone 0.0.2 → 0.1.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/README-zh.md +405 -0
- package/README.md +199 -52
- package/dist/core/animation/TransitionGroup.d.ts +7 -0
- package/dist/core/animation/index.d.ts +2 -0
- package/dist/core/animation/list-animation-controller.d.ts +16 -0
- package/dist/core/animation/transition-group-strategy.d.ts +15 -0
- package/dist/core/animation/types.d.ts +25 -0
- package/dist/core/app.d.ts +25 -8
- package/dist/core/index.d.ts +1 -0
- package/dist/core/renderer/element-strategy.d.ts +25 -0
- package/dist/core/renderer.d.ts +2 -21
- package/dist/core/vnode.d.ts +36 -0
- package/dist/{index-ycmc7ga1.js → index-wv9gyjqt.js} +628 -334
- package/dist/index-wv9gyjqt.js.map +25 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +258 -105
- package/dist/index.js.map +6 -5
- package/dist/router/index.js +1 -1
- package/package.json +2 -2
- package/dist/index-ycmc7ga1.js.map +0 -21
|
@@ -345,38 +345,100 @@ function isReadonly(value) {
|
|
|
345
345
|
return isObject(value) && hasReactiveFlag(value, IS_READONLY);
|
|
346
346
|
}
|
|
347
347
|
|
|
348
|
-
// lib/core/
|
|
349
|
-
function
|
|
350
|
-
return
|
|
348
|
+
// lib/core/vnode.ts
|
|
349
|
+
function isComponentNode(vnode) {
|
|
350
|
+
return typeof vnode === "object" && vnode !== null && "component" in vnode;
|
|
351
351
|
}
|
|
352
|
-
function
|
|
353
|
-
return
|
|
352
|
+
function isHTMLNode(vnode) {
|
|
353
|
+
return typeof vnode === "object" && vnode !== null && "tag" in vnode && vnode.tag !== "slot";
|
|
354
354
|
}
|
|
355
|
-
function
|
|
356
|
-
|
|
357
|
-
return { eventName, modifiers: new Set(modifiers) };
|
|
355
|
+
function isSlotProvider(vnode) {
|
|
356
|
+
return typeof vnode === "object" && vnode !== null && "tag" in vnode && vnode.tag === "slot";
|
|
358
357
|
}
|
|
359
|
-
function
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
if (modifiers.has("self") && event.currentTarget !== event.target) {
|
|
368
|
-
return;
|
|
369
|
-
}
|
|
370
|
-
if (modifiers.has("once")) {
|
|
371
|
-
event.currentTarget.removeEventListener(event.type, eventHandler);
|
|
372
|
-
}
|
|
373
|
-
handler(event);
|
|
358
|
+
function h(tag, props, children, listeners, key, directions) {
|
|
359
|
+
return {
|
|
360
|
+
tag,
|
|
361
|
+
props,
|
|
362
|
+
children,
|
|
363
|
+
listeners,
|
|
364
|
+
key,
|
|
365
|
+
directions
|
|
374
366
|
};
|
|
375
|
-
return eventHandler;
|
|
376
367
|
}
|
|
377
|
-
function
|
|
378
|
-
|
|
379
|
-
|
|
368
|
+
function Tag(tag, options = {}) {
|
|
369
|
+
return {
|
|
370
|
+
tag,
|
|
371
|
+
...options
|
|
372
|
+
};
|
|
373
|
+
}
|
|
374
|
+
function createElementFactory(tag) {
|
|
375
|
+
return (options = {}) => Tag(tag, options);
|
|
376
|
+
}
|
|
377
|
+
var Div = createElementFactory("div");
|
|
378
|
+
var Span = createElementFactory("span");
|
|
379
|
+
var P = createElementFactory("p");
|
|
380
|
+
var Button = createElementFactory("button");
|
|
381
|
+
var Input = createElementFactory("input");
|
|
382
|
+
var Section = createElementFactory("section");
|
|
383
|
+
var Main = createElementFactory("main");
|
|
384
|
+
var Header = createElementFactory("header");
|
|
385
|
+
var Footer = createElementFactory("footer");
|
|
386
|
+
var Nav = createElementFactory("nav");
|
|
387
|
+
var Article = createElementFactory("article");
|
|
388
|
+
var Aside = createElementFactory("aside");
|
|
389
|
+
var H1 = createElementFactory("h1");
|
|
390
|
+
var H2 = createElementFactory("h2");
|
|
391
|
+
var H3 = createElementFactory("h3");
|
|
392
|
+
var H4 = createElementFactory("h4");
|
|
393
|
+
var H5 = createElementFactory("h5");
|
|
394
|
+
var H6 = createElementFactory("h6");
|
|
395
|
+
var Strong = createElementFactory("strong");
|
|
396
|
+
var Em = createElementFactory("em");
|
|
397
|
+
var Small = createElementFactory("small");
|
|
398
|
+
var Pre = createElementFactory("pre");
|
|
399
|
+
var Code = createElementFactory("code");
|
|
400
|
+
var Blockquote = createElementFactory("blockquote");
|
|
401
|
+
var Ul = createElementFactory("ul");
|
|
402
|
+
var Ol = createElementFactory("ol");
|
|
403
|
+
var Li = createElementFactory("li");
|
|
404
|
+
var A = createElementFactory("a");
|
|
405
|
+
var Img = createElementFactory("img");
|
|
406
|
+
var Form = createElementFactory("form");
|
|
407
|
+
var Label = createElementFactory("label");
|
|
408
|
+
var Textarea = createElementFactory("textarea");
|
|
409
|
+
var Select = createElementFactory("select");
|
|
410
|
+
var Option = createElementFactory("option");
|
|
411
|
+
var Table = createElementFactory("table");
|
|
412
|
+
var Thead = createElementFactory("thead");
|
|
413
|
+
var Tbody = createElementFactory("tbody");
|
|
414
|
+
var Tr = createElementFactory("tr");
|
|
415
|
+
var Th = createElementFactory("th");
|
|
416
|
+
var Td = createElementFactory("td");
|
|
417
|
+
function createComponent(componentClass, props, children, key, directions) {
|
|
418
|
+
return {
|
|
419
|
+
component: componentClass,
|
|
420
|
+
props,
|
|
421
|
+
children,
|
|
422
|
+
key,
|
|
423
|
+
directions
|
|
424
|
+
};
|
|
425
|
+
}
|
|
426
|
+
function slot(name, key, directions) {
|
|
427
|
+
return {
|
|
428
|
+
tag: "slot",
|
|
429
|
+
props: { name },
|
|
430
|
+
key,
|
|
431
|
+
directions
|
|
432
|
+
};
|
|
433
|
+
}
|
|
434
|
+
function each(items, render, key) {
|
|
435
|
+
return items.map((item, index) => {
|
|
436
|
+
const vnode = render(item, index);
|
|
437
|
+
if (typeof vnode === "string") {
|
|
438
|
+
throw new Error("each render callback must return a VNode");
|
|
439
|
+
}
|
|
440
|
+
return { ...vnode, key: key(item, index) };
|
|
441
|
+
});
|
|
380
442
|
}
|
|
381
443
|
|
|
382
444
|
// lib/core/model.ts
|
|
@@ -560,63 +622,551 @@ class ModelBindingController {
|
|
|
560
622
|
}
|
|
561
623
|
}
|
|
562
624
|
|
|
563
|
-
// lib/core/
|
|
564
|
-
function
|
|
565
|
-
return
|
|
566
|
-
}
|
|
567
|
-
function isHTMLNode(vnode) {
|
|
568
|
-
return typeof vnode === "object" && vnode !== null && "tag" in vnode && vnode.tag !== "slot";
|
|
569
|
-
}
|
|
570
|
-
function isSlotProvider(vnode) {
|
|
571
|
-
return typeof vnode === "object" && vnode !== null && "tag" in vnode && vnode.tag === "slot";
|
|
625
|
+
// lib/core/renderer/props.ts
|
|
626
|
+
function isEventProp(key) {
|
|
627
|
+
return /^on[A-Z]/.test(key) || /^on[a-z]/.test(key);
|
|
572
628
|
}
|
|
573
|
-
function
|
|
574
|
-
return
|
|
575
|
-
tag,
|
|
576
|
-
props,
|
|
577
|
-
children,
|
|
578
|
-
listeners,
|
|
579
|
-
key,
|
|
580
|
-
directions
|
|
581
|
-
};
|
|
629
|
+
function eventNameFromProp(key) {
|
|
630
|
+
return key.slice(2).toLowerCase();
|
|
582
631
|
}
|
|
583
|
-
function
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
...options
|
|
587
|
-
});
|
|
632
|
+
function parseEventName(event) {
|
|
633
|
+
const [eventName, ...modifiers] = event.split(".");
|
|
634
|
+
return { eventName, modifiers: new Set(modifiers) };
|
|
588
635
|
}
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
636
|
+
function wrapEventHandler(handler, modifiers) {
|
|
637
|
+
const eventHandler = (event) => {
|
|
638
|
+
if (modifiers.has("stop")) {
|
|
639
|
+
event.stopPropagation();
|
|
640
|
+
}
|
|
641
|
+
if (modifiers.has("prevent")) {
|
|
642
|
+
event.preventDefault();
|
|
643
|
+
}
|
|
644
|
+
if (modifiers.has("self") && event.currentTarget !== event.target) {
|
|
645
|
+
return;
|
|
646
|
+
}
|
|
647
|
+
if (modifiers.has("once")) {
|
|
648
|
+
event.currentTarget.removeEventListener(event.type, eventHandler);
|
|
649
|
+
}
|
|
650
|
+
handler(event);
|
|
601
651
|
};
|
|
652
|
+
return eventHandler;
|
|
602
653
|
}
|
|
603
|
-
function
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
props: { name },
|
|
607
|
-
key,
|
|
608
|
-
directions
|
|
609
|
-
};
|
|
654
|
+
function setStyleValue(style, property, value) {
|
|
655
|
+
const cssProperty = property.includes("-") ? property : property.replace(/[A-Z]/g, (match) => `-${match.toLowerCase()}`);
|
|
656
|
+
style.setProperty(cssProperty, String(value));
|
|
610
657
|
}
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
658
|
+
|
|
659
|
+
// lib/core/renderer/element-strategy.ts
|
|
660
|
+
class ElementRenderStrategy {
|
|
661
|
+
listeners = new WeakMap;
|
|
662
|
+
effects = new WeakMap;
|
|
663
|
+
modelBindings = new ModelBindingController;
|
|
664
|
+
matches(vnode) {
|
|
665
|
+
return typeof vnode === "object" && vnode !== null && isHTMLNode(vnode);
|
|
666
|
+
}
|
|
667
|
+
mount(vnode, context) {
|
|
668
|
+
if (vnode.directions?.if === false) {
|
|
669
|
+
return document.createComment("if");
|
|
670
|
+
}
|
|
671
|
+
const element = document.createElement(vnode.tag);
|
|
672
|
+
this.applyProps(element, {}, vnode.props ?? {}, context);
|
|
673
|
+
this.updateListeners(element, {}, this.collectListeners(vnode));
|
|
674
|
+
this.mountChildren(element, vnode, context);
|
|
675
|
+
this.applyDirections(element, undefined, vnode.directions, context);
|
|
676
|
+
return element;
|
|
677
|
+
}
|
|
678
|
+
patch(oldVNode, newVNode, currentNode, context) {
|
|
679
|
+
if (oldVNode.tag !== newVNode.tag || currentNode.nodeType === Node.COMMENT_NODE) {
|
|
680
|
+
const nextNode = this.mount(newVNode, context);
|
|
681
|
+
currentNode.parentNode?.replaceChild(nextNode, currentNode);
|
|
682
|
+
this.unmount(oldVNode, currentNode, context);
|
|
683
|
+
return nextNode;
|
|
684
|
+
}
|
|
685
|
+
if (!(currentNode instanceof HTMLElement)) {
|
|
686
|
+
return currentNode;
|
|
687
|
+
}
|
|
688
|
+
if (newVNode.directions?.if === false) {
|
|
689
|
+
const nextNode = document.createComment("if");
|
|
690
|
+
currentNode.parentNode?.replaceChild(nextNode, currentNode);
|
|
691
|
+
this.unmount(oldVNode, currentNode, context);
|
|
692
|
+
return nextNode;
|
|
693
|
+
}
|
|
694
|
+
this.applyProps(currentNode, oldVNode.props ?? {}, newVNode.props ?? {}, context);
|
|
695
|
+
this.updateListeners(currentNode, this.collectListeners(oldVNode), this.collectListeners(newVNode));
|
|
696
|
+
this.updateChildren(currentNode, oldVNode, newVNode, context);
|
|
697
|
+
this.applyDirections(currentNode, oldVNode.directions, newVNode.directions, context);
|
|
698
|
+
return currentNode;
|
|
699
|
+
}
|
|
700
|
+
unmount(vnode, currentNode, context) {
|
|
701
|
+
if (!(currentNode instanceof HTMLElement)) {
|
|
702
|
+
return;
|
|
703
|
+
}
|
|
704
|
+
this.effects.get(currentNode)?.forEach((item) => stop(item));
|
|
705
|
+
this.effects.delete(currentNode);
|
|
706
|
+
this.listeners.get(currentNode)?.forEach(({ eventName, listener }) => {
|
|
707
|
+
currentNode.removeEventListener(eventName, listener);
|
|
708
|
+
});
|
|
709
|
+
this.listeners.delete(currentNode);
|
|
710
|
+
this.modelBindings.cleanup(currentNode);
|
|
711
|
+
this.unmountChildren(currentNode, vnode, context);
|
|
712
|
+
}
|
|
713
|
+
mountChildren(element, vnode, context) {
|
|
714
|
+
(vnode.children ?? []).forEach((child) => {
|
|
715
|
+
element.appendChild(context.renderer.mount(child, context));
|
|
716
|
+
});
|
|
717
|
+
}
|
|
718
|
+
updateChildren(element, oldVNode, newVNode, context) {
|
|
719
|
+
this.updateOrdinaryChildren(element, oldVNode.children ?? [], newVNode.children ?? [], context);
|
|
720
|
+
}
|
|
721
|
+
unmountChildren(element, vnode, context) {
|
|
722
|
+
(vnode.children ?? []).forEach((child, index) => {
|
|
723
|
+
const childNode = element.childNodes[index];
|
|
724
|
+
if (childNode) {
|
|
725
|
+
context.renderer.unmount(child, childNode, context);
|
|
726
|
+
}
|
|
727
|
+
});
|
|
728
|
+
}
|
|
729
|
+
applyProps(element, oldProps, newProps, context) {
|
|
730
|
+
Object.keys(oldProps).forEach((key) => {
|
|
731
|
+
if (isEventProp(key) || key in newProps) {
|
|
732
|
+
return;
|
|
733
|
+
}
|
|
734
|
+
if (key === "className" || key === "class") {
|
|
735
|
+
element.removeAttribute("class");
|
|
736
|
+
} else if (key === "style") {
|
|
737
|
+
element.removeAttribute("style");
|
|
738
|
+
} else {
|
|
739
|
+
element.removeAttribute(key);
|
|
740
|
+
}
|
|
741
|
+
});
|
|
742
|
+
Object.entries(newProps).forEach(([key, value]) => {
|
|
743
|
+
if (isEventProp(key)) {
|
|
744
|
+
return;
|
|
745
|
+
}
|
|
746
|
+
if (key === "className" || key === "class") {
|
|
747
|
+
element.className = String(value ?? "");
|
|
748
|
+
return;
|
|
749
|
+
}
|
|
750
|
+
if (key === "style" && typeof value === "object" && value !== null) {
|
|
751
|
+
element.removeAttribute("style");
|
|
752
|
+
Object.entries(value).forEach(([cssKey, cssValue]) => {
|
|
753
|
+
setStyleValue(element.style, cssKey, cssValue);
|
|
754
|
+
});
|
|
755
|
+
return;
|
|
756
|
+
}
|
|
757
|
+
if (value === false || value === undefined || value === null) {
|
|
758
|
+
element.removeAttribute(key);
|
|
759
|
+
return;
|
|
760
|
+
}
|
|
761
|
+
if (value === true) {
|
|
762
|
+
element.setAttribute(key, "");
|
|
763
|
+
return;
|
|
764
|
+
}
|
|
765
|
+
if (typeof value === "string" && context.templateEngine.hasExpressions(value)) {
|
|
766
|
+
this.setupReactiveAttribute(element, key, value, context);
|
|
767
|
+
return;
|
|
768
|
+
}
|
|
769
|
+
element.setAttribute(key, String(value));
|
|
770
|
+
});
|
|
771
|
+
}
|
|
772
|
+
applyDirections(element, oldDirections, newDirections, context) {
|
|
773
|
+
if (newDirections && "show" in newDirections) {
|
|
774
|
+
element.style.display = newDirections.show ? "" : "none";
|
|
775
|
+
} else if (oldDirections && "show" in oldDirections) {
|
|
776
|
+
element.style.display = "";
|
|
777
|
+
}
|
|
778
|
+
if (!newDirections?.model) {
|
|
779
|
+
this.modelBindings.cleanup(element);
|
|
780
|
+
return;
|
|
781
|
+
}
|
|
782
|
+
this.modelBindings.bind(element, newDirections.model, context.templateEngine.state);
|
|
783
|
+
}
|
|
784
|
+
updateOrdinaryChildren(element, oldChildren, newChildren, context) {
|
|
785
|
+
this.assertNoDuplicateKeys(oldChildren);
|
|
786
|
+
this.assertNoDuplicateKeys(newChildren);
|
|
787
|
+
if (this.hasOnlyKeyedChildren(oldChildren, newChildren)) {
|
|
788
|
+
this.updateKeyedChildren(element, oldChildren, newChildren, context);
|
|
789
|
+
return;
|
|
790
|
+
}
|
|
791
|
+
const sharedLength = Math.min(oldChildren.length, newChildren.length);
|
|
792
|
+
for (let index = 0;index < sharedLength; index += 1) {
|
|
793
|
+
const childNode = element.childNodes[index];
|
|
794
|
+
if (!childNode) {
|
|
795
|
+
element.appendChild(context.renderer.mount(newChildren[index], context));
|
|
796
|
+
continue;
|
|
797
|
+
}
|
|
798
|
+
context.renderer.patch(oldChildren[index], newChildren[index], childNode, context);
|
|
799
|
+
}
|
|
800
|
+
for (let index = sharedLength;index < newChildren.length; index += 1) {
|
|
801
|
+
element.appendChild(context.renderer.mount(newChildren[index], context));
|
|
802
|
+
}
|
|
803
|
+
for (let index = oldChildren.length - 1;index >= newChildren.length; index -= 1) {
|
|
804
|
+
const childNode = element.childNodes[index];
|
|
805
|
+
if (childNode) {
|
|
806
|
+
context.renderer.unmount(oldChildren[index], childNode, context);
|
|
807
|
+
if (childNode.parentNode === element) {
|
|
808
|
+
element.removeChild(childNode);
|
|
809
|
+
}
|
|
810
|
+
}
|
|
811
|
+
}
|
|
812
|
+
}
|
|
813
|
+
updateKeyedChildren(element, oldChildren, newChildren, context) {
|
|
814
|
+
const oldEntries = oldChildren.map((vnode, index) => ({
|
|
815
|
+
vnode,
|
|
816
|
+
node: element.childNodes[index],
|
|
817
|
+
index
|
|
818
|
+
}));
|
|
819
|
+
const keyedOldEntries = new Map;
|
|
820
|
+
const usedOldIndexes = new Set;
|
|
821
|
+
oldEntries.forEach((entry) => {
|
|
822
|
+
const key = this.getVNodeKey(entry.vnode);
|
|
823
|
+
if (key !== undefined && entry.node) {
|
|
824
|
+
keyedOldEntries.set(key, {
|
|
825
|
+
vnode: entry.vnode,
|
|
826
|
+
node: entry.node,
|
|
827
|
+
index: entry.index
|
|
828
|
+
});
|
|
829
|
+
}
|
|
830
|
+
});
|
|
831
|
+
newChildren.forEach((newChild, newIndex) => {
|
|
832
|
+
const key = this.getVNodeKey(newChild);
|
|
833
|
+
const oldEntry = key === undefined ? undefined : keyedOldEntries.get(key);
|
|
834
|
+
let nextNode;
|
|
835
|
+
if (oldEntry) {
|
|
836
|
+
nextNode = context.renderer.patch(oldEntry.vnode, newChild, oldEntry.node, context);
|
|
837
|
+
usedOldIndexes.add(oldEntry.index);
|
|
838
|
+
} else {
|
|
839
|
+
nextNode = context.renderer.mount(newChild, context);
|
|
840
|
+
}
|
|
841
|
+
const referenceNode = element.childNodes[newIndex] ?? null;
|
|
842
|
+
if (nextNode !== referenceNode) {
|
|
843
|
+
element.insertBefore(nextNode, referenceNode);
|
|
844
|
+
}
|
|
845
|
+
});
|
|
846
|
+
oldEntries.forEach((entry) => {
|
|
847
|
+
if (!entry.node || usedOldIndexes.has(entry.index)) {
|
|
848
|
+
return;
|
|
849
|
+
}
|
|
850
|
+
context.renderer.unmount(entry.vnode, entry.node, context);
|
|
851
|
+
if (entry.node.parentNode === element) {
|
|
852
|
+
element.removeChild(entry.node);
|
|
853
|
+
}
|
|
854
|
+
});
|
|
855
|
+
}
|
|
856
|
+
hasOnlyKeyedChildren(oldChildren, newChildren) {
|
|
857
|
+
return [...oldChildren, ...newChildren].every((child) => this.getVNodeKey(child) !== undefined);
|
|
858
|
+
}
|
|
859
|
+
assertNoDuplicateKeys(children) {
|
|
860
|
+
const keys = new Set;
|
|
861
|
+
children.forEach((child) => {
|
|
862
|
+
const key = this.getVNodeKey(child);
|
|
863
|
+
if (key === undefined) {
|
|
864
|
+
return;
|
|
865
|
+
}
|
|
866
|
+
if (keys.has(key)) {
|
|
867
|
+
throw new Error(`Duplicate key "${key}"`);
|
|
868
|
+
}
|
|
869
|
+
keys.add(key);
|
|
870
|
+
});
|
|
871
|
+
}
|
|
872
|
+
getVNodeKey(vnode) {
|
|
614
873
|
if (typeof vnode === "string") {
|
|
615
|
-
|
|
874
|
+
return;
|
|
616
875
|
}
|
|
617
|
-
return
|
|
876
|
+
return vnode.key;
|
|
877
|
+
}
|
|
878
|
+
collectListeners(vnode) {
|
|
879
|
+
const listeners = {};
|
|
880
|
+
Object.entries(vnode.props ?? {}).forEach(([key, value]) => {
|
|
881
|
+
if (isEventProp(key) && typeof value === "function") {
|
|
882
|
+
listeners[eventNameFromProp(key)] = value;
|
|
883
|
+
}
|
|
884
|
+
});
|
|
885
|
+
return {
|
|
886
|
+
...listeners,
|
|
887
|
+
...vnode.listeners ?? {}
|
|
888
|
+
};
|
|
889
|
+
}
|
|
890
|
+
updateListeners(element, oldListeners, newListeners) {
|
|
891
|
+
const store = this.listeners.get(element) ?? new Map;
|
|
892
|
+
const oldKeys = new Set(Object.keys(oldListeners));
|
|
893
|
+
const newKeys = new Set(Object.keys(newListeners));
|
|
894
|
+
oldKeys.forEach((event) => {
|
|
895
|
+
if (!newKeys.has(event) || oldListeners[event] !== newListeners[event]) {
|
|
896
|
+
const stored = store.get(event);
|
|
897
|
+
if (stored) {
|
|
898
|
+
element.removeEventListener(stored.eventName, stored.listener);
|
|
899
|
+
store.delete(event);
|
|
900
|
+
}
|
|
901
|
+
}
|
|
902
|
+
});
|
|
903
|
+
newKeys.forEach((event) => {
|
|
904
|
+
if (!oldKeys.has(event) || oldListeners[event] !== newListeners[event]) {
|
|
905
|
+
const { eventName, modifiers } = parseEventName(event);
|
|
906
|
+
const listener = wrapEventHandler(newListeners[event], modifiers);
|
|
907
|
+
element.addEventListener(eventName, listener);
|
|
908
|
+
store.set(event, { eventName, listener });
|
|
909
|
+
}
|
|
910
|
+
});
|
|
911
|
+
this.listeners.set(element, store);
|
|
912
|
+
}
|
|
913
|
+
setupReactiveAttribute(element, attrName, attrValue, context) {
|
|
914
|
+
const effectRef = effect(() => {
|
|
915
|
+
element.setAttribute(attrName, context.templateEngine.evaluateTemplateValue(attrValue));
|
|
916
|
+
});
|
|
917
|
+
this.trackEffect(element, effectRef);
|
|
918
|
+
}
|
|
919
|
+
trackEffect(element, effectRef) {
|
|
920
|
+
const effects = this.effects.get(element) ?? new Set;
|
|
921
|
+
effects.add(effectRef);
|
|
922
|
+
this.effects.set(element, effects);
|
|
923
|
+
}
|
|
924
|
+
}
|
|
925
|
+
|
|
926
|
+
// lib/core/animation/list-animation-controller.ts
|
|
927
|
+
var ENTER_KEYFRAMES = {
|
|
928
|
+
fade: [{ opacity: 0 }, { opacity: 1 }],
|
|
929
|
+
"slide-up": [
|
|
930
|
+
{ opacity: 0, transform: "translateY(12px)" },
|
|
931
|
+
{ opacity: 1, transform: "translateY(0)" }
|
|
932
|
+
],
|
|
933
|
+
"slide-down": [
|
|
934
|
+
{ opacity: 0, transform: "translateY(-12px)" },
|
|
935
|
+
{ opacity: 1, transform: "translateY(0)" }
|
|
936
|
+
],
|
|
937
|
+
"slide-left": [
|
|
938
|
+
{ opacity: 0, transform: "translateX(12px)" },
|
|
939
|
+
{ opacity: 1, transform: "translateX(0)" }
|
|
940
|
+
],
|
|
941
|
+
"slide-right": [
|
|
942
|
+
{ opacity: 0, transform: "translateX(-12px)" },
|
|
943
|
+
{ opacity: 1, transform: "translateX(0)" }
|
|
944
|
+
],
|
|
945
|
+
scale: [
|
|
946
|
+
{ opacity: 0, transform: "scale(0.95)" },
|
|
947
|
+
{ opacity: 1, transform: "scale(1)" }
|
|
948
|
+
]
|
|
949
|
+
};
|
|
950
|
+
|
|
951
|
+
class ListAnimationController {
|
|
952
|
+
runs = new WeakMap;
|
|
953
|
+
playEnter(element, options) {
|
|
954
|
+
return this.play(element, options, "enter");
|
|
955
|
+
}
|
|
956
|
+
playExit(element, options) {
|
|
957
|
+
return this.play(element, options, "exit");
|
|
958
|
+
}
|
|
959
|
+
cancel(element) {
|
|
960
|
+
const current = this.runs.get(element);
|
|
961
|
+
if (!current) {
|
|
962
|
+
return;
|
|
963
|
+
}
|
|
964
|
+
this.runs.delete(element);
|
|
965
|
+
current.animation.cancel();
|
|
966
|
+
}
|
|
967
|
+
play(element, transition, phase) {
|
|
968
|
+
this.cancel(element);
|
|
969
|
+
if (!this.canAnimate(element)) {
|
|
970
|
+
return null;
|
|
971
|
+
}
|
|
972
|
+
const enterKeyframes = ENTER_KEYFRAMES[transition.type];
|
|
973
|
+
const keyframes = phase === "enter" ? [...enterKeyframes] : [...enterKeyframes].reverse();
|
|
974
|
+
const options = {
|
|
975
|
+
duration: transition.duration,
|
|
976
|
+
easing: "ease",
|
|
977
|
+
fill: "both"
|
|
978
|
+
};
|
|
979
|
+
const animation = element.animate(keyframes, options);
|
|
980
|
+
const token = Symbol("list-animation");
|
|
981
|
+
const finished = animation.finished.then(() => "finished", () => "cancelled");
|
|
982
|
+
const run = {
|
|
983
|
+
animation,
|
|
984
|
+
token,
|
|
985
|
+
keyframes,
|
|
986
|
+
options,
|
|
987
|
+
finished
|
|
988
|
+
};
|
|
989
|
+
this.runs.set(element, run);
|
|
990
|
+
finished.then((result) => {
|
|
991
|
+
if (this.runs.get(element)?.token !== token) {
|
|
992
|
+
return;
|
|
993
|
+
}
|
|
994
|
+
this.runs.delete(element);
|
|
995
|
+
if (phase === "enter" && result === "finished") {
|
|
996
|
+
animation.cancel();
|
|
997
|
+
}
|
|
998
|
+
});
|
|
999
|
+
return run;
|
|
1000
|
+
}
|
|
1001
|
+
canAnimate(element) {
|
|
1002
|
+
const reduced = typeof window !== "undefined" && typeof window.matchMedia === "function" && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
1003
|
+
return !reduced && typeof element.animate === "function";
|
|
1004
|
+
}
|
|
1005
|
+
}
|
|
1006
|
+
|
|
1007
|
+
// lib/core/animation/types.ts
|
|
1008
|
+
var TRANSITION_ANIMATION_TYPES = [
|
|
1009
|
+
"fade",
|
|
1010
|
+
"slide-up",
|
|
1011
|
+
"slide-down",
|
|
1012
|
+
"slide-left",
|
|
1013
|
+
"slide-right",
|
|
1014
|
+
"scale"
|
|
1015
|
+
];
|
|
1016
|
+
function normalizeTransitionGroupProps(props) {
|
|
1017
|
+
const tag = (props.tag ?? "div").trim();
|
|
1018
|
+
const type = props.type ?? "fade";
|
|
1019
|
+
const duration = props.duration ?? 300;
|
|
1020
|
+
if (!tag) {
|
|
1021
|
+
throw new Error("TransitionGroup tag must not be empty");
|
|
1022
|
+
}
|
|
1023
|
+
if (!TRANSITION_ANIMATION_TYPES.includes(type)) {
|
|
1024
|
+
throw new Error(`Unknown TransitionGroup animation type "${type}"`);
|
|
1025
|
+
}
|
|
1026
|
+
if (!Number.isFinite(duration) || duration < 0) {
|
|
1027
|
+
throw new Error("TransitionGroup duration must be a non-negative finite number");
|
|
1028
|
+
}
|
|
1029
|
+
return { tag, type, duration };
|
|
1030
|
+
}
|
|
1031
|
+
function validateTransitionGroupChildren(children) {
|
|
1032
|
+
const keys = new Set;
|
|
1033
|
+
return children.map((child) => {
|
|
1034
|
+
if (typeof child === "string" || child.key === undefined || keys.has(child.key)) {
|
|
1035
|
+
throw new Error("TransitionGroup children must have unique keys");
|
|
1036
|
+
}
|
|
1037
|
+
keys.add(child.key);
|
|
1038
|
+
return child;
|
|
618
1039
|
});
|
|
619
1040
|
}
|
|
1041
|
+
function isTransitionGroupNode(vnode) {
|
|
1042
|
+
return typeof vnode === "object" && vnode !== null && "transitionGroup" in vnode && isHTMLNode(vnode);
|
|
1043
|
+
}
|
|
1044
|
+
|
|
1045
|
+
// lib/core/animation/transition-group-strategy.ts
|
|
1046
|
+
class TransitionGroupRenderStrategy extends ElementRenderStrategy {
|
|
1047
|
+
entries = new WeakMap;
|
|
1048
|
+
animations = new ListAnimationController;
|
|
1049
|
+
matches(vnode) {
|
|
1050
|
+
return isTransitionGroupNode(vnode);
|
|
1051
|
+
}
|
|
1052
|
+
mountChildren(element, groupVNode, context) {
|
|
1053
|
+
const keyedChildren = validateTransitionGroupChildren(groupVNode.children ?? []);
|
|
1054
|
+
const entries = new Map;
|
|
1055
|
+
keyedChildren.forEach((childVNode) => {
|
|
1056
|
+
const node = context.renderer.mount(childVNode, context);
|
|
1057
|
+
element.appendChild(node);
|
|
1058
|
+
const entry = {
|
|
1059
|
+
key: childVNode.key,
|
|
1060
|
+
vnode: childVNode,
|
|
1061
|
+
node,
|
|
1062
|
+
status: "active"
|
|
1063
|
+
};
|
|
1064
|
+
entries.set(entry.key, entry);
|
|
1065
|
+
this.playEnter(entry, node, groupVNode.transitionGroup);
|
|
1066
|
+
});
|
|
1067
|
+
this.entries.set(element, entries);
|
|
1068
|
+
}
|
|
1069
|
+
updateChildren(element, _oldVNode, newVNode, context) {
|
|
1070
|
+
const entries = this.entries.get(element) ?? new Map;
|
|
1071
|
+
const nextChildren = validateTransitionGroupChildren(newVNode.children ?? []);
|
|
1072
|
+
const nextKeys = new Set(nextChildren.map((child) => child.key));
|
|
1073
|
+
const ordered = [];
|
|
1074
|
+
nextChildren.forEach((childVNode) => {
|
|
1075
|
+
const key = childVNode.key;
|
|
1076
|
+
const current = entries.get(key);
|
|
1077
|
+
if (current) {
|
|
1078
|
+
const wasExiting = current.status === "exiting";
|
|
1079
|
+
if (wasExiting && current.node instanceof HTMLElement) {
|
|
1080
|
+
this.animations.cancel(current.node);
|
|
1081
|
+
}
|
|
1082
|
+
current.status = "active";
|
|
1083
|
+
current.animationToken = undefined;
|
|
1084
|
+
current.node = context.renderer.patch(current.vnode, childVNode, current.node, context);
|
|
1085
|
+
current.vnode = childVNode;
|
|
1086
|
+
ordered.push(current);
|
|
1087
|
+
if (wasExiting) {
|
|
1088
|
+
this.playEnter(current, current.node, newVNode.transitionGroup);
|
|
1089
|
+
}
|
|
1090
|
+
return;
|
|
1091
|
+
}
|
|
1092
|
+
const node = context.renderer.mount(childVNode, context);
|
|
1093
|
+
const entry = {
|
|
1094
|
+
key,
|
|
1095
|
+
vnode: childVNode,
|
|
1096
|
+
node,
|
|
1097
|
+
status: "active"
|
|
1098
|
+
};
|
|
1099
|
+
entries.set(key, entry);
|
|
1100
|
+
ordered.push(entry);
|
|
1101
|
+
this.playEnter(entry, node, newVNode.transitionGroup);
|
|
1102
|
+
});
|
|
1103
|
+
entries.forEach((entry, key) => {
|
|
1104
|
+
if (nextKeys.has(key) || entry.status !== "active") {
|
|
1105
|
+
return;
|
|
1106
|
+
}
|
|
1107
|
+
this.startExit(element, entry, newVNode.transitionGroup, context);
|
|
1108
|
+
});
|
|
1109
|
+
this.placeActiveEntries(element, ordered);
|
|
1110
|
+
this.entries.set(element, entries);
|
|
1111
|
+
}
|
|
1112
|
+
unmountChildren(element, vnode, context) {
|
|
1113
|
+
const entries = this.entries.get(element);
|
|
1114
|
+
if (!entries) {
|
|
1115
|
+
super.unmountChildren(element, vnode, context);
|
|
1116
|
+
return;
|
|
1117
|
+
}
|
|
1118
|
+
entries.forEach((entry) => {
|
|
1119
|
+
if (entry.node instanceof HTMLElement) {
|
|
1120
|
+
this.animations.cancel(entry.node);
|
|
1121
|
+
}
|
|
1122
|
+
context.renderer.unmount(entry.vnode, entry.node, context);
|
|
1123
|
+
if (entry.node.parentNode === element) {
|
|
1124
|
+
element.removeChild(entry.node);
|
|
1125
|
+
}
|
|
1126
|
+
});
|
|
1127
|
+
entries.clear();
|
|
1128
|
+
this.entries.delete(element);
|
|
1129
|
+
}
|
|
1130
|
+
playEnter(entry, node, options) {
|
|
1131
|
+
if (!(node instanceof HTMLElement)) {
|
|
1132
|
+
return;
|
|
1133
|
+
}
|
|
1134
|
+
const run = this.animations.playEnter(node, options);
|
|
1135
|
+
entry.animationToken = run?.token;
|
|
1136
|
+
}
|
|
1137
|
+
startExit(wrapper, entry, options, context) {
|
|
1138
|
+
entry.status = "exiting";
|
|
1139
|
+
const run = entry.node instanceof HTMLElement ? this.animations.playExit(entry.node, options) : null;
|
|
1140
|
+
if (!run) {
|
|
1141
|
+
this.finishExit(wrapper, entry, context);
|
|
1142
|
+
return;
|
|
1143
|
+
}
|
|
1144
|
+
entry.animationToken = run.token;
|
|
1145
|
+
run.finished.then((result) => {
|
|
1146
|
+
if (result === "finished" && entry.status === "exiting" && entry.animationToken === run.token) {
|
|
1147
|
+
this.finishExit(wrapper, entry, context);
|
|
1148
|
+
}
|
|
1149
|
+
});
|
|
1150
|
+
}
|
|
1151
|
+
finishExit(wrapper, entry, context) {
|
|
1152
|
+
const entries = this.entries.get(wrapper);
|
|
1153
|
+
if (entries?.get(entry.key) !== entry) {
|
|
1154
|
+
return;
|
|
1155
|
+
}
|
|
1156
|
+
context.renderer.unmount(entry.vnode, entry.node, context);
|
|
1157
|
+
if (entry.node.parentNode === wrapper) {
|
|
1158
|
+
wrapper.removeChild(entry.node);
|
|
1159
|
+
}
|
|
1160
|
+
entries.delete(entry.key);
|
|
1161
|
+
}
|
|
1162
|
+
placeActiveEntries(wrapper, ordered) {
|
|
1163
|
+
let reference = null;
|
|
1164
|
+
for (let index = ordered.length - 1;index >= 0; index -= 1) {
|
|
1165
|
+
wrapper.insertBefore(ordered[index].node, reference);
|
|
1166
|
+
reference = ordered[index].node;
|
|
1167
|
+
}
|
|
1168
|
+
}
|
|
1169
|
+
}
|
|
620
1170
|
|
|
621
1171
|
// lib/core/renderer.ts
|
|
622
1172
|
class RendererContext {
|
|
@@ -626,6 +1176,7 @@ class RendererContext {
|
|
|
626
1176
|
new TextRenderStrategy,
|
|
627
1177
|
new ComponentRenderStrategy,
|
|
628
1178
|
new SlotRenderStrategy,
|
|
1179
|
+
new TransitionGroupRenderStrategy,
|
|
629
1180
|
new ElementRenderStrategy
|
|
630
1181
|
];
|
|
631
1182
|
}
|
|
@@ -843,263 +1394,6 @@ class SlotRenderStrategy {
|
|
|
843
1394
|
}
|
|
844
1395
|
}
|
|
845
1396
|
|
|
846
|
-
class ElementRenderStrategy {
|
|
847
|
-
listeners = new WeakMap;
|
|
848
|
-
effects = new WeakMap;
|
|
849
|
-
modelBindings = new ModelBindingController;
|
|
850
|
-
matches(vnode) {
|
|
851
|
-
return typeof vnode === "object" && vnode !== null && isHTMLNode(vnode);
|
|
852
|
-
}
|
|
853
|
-
mount(vnode, context) {
|
|
854
|
-
if (vnode.directions?.if === false) {
|
|
855
|
-
return document.createComment("if");
|
|
856
|
-
}
|
|
857
|
-
const element = document.createElement(vnode.tag);
|
|
858
|
-
this.applyProps(element, {}, vnode.props ?? {}, context);
|
|
859
|
-
this.updateListeners(element, {}, this.collectListeners(vnode));
|
|
860
|
-
(vnode.children ?? []).forEach((child) => {
|
|
861
|
-
element.appendChild(context.renderer.mount(child, context));
|
|
862
|
-
});
|
|
863
|
-
this.applyDirections(element, undefined, vnode.directions, context);
|
|
864
|
-
return element;
|
|
865
|
-
}
|
|
866
|
-
patch(oldVNode, newVNode, currentNode, context) {
|
|
867
|
-
if (oldVNode.tag !== newVNode.tag || currentNode.nodeType === Node.COMMENT_NODE) {
|
|
868
|
-
const nextNode = this.mount(newVNode, context);
|
|
869
|
-
currentNode.parentNode?.replaceChild(nextNode, currentNode);
|
|
870
|
-
this.unmount(oldVNode, currentNode, context);
|
|
871
|
-
return nextNode;
|
|
872
|
-
}
|
|
873
|
-
if (!(currentNode instanceof HTMLElement)) {
|
|
874
|
-
return currentNode;
|
|
875
|
-
}
|
|
876
|
-
if (newVNode.directions?.if === false) {
|
|
877
|
-
const nextNode = document.createComment("if");
|
|
878
|
-
currentNode.parentNode?.replaceChild(nextNode, currentNode);
|
|
879
|
-
this.unmount(oldVNode, currentNode, context);
|
|
880
|
-
return nextNode;
|
|
881
|
-
}
|
|
882
|
-
this.applyProps(currentNode, oldVNode.props ?? {}, newVNode.props ?? {}, context);
|
|
883
|
-
this.updateListeners(currentNode, this.collectListeners(oldVNode), this.collectListeners(newVNode));
|
|
884
|
-
this.updateChildren(currentNode, oldVNode.children ?? [], newVNode.children ?? [], context);
|
|
885
|
-
this.applyDirections(currentNode, oldVNode.directions, newVNode.directions, context);
|
|
886
|
-
return currentNode;
|
|
887
|
-
}
|
|
888
|
-
unmount(vnode, currentNode, context) {
|
|
889
|
-
if (!(currentNode instanceof HTMLElement)) {
|
|
890
|
-
return;
|
|
891
|
-
}
|
|
892
|
-
this.effects.get(currentNode)?.forEach((item) => stop(item));
|
|
893
|
-
this.effects.delete(currentNode);
|
|
894
|
-
this.listeners.get(currentNode)?.forEach(({ eventName, listener }) => {
|
|
895
|
-
currentNode.removeEventListener(eventName, listener);
|
|
896
|
-
});
|
|
897
|
-
this.listeners.delete(currentNode);
|
|
898
|
-
this.modelBindings.cleanup(currentNode);
|
|
899
|
-
(vnode.children ?? []).forEach((child, index) => {
|
|
900
|
-
const childNode = currentNode.childNodes[index];
|
|
901
|
-
if (childNode) {
|
|
902
|
-
context.renderer.unmount(child, childNode, context);
|
|
903
|
-
}
|
|
904
|
-
});
|
|
905
|
-
}
|
|
906
|
-
applyProps(element, oldProps, newProps, context) {
|
|
907
|
-
Object.keys(oldProps).forEach((key) => {
|
|
908
|
-
if (isEventProp(key) || key in newProps) {
|
|
909
|
-
return;
|
|
910
|
-
}
|
|
911
|
-
if (key === "className" || key === "class") {
|
|
912
|
-
element.removeAttribute("class");
|
|
913
|
-
} else if (key === "style") {
|
|
914
|
-
element.removeAttribute("style");
|
|
915
|
-
} else {
|
|
916
|
-
element.removeAttribute(key);
|
|
917
|
-
}
|
|
918
|
-
});
|
|
919
|
-
Object.entries(newProps).forEach(([key, value]) => {
|
|
920
|
-
if (isEventProp(key)) {
|
|
921
|
-
return;
|
|
922
|
-
}
|
|
923
|
-
if (key === "className" || key === "class") {
|
|
924
|
-
element.className = String(value ?? "");
|
|
925
|
-
return;
|
|
926
|
-
}
|
|
927
|
-
if (key === "style" && typeof value === "object" && value !== null) {
|
|
928
|
-
element.removeAttribute("style");
|
|
929
|
-
Object.entries(value).forEach(([cssKey, cssValue]) => {
|
|
930
|
-
setStyleValue(element.style, cssKey, cssValue);
|
|
931
|
-
});
|
|
932
|
-
return;
|
|
933
|
-
}
|
|
934
|
-
if (value === false || value === undefined || value === null) {
|
|
935
|
-
element.removeAttribute(key);
|
|
936
|
-
return;
|
|
937
|
-
}
|
|
938
|
-
if (value === true) {
|
|
939
|
-
element.setAttribute(key, "");
|
|
940
|
-
return;
|
|
941
|
-
}
|
|
942
|
-
if (typeof value === "string" && context.templateEngine.hasExpressions(value)) {
|
|
943
|
-
this.setupReactiveAttribute(element, key, value, context);
|
|
944
|
-
return;
|
|
945
|
-
}
|
|
946
|
-
element.setAttribute(key, String(value));
|
|
947
|
-
});
|
|
948
|
-
}
|
|
949
|
-
applyDirections(element, oldDirections, newDirections, context) {
|
|
950
|
-
if (newDirections && "show" in newDirections) {
|
|
951
|
-
element.style.display = newDirections.show ? "" : "none";
|
|
952
|
-
} else if (oldDirections && "show" in oldDirections) {
|
|
953
|
-
element.style.display = "";
|
|
954
|
-
}
|
|
955
|
-
if (!newDirections?.model) {
|
|
956
|
-
this.modelBindings.cleanup(element);
|
|
957
|
-
return;
|
|
958
|
-
}
|
|
959
|
-
this.modelBindings.bind(element, newDirections.model, context.templateEngine.state);
|
|
960
|
-
}
|
|
961
|
-
updateChildren(element, oldChildren, newChildren, context) {
|
|
962
|
-
this.assertNoDuplicateKeys(oldChildren);
|
|
963
|
-
this.assertNoDuplicateKeys(newChildren);
|
|
964
|
-
if (this.hasOnlyKeyedChildren(oldChildren, newChildren)) {
|
|
965
|
-
this.updateKeyedChildren(element, oldChildren, newChildren, context);
|
|
966
|
-
return;
|
|
967
|
-
}
|
|
968
|
-
const sharedLength = Math.min(oldChildren.length, newChildren.length);
|
|
969
|
-
for (let index = 0;index < sharedLength; index += 1) {
|
|
970
|
-
const childNode = element.childNodes[index];
|
|
971
|
-
if (!childNode) {
|
|
972
|
-
element.appendChild(context.renderer.mount(newChildren[index], context));
|
|
973
|
-
continue;
|
|
974
|
-
}
|
|
975
|
-
context.renderer.patch(oldChildren[index], newChildren[index], childNode, context);
|
|
976
|
-
}
|
|
977
|
-
for (let index = sharedLength;index < newChildren.length; index += 1) {
|
|
978
|
-
element.appendChild(context.renderer.mount(newChildren[index], context));
|
|
979
|
-
}
|
|
980
|
-
for (let index = oldChildren.length - 1;index >= newChildren.length; index -= 1) {
|
|
981
|
-
const childNode = element.childNodes[index];
|
|
982
|
-
if (childNode) {
|
|
983
|
-
context.renderer.unmount(oldChildren[index], childNode, context);
|
|
984
|
-
if (childNode.parentNode === element) {
|
|
985
|
-
element.removeChild(childNode);
|
|
986
|
-
}
|
|
987
|
-
}
|
|
988
|
-
}
|
|
989
|
-
}
|
|
990
|
-
updateKeyedChildren(element, oldChildren, newChildren, context) {
|
|
991
|
-
const oldEntries = oldChildren.map((vnode, index) => ({
|
|
992
|
-
vnode,
|
|
993
|
-
node: element.childNodes[index],
|
|
994
|
-
index
|
|
995
|
-
}));
|
|
996
|
-
const keyedOldEntries = new Map;
|
|
997
|
-
const usedOldIndexes = new Set;
|
|
998
|
-
oldEntries.forEach((entry) => {
|
|
999
|
-
const key = this.getVNodeKey(entry.vnode);
|
|
1000
|
-
if (key !== undefined && entry.node) {
|
|
1001
|
-
keyedOldEntries.set(key, {
|
|
1002
|
-
vnode: entry.vnode,
|
|
1003
|
-
node: entry.node,
|
|
1004
|
-
index: entry.index
|
|
1005
|
-
});
|
|
1006
|
-
}
|
|
1007
|
-
});
|
|
1008
|
-
newChildren.forEach((newChild, newIndex) => {
|
|
1009
|
-
const key = this.getVNodeKey(newChild);
|
|
1010
|
-
const oldEntry = key === undefined ? undefined : keyedOldEntries.get(key);
|
|
1011
|
-
let nextNode;
|
|
1012
|
-
if (oldEntry) {
|
|
1013
|
-
nextNode = context.renderer.patch(oldEntry.vnode, newChild, oldEntry.node, context);
|
|
1014
|
-
usedOldIndexes.add(oldEntry.index);
|
|
1015
|
-
} else {
|
|
1016
|
-
nextNode = context.renderer.mount(newChild, context);
|
|
1017
|
-
}
|
|
1018
|
-
const referenceNode = element.childNodes[newIndex] ?? null;
|
|
1019
|
-
if (nextNode !== referenceNode) {
|
|
1020
|
-
element.insertBefore(nextNode, referenceNode);
|
|
1021
|
-
}
|
|
1022
|
-
});
|
|
1023
|
-
oldEntries.forEach((entry) => {
|
|
1024
|
-
if (!entry.node || usedOldIndexes.has(entry.index)) {
|
|
1025
|
-
return;
|
|
1026
|
-
}
|
|
1027
|
-
context.renderer.unmount(entry.vnode, entry.node, context);
|
|
1028
|
-
if (entry.node.parentNode === element) {
|
|
1029
|
-
element.removeChild(entry.node);
|
|
1030
|
-
}
|
|
1031
|
-
});
|
|
1032
|
-
}
|
|
1033
|
-
hasOnlyKeyedChildren(oldChildren, newChildren) {
|
|
1034
|
-
return [...oldChildren, ...newChildren].every((child) => this.getVNodeKey(child) !== undefined);
|
|
1035
|
-
}
|
|
1036
|
-
assertNoDuplicateKeys(children) {
|
|
1037
|
-
const keys = new Set;
|
|
1038
|
-
children.forEach((child) => {
|
|
1039
|
-
const key = this.getVNodeKey(child);
|
|
1040
|
-
if (key === undefined) {
|
|
1041
|
-
return;
|
|
1042
|
-
}
|
|
1043
|
-
if (keys.has(key)) {
|
|
1044
|
-
throw new Error(`Duplicate key "${key}"`);
|
|
1045
|
-
}
|
|
1046
|
-
keys.add(key);
|
|
1047
|
-
});
|
|
1048
|
-
}
|
|
1049
|
-
getVNodeKey(vnode) {
|
|
1050
|
-
if (typeof vnode === "string") {
|
|
1051
|
-
return;
|
|
1052
|
-
}
|
|
1053
|
-
return vnode.key;
|
|
1054
|
-
}
|
|
1055
|
-
collectListeners(vnode) {
|
|
1056
|
-
const listeners = {};
|
|
1057
|
-
Object.entries(vnode.props ?? {}).forEach(([key, value]) => {
|
|
1058
|
-
if (isEventProp(key) && typeof value === "function") {
|
|
1059
|
-
listeners[eventNameFromProp(key)] = value;
|
|
1060
|
-
}
|
|
1061
|
-
});
|
|
1062
|
-
return {
|
|
1063
|
-
...listeners,
|
|
1064
|
-
...vnode.listeners ?? {}
|
|
1065
|
-
};
|
|
1066
|
-
}
|
|
1067
|
-
updateListeners(element, oldListeners, newListeners) {
|
|
1068
|
-
const store = this.listeners.get(element) ?? new Map;
|
|
1069
|
-
const oldKeys = new Set(Object.keys(oldListeners));
|
|
1070
|
-
const newKeys = new Set(Object.keys(newListeners));
|
|
1071
|
-
oldKeys.forEach((event) => {
|
|
1072
|
-
if (!newKeys.has(event) || oldListeners[event] !== newListeners[event]) {
|
|
1073
|
-
const stored = store.get(event);
|
|
1074
|
-
if (stored) {
|
|
1075
|
-
element.removeEventListener(stored.eventName, stored.listener);
|
|
1076
|
-
store.delete(event);
|
|
1077
|
-
}
|
|
1078
|
-
}
|
|
1079
|
-
});
|
|
1080
|
-
newKeys.forEach((event) => {
|
|
1081
|
-
if (!oldKeys.has(event) || oldListeners[event] !== newListeners[event]) {
|
|
1082
|
-
const { eventName, modifiers } = parseEventName(event);
|
|
1083
|
-
const listener = wrapEventHandler(newListeners[event], modifiers);
|
|
1084
|
-
element.addEventListener(eventName, listener);
|
|
1085
|
-
store.set(event, { eventName, listener });
|
|
1086
|
-
}
|
|
1087
|
-
});
|
|
1088
|
-
this.listeners.set(element, store);
|
|
1089
|
-
}
|
|
1090
|
-
setupReactiveAttribute(element, attrName, attrValue, context) {
|
|
1091
|
-
const effectRef = effect(() => {
|
|
1092
|
-
element.setAttribute(attrName, context.templateEngine.evaluateTemplateValue(attrValue));
|
|
1093
|
-
});
|
|
1094
|
-
this.trackEffect(element, effectRef);
|
|
1095
|
-
}
|
|
1096
|
-
trackEffect(element, effectRef) {
|
|
1097
|
-
const effects = this.effects.get(element) ?? new Set;
|
|
1098
|
-
effects.add(effectRef);
|
|
1099
|
-
this.effects.set(element, effects);
|
|
1100
|
-
}
|
|
1101
|
-
}
|
|
1102
|
-
|
|
1103
1397
|
// lib/core/template.ts
|
|
1104
1398
|
class TemplateEngine {
|
|
1105
1399
|
state;
|
|
@@ -1812,7 +2106,7 @@ function createRouter(options) {
|
|
|
1812
2106
|
return new Router(options);
|
|
1813
2107
|
}
|
|
1814
2108
|
|
|
1815
|
-
export {
|
|
2109
|
+
export { isComponentNode, isHTMLNode, isSlotProvider, h, Tag, Div, Span, P, Button, Input, Section, Main, Header, Footer, Nav, Article, Aside, H1, H2, H3, H4, H5, H6, Strong, Em, Small, Pre, Code, Blockquote, Ul, Ol, Li, A, Img, Form, Label, Textarea, Select, Option, Table, Thead, Tbody, Tr, Th, Td, createComponent, slot, each, ReactiveSystem, reactive, readonly, effect, computed, ref, isRef, unref, stop, isReactive, isReadonly, modelPath, getModelValue, setModelValue, ModelBindingController, ElementRenderStrategy, normalizeTransitionGroupProps, validateTransitionGroupChildren, RendererContext, TextRenderStrategy, ComponentRenderStrategy, SlotRenderStrategy, TemplateEngine, Component, useRouter, Router, RouterLink, RouterView, createRouter };
|
|
1816
2110
|
|
|
1817
|
-
//# debugId=
|
|
1818
|
-
//# sourceMappingURL=index-
|
|
2111
|
+
//# debugId=91AF0EEFB67A584364756E2164756E21
|
|
2112
|
+
//# sourceMappingURL=index-wv9gyjqt.js.map
|