cradova 3.13.2 → 3.15.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/index.js +248 -254
- package/dist/primitives/classes.d.ts +37 -26
- package/dist/primitives/types.d.ts +7 -6
- package/package.json +6 -5
package/dist/index.js
CHANGED
|
@@ -14,13 +14,13 @@ var makeElement = (element, ElementChildrenAndPropertyList) => {
|
|
|
14
14
|
}
|
|
15
15
|
if (Array.isArray(child)) {
|
|
16
16
|
if (child[1] instanceof Signal) {
|
|
17
|
-
child[1].
|
|
17
|
+
child[1].computed(child[0], () => {
|
|
18
18
|
element.innerHTML = "";
|
|
19
19
|
element.appendChild(unroll_child_list([
|
|
20
|
-
child[1].
|
|
20
|
+
child[1].data[child[0]]
|
|
21
21
|
]));
|
|
22
22
|
});
|
|
23
|
-
element.appendChild(unroll_child_list([child[1].
|
|
23
|
+
element.appendChild(unroll_child_list([child[1].data[child[0]]]));
|
|
24
24
|
continue;
|
|
25
25
|
}
|
|
26
26
|
element.appendChild(unroll_child_list(child));
|
|
@@ -61,10 +61,10 @@ var makeElement = (element, ElementChildrenAndPropertyList) => {
|
|
|
61
61
|
if (value.length === 2 && value[1] instanceof Signal && typeof value[0] === "string") {
|
|
62
62
|
const eventName = value[0];
|
|
63
63
|
const signalInstance = value[1];
|
|
64
|
-
signalInstance.
|
|
65
|
-
element.setAttribute(prop, signalInstance.
|
|
64
|
+
signalInstance.computed([eventName], () => {
|
|
65
|
+
element.setAttribute(prop, signalInstance.data[eventName]);
|
|
66
66
|
});
|
|
67
|
-
element.setAttribute(prop, signalInstance.
|
|
67
|
+
element.setAttribute(prop, signalInstance.data[eventName]);
|
|
68
68
|
continue;
|
|
69
69
|
}
|
|
70
70
|
}
|
|
@@ -325,9 +325,7 @@ var compManager = {
|
|
|
325
325
|
},
|
|
326
326
|
recall(component) {
|
|
327
327
|
if (component.rendered && component.published) {
|
|
328
|
-
|
|
329
|
-
this.activate(component);
|
|
330
|
-
}, 0);
|
|
328
|
+
this.activate(component);
|
|
331
329
|
}
|
|
332
330
|
window.CradovaEvent.dispatchEvent("after_page_is_killed");
|
|
333
331
|
window.CradovaEvent.dispatchEvent("after_comp_is_mounted");
|
|
@@ -342,7 +340,6 @@ var compManager = {
|
|
|
342
340
|
resetComponent(component);
|
|
343
341
|
const newHtml = component(component, ...component._args || []);
|
|
344
342
|
if (newHtml instanceof HTMLElement) {
|
|
345
|
-
node.replaceWith(newHtml);
|
|
346
343
|
node.insertAdjacentElement("beforebegin", newHtml);
|
|
347
344
|
node.remove();
|
|
348
345
|
component.reference = newHtml;
|
|
@@ -486,198 +483,65 @@ class cradovaEvent {
|
|
|
486
483
|
}
|
|
487
484
|
window.CradovaEvent = new cradovaEvent;
|
|
488
485
|
|
|
489
|
-
class Store {
|
|
490
|
-
$_internal_data;
|
|
491
|
-
constructor(data, notifier) {
|
|
492
|
-
this.$_internal_data = data;
|
|
493
|
-
for (const key in this.$_internal_data) {
|
|
494
|
-
if (this.$_internal_data.hasOwnProperty(key)) {
|
|
495
|
-
Object.defineProperty(this, key, {
|
|
496
|
-
get() {
|
|
497
|
-
return this.$_internal_data[key];
|
|
498
|
-
},
|
|
499
|
-
set(value) {
|
|
500
|
-
this.$_internal_data[key] = value;
|
|
501
|
-
notifier(key, value);
|
|
502
|
-
},
|
|
503
|
-
enumerable: true,
|
|
504
|
-
configurable: true
|
|
505
|
-
});
|
|
506
|
-
}
|
|
507
|
-
}
|
|
508
|
-
}
|
|
509
|
-
_set(data) {
|
|
510
|
-
this.$_internal_data = data;
|
|
511
|
-
return Object.keys(this.$_internal_data);
|
|
512
|
-
}
|
|
513
|
-
}
|
|
514
|
-
|
|
515
|
-
class SilentStore {
|
|
516
|
-
$store;
|
|
517
|
-
constructor(store) {
|
|
518
|
-
this.$store = store;
|
|
519
|
-
for (const key in this.$store.$_internal_data) {
|
|
520
|
-
if (this.$store.$_internal_data.hasOwnProperty(key)) {
|
|
521
|
-
Object.defineProperty(this, key, {
|
|
522
|
-
set(value) {
|
|
523
|
-
this.$store.$_internal_data[key] = value;
|
|
524
|
-
},
|
|
525
|
-
enumerable: true,
|
|
526
|
-
configurable: true
|
|
527
|
-
});
|
|
528
|
-
}
|
|
529
|
-
}
|
|
530
|
-
}
|
|
531
|
-
}
|
|
532
|
-
|
|
533
|
-
class List {
|
|
534
|
-
_data;
|
|
535
|
-
_dirtyIndices;
|
|
536
|
-
notifier;
|
|
537
|
-
constructor(initialData, notifier) {
|
|
538
|
-
this._data = initialData || [];
|
|
539
|
-
this._dirtyIndices = new Set;
|
|
540
|
-
this.notifier = notifier;
|
|
541
|
-
this._dirtyIndices.add("all");
|
|
542
|
-
}
|
|
543
|
-
get items() {
|
|
544
|
-
return {
|
|
545
|
-
[Symbol.iterator]: () => {
|
|
546
|
-
return this._data[Symbol.iterator]();
|
|
547
|
-
},
|
|
548
|
-
next: () => {
|
|
549
|
-
return this._data[Symbol.iterator]().next();
|
|
550
|
-
}
|
|
551
|
-
};
|
|
552
|
-
}
|
|
553
|
-
get length() {
|
|
554
|
-
return this._data.length;
|
|
555
|
-
}
|
|
556
|
-
get(index) {
|
|
557
|
-
return this._data[index];
|
|
558
|
-
}
|
|
559
|
-
indexOf(item) {
|
|
560
|
-
return this._data.indexOf(item);
|
|
561
|
-
}
|
|
562
|
-
update(index, newItemData) {
|
|
563
|
-
if (index >= 0 && index < this._data.length && this._data[index] !== newItemData) {
|
|
564
|
-
this._data[index] = newItemData;
|
|
565
|
-
this._dirtyIndices.add(index);
|
|
566
|
-
this.notifier("itemUpdated", { index, newItemData });
|
|
567
|
-
}
|
|
568
|
-
}
|
|
569
|
-
push(itemData, index) {
|
|
570
|
-
if (index === undefined || index > this._data.length || index < 0) {
|
|
571
|
-
index = this._data.length;
|
|
572
|
-
}
|
|
573
|
-
this._data.splice(index, 0, itemData);
|
|
574
|
-
this._dirtyIndices.add("all");
|
|
575
|
-
this.notifier("dataChanged", { type: "add", index });
|
|
576
|
-
}
|
|
577
|
-
map(callback) {
|
|
578
|
-
return this._data.map(callback);
|
|
579
|
-
}
|
|
580
|
-
remove(index, count = 1) {
|
|
581
|
-
if (index >= 0 && index < this._data.length && count > 0) {
|
|
582
|
-
this._data.splice(index, count);
|
|
583
|
-
this._dirtyIndices.add("all");
|
|
584
|
-
this.notifier("dataChanged", { type: "remove", index });
|
|
585
|
-
}
|
|
586
|
-
}
|
|
587
|
-
_set(newData) {
|
|
588
|
-
this._data = newData || [];
|
|
589
|
-
this._dirtyIndices.clear();
|
|
590
|
-
this._dirtyIndices.add("all");
|
|
591
|
-
return ["dataChanged"];
|
|
592
|
-
}
|
|
593
|
-
_isDirty(index = "all") {
|
|
594
|
-
if (this._dirtyIndices.has(index)) {
|
|
595
|
-
this._dirtyIndices.delete(index);
|
|
596
|
-
return true;
|
|
597
|
-
}
|
|
598
|
-
return false;
|
|
599
|
-
}
|
|
600
|
-
_clearAllDirty() {
|
|
601
|
-
this._dirtyIndices.clear();
|
|
602
|
-
}
|
|
603
|
-
}
|
|
604
|
-
|
|
605
486
|
class Signal {
|
|
606
487
|
pn;
|
|
607
|
-
isList = false;
|
|
608
488
|
subscribers = {};
|
|
609
|
-
|
|
610
|
-
|
|
489
|
+
data = {};
|
|
490
|
+
picker = {};
|
|
491
|
+
soft = {};
|
|
611
492
|
passers;
|
|
493
|
+
queue = new Set;
|
|
612
494
|
constructor(initial, props) {
|
|
613
|
-
if (!initial || typeof initial !== "object") {
|
|
614
|
-
throw new Error("Initial signal value must be an
|
|
615
|
-
}
|
|
616
|
-
if (!Array.isArray(initial)) {
|
|
617
|
-
this.store = new Store(initial, (key) => {
|
|
618
|
-
this.publish(key);
|
|
619
|
-
});
|
|
620
|
-
this.silentStore = new SilentStore(this.store);
|
|
621
|
-
} else {
|
|
622
|
-
this.isList = true;
|
|
623
|
-
this.store = new List(initial, (eventType) => {
|
|
624
|
-
this.publish(eventType);
|
|
625
|
-
});
|
|
495
|
+
if (!initial || typeof initial !== "object" || Array.isArray(initial)) {
|
|
496
|
+
throw new Error("Initial signal value must be an object");
|
|
626
497
|
}
|
|
498
|
+
this.picker = initial;
|
|
627
499
|
if (props && props.persistName) {
|
|
628
500
|
this.pn = props.persistName;
|
|
629
501
|
const key = localStorage.getItem(props.persistName);
|
|
630
502
|
if (key && key !== "undefined") {
|
|
631
503
|
const restored = JSON.parse(key);
|
|
632
|
-
|
|
633
|
-
this.store = new Store(Object.assign(initial, restored), (key2) => {
|
|
634
|
-
this.publish(key2);
|
|
635
|
-
});
|
|
636
|
-
this.silentStore = new SilentStore(this.store);
|
|
637
|
-
} else if (Array.isArray(restored)) {
|
|
638
|
-
this.isList = true;
|
|
639
|
-
this.store = new List(restored, (eventType) => {
|
|
640
|
-
this.publish(eventType);
|
|
641
|
-
});
|
|
642
|
-
}
|
|
504
|
+
this.picker = Object.assign(initial, restored);
|
|
643
505
|
}
|
|
644
506
|
}
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
507
|
+
for (const key in this.picker) {
|
|
508
|
+
Object.defineProperty(this.data, key, {
|
|
509
|
+
set: (value) => {
|
|
510
|
+
this.picker[key] = value;
|
|
511
|
+
this.queue.add(key);
|
|
512
|
+
queueMicrotask(() => this.queue.size && this.publish());
|
|
513
|
+
},
|
|
514
|
+
get: () => this.picker[key],
|
|
515
|
+
enumerable: true,
|
|
516
|
+
configurable: true
|
|
517
|
+
});
|
|
518
|
+
Object.defineProperty(this.soft, key, {
|
|
519
|
+
set: (value) => {
|
|
520
|
+
this.picker[key] = value;
|
|
521
|
+
},
|
|
522
|
+
enumerable: true,
|
|
523
|
+
configurable: true
|
|
524
|
+
});
|
|
663
525
|
}
|
|
664
526
|
}
|
|
665
|
-
|
|
527
|
+
publish() {
|
|
666
528
|
const s = new Set;
|
|
667
|
-
|
|
668
|
-
for (const
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
529
|
+
this.queue.add("__ALL__");
|
|
530
|
+
for (const k of this.queue) {
|
|
531
|
+
if (this.picker.hasOwnProperty(k)) {
|
|
532
|
+
const subs2 = this.subscribers[k];
|
|
533
|
+
if (subs2) {
|
|
534
|
+
for (const fn of subs2) {
|
|
535
|
+
s.add(fn);
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
} else {
|
|
539
|
+
if (k !== "__ALL__") {
|
|
540
|
+
delete this.subscribers[k];
|
|
673
541
|
}
|
|
674
542
|
}
|
|
675
543
|
}
|
|
676
|
-
|
|
677
|
-
for (const fn of this.subscribers["__ALL__"]) {
|
|
678
|
-
s.add(fn);
|
|
679
|
-
}
|
|
680
|
-
}
|
|
544
|
+
this.queue.clear();
|
|
681
545
|
for (const c of s.values()) {
|
|
682
546
|
if (c.published) {
|
|
683
547
|
compManager.recall(c);
|
|
@@ -686,97 +550,44 @@ class Signal {
|
|
|
686
550
|
}
|
|
687
551
|
}
|
|
688
552
|
if (this.pn) {
|
|
689
|
-
localStorage.setItem(this.pn, JSON.stringify(this.
|
|
553
|
+
localStorage.setItem(this.pn, JSON.stringify(this.picker));
|
|
690
554
|
}
|
|
691
555
|
}
|
|
692
|
-
|
|
556
|
+
set(data) {
|
|
557
|
+
Object.assign(this.picker, data);
|
|
558
|
+
this.queue = new Set(Object.keys(this.subscribers));
|
|
559
|
+
queueMicrotask(() => this.publish());
|
|
560
|
+
}
|
|
561
|
+
computed(eventName, listener) {
|
|
693
562
|
if (!eventName) {
|
|
694
563
|
console.error(` ✘ Cradova err: eventName ${String(eventName)} or listener ${String(listener)} is not a valid event name or function`);
|
|
695
564
|
return;
|
|
696
565
|
}
|
|
697
566
|
if (typeof eventName === "function") {
|
|
698
567
|
listener = eventName;
|
|
699
|
-
|
|
700
|
-
eventName = ["dataChanged", "itemUpdated"];
|
|
701
|
-
} else {
|
|
702
|
-
eventName = Object.keys(this.store);
|
|
703
|
-
}
|
|
704
|
-
}
|
|
705
|
-
if (typeof listener !== "function" || !eventName) {
|
|
706
|
-
console.error(` ✘ Cradova err: listener or eventName ${String(listener)} is not a valid listener function or string`);
|
|
707
|
-
return;
|
|
708
|
-
}
|
|
709
|
-
if (Array.isArray(eventName)) {
|
|
710
|
-
eventName.forEach((en) => {
|
|
711
|
-
this.notify(en, listener);
|
|
712
|
-
});
|
|
713
|
-
return;
|
|
568
|
+
eventName = "__ALL__";
|
|
714
569
|
}
|
|
715
570
|
if (!this.subscribers[eventName]) {
|
|
716
571
|
this.subscribers[eventName] = [];
|
|
717
572
|
}
|
|
718
|
-
|
|
719
|
-
listener = toCompNoRender(listener);
|
|
720
|
-
}
|
|
721
|
-
this.subscribers[eventName].push(listener);
|
|
722
|
-
}
|
|
723
|
-
computed(eventName, element) {
|
|
724
|
-
if (!eventName) {
|
|
725
|
-
console.error(` ✘ Cradova err: eventName ${String(eventName)} or element ${String(element)} is not a valid event name or function`);
|
|
726
|
-
return;
|
|
727
|
-
}
|
|
728
|
-
if (typeof eventName === "function") {
|
|
729
|
-
element = eventName;
|
|
730
|
-
if (this.isList) {
|
|
731
|
-
eventName = "__ALL__";
|
|
732
|
-
} else {
|
|
733
|
-
eventName = "__ALL__";
|
|
734
|
-
}
|
|
735
|
-
}
|
|
736
|
-
const isComp = !isArrowFunc(element);
|
|
737
|
-
let el;
|
|
573
|
+
const isComp = !isArrowFunc(listener);
|
|
738
574
|
if (isComp) {
|
|
739
|
-
el = toComp(
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
}
|
|
743
|
-
if (el === undefined || !(el instanceof HTMLElement)) {
|
|
744
|
-
console.error(` ✘ Cradova err: ${String(element)} is not a valid element or function`);
|
|
745
|
-
return;
|
|
746
|
-
}
|
|
747
|
-
const listener = () => {
|
|
748
|
-
if (!document.body.contains(listener.element)) {
|
|
749
|
-
listener.element?.remove();
|
|
750
|
-
this.subscribers[eventName] = this.subscribers[eventName].filter((f) => listener.idx !== f.idx);
|
|
751
|
-
return;
|
|
752
|
-
}
|
|
753
|
-
let newEl;
|
|
754
|
-
if (isComp) {
|
|
755
|
-
newEl = toComp(element);
|
|
756
|
-
} else {
|
|
757
|
-
newEl = element?.();
|
|
758
|
-
}
|
|
759
|
-
if (newEl === undefined || !(newEl instanceof HTMLElement)) {
|
|
760
|
-
console.error(` ✘ Cradova err: ${String(element)} is not a valid element or function`);
|
|
575
|
+
const el = toComp(listener);
|
|
576
|
+
if (el === undefined || !(el instanceof HTMLElement)) {
|
|
577
|
+
console.error(` ✘ Cradova err: ${String(listener)} is not a valid element or function`);
|
|
761
578
|
return;
|
|
762
579
|
}
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
listener.element = newEl;
|
|
766
|
-
};
|
|
767
|
-
listener.element = el;
|
|
768
|
-
if (!this.subscribers[eventName]) {
|
|
769
|
-
this.subscribers[eventName] = [];
|
|
580
|
+
this.subscribers[eventName].push(listener);
|
|
581
|
+
return el;
|
|
770
582
|
}
|
|
771
|
-
listener.idx = this.subscribers[eventName].length;
|
|
772
583
|
this.subscribers[eventName].push(listener);
|
|
773
|
-
return
|
|
584
|
+
return;
|
|
774
585
|
}
|
|
775
586
|
get pass() {
|
|
776
587
|
if (this.passers) {
|
|
777
588
|
return this.passers;
|
|
778
589
|
}
|
|
779
|
-
const keys = Object.keys(this.
|
|
590
|
+
const keys = Object.keys(this.picker);
|
|
780
591
|
this.passers = {};
|
|
781
592
|
for (const key of keys) {
|
|
782
593
|
this.passers[key] = [key, this];
|
|
@@ -790,6 +601,185 @@ class Signal {
|
|
|
790
601
|
}
|
|
791
602
|
}
|
|
792
603
|
|
|
604
|
+
class List {
|
|
605
|
+
state;
|
|
606
|
+
item;
|
|
607
|
+
length;
|
|
608
|
+
options;
|
|
609
|
+
renderingRange;
|
|
610
|
+
container;
|
|
611
|
+
firstItemIndex = 0;
|
|
612
|
+
lastItemIndex = 0;
|
|
613
|
+
rendered = false;
|
|
614
|
+
subscribers = [];
|
|
615
|
+
constructor(state, item, options) {
|
|
616
|
+
this.state = state;
|
|
617
|
+
this.item = item || ((item2) => div(String(item2)));
|
|
618
|
+
this.length = state.length;
|
|
619
|
+
this.options = options;
|
|
620
|
+
this.renderingRange = Math.round(Math.min(this.length > 50 ? this.length * 0.5 : this.length, window.innerHeight / (this.options?.itemHeight || 1)));
|
|
621
|
+
this.lastItemIndex = this.renderingRange - 1;
|
|
622
|
+
this.container = document.createElement("div");
|
|
623
|
+
if (this.options?.className) {
|
|
624
|
+
this.container.className = this.options?.className;
|
|
625
|
+
}
|
|
626
|
+
if (this.options?.id) {
|
|
627
|
+
this.container.id = this.options?.id;
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
get Element() {
|
|
631
|
+
if (this.rendered) {
|
|
632
|
+
return this.container;
|
|
633
|
+
}
|
|
634
|
+
for (let i2 = 0;i2 < this.renderingRange; i2++) {
|
|
635
|
+
const item = this.item(this.state[i2]);
|
|
636
|
+
item.setAttribute("data-index", i2.toString());
|
|
637
|
+
this.container.appendChild(item);
|
|
638
|
+
}
|
|
639
|
+
this.rendered = true;
|
|
640
|
+
const domObser = () => {
|
|
641
|
+
const observer = new IntersectionObserver((entries) => {
|
|
642
|
+
entries.forEach((entry) => {
|
|
643
|
+
if (entry.isIntersecting) {
|
|
644
|
+
const isBottom = entry.target === this.container.lastElementChild;
|
|
645
|
+
const isTop = !isBottom;
|
|
646
|
+
observer.unobserve(entry.target);
|
|
647
|
+
const index = Number(entry.target.getAttribute("data-index"));
|
|
648
|
+
if (isBottom) {
|
|
649
|
+
for (let i2 = index + 1;i2 < this.length; i2++) {
|
|
650
|
+
const item = this.item(this.state[i2]);
|
|
651
|
+
item.setAttribute("data-index", i2.toString());
|
|
652
|
+
this.container.appendChild(item);
|
|
653
|
+
}
|
|
654
|
+
for (let i2 = index - this.renderingRange;i2 > 0; i2--) {
|
|
655
|
+
this.container.removeChild(this.container.children[i2]);
|
|
656
|
+
}
|
|
657
|
+
this.firstItemIndex = Number(this.container.firstElementChild?.getAttribute("data-index") || 0);
|
|
658
|
+
this.lastItemIndex = Number(this.container.lastElementChild?.getAttribute("data-index") || 0);
|
|
659
|
+
}
|
|
660
|
+
if (isTop) {
|
|
661
|
+
for (let i2 = index - 1;i2 > 0; i2--) {
|
|
662
|
+
const item = this.item(this.state[i2]);
|
|
663
|
+
item.setAttribute("data-index", i2.toString());
|
|
664
|
+
this.container.appendChild(item);
|
|
665
|
+
}
|
|
666
|
+
for (let i2 = index + this.renderingRange;i2 < this.length; i2++) {
|
|
667
|
+
this.container.removeChild(this.container.children[i2]);
|
|
668
|
+
}
|
|
669
|
+
this.lastItemIndex = Number(this.container.lastElementChild?.getAttribute("data-index") || 0);
|
|
670
|
+
this.firstItemIndex = Number(this.container.firstElementChild?.getAttribute("data-index") || 0);
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
});
|
|
674
|
+
});
|
|
675
|
+
observer.observe(this.container.lastElementChild);
|
|
676
|
+
observer.observe(this.container.firstElementChild);
|
|
677
|
+
};
|
|
678
|
+
window.addEventListener("scroll", domObser);
|
|
679
|
+
window.CradovaEvent.after_page_is_killed.push(() => {
|
|
680
|
+
window.removeEventListener("scroll", domObser);
|
|
681
|
+
});
|
|
682
|
+
return this.container;
|
|
683
|
+
}
|
|
684
|
+
computed(listener) {
|
|
685
|
+
if (!listener) {
|
|
686
|
+
console.error(` ✘ Cradova err: listener ${String(listener)} is not a valid event name or function`);
|
|
687
|
+
return;
|
|
688
|
+
}
|
|
689
|
+
if (!this.subscribers) {
|
|
690
|
+
this.subscribers = [];
|
|
691
|
+
}
|
|
692
|
+
const isComp = !isArrowFunc(listener);
|
|
693
|
+
if (isComp) {
|
|
694
|
+
const el = toComp(listener);
|
|
695
|
+
if (el === undefined || !(el instanceof HTMLElement)) {
|
|
696
|
+
console.error(` ✘ Cradova err: ${String(listener)} is not a valid element or function`);
|
|
697
|
+
return;
|
|
698
|
+
}
|
|
699
|
+
this.subscribers.push(listener);
|
|
700
|
+
return el;
|
|
701
|
+
}
|
|
702
|
+
this.subscribers.push(listener);
|
|
703
|
+
return;
|
|
704
|
+
}
|
|
705
|
+
diffDOMBeforeUpdatingState(newState) {
|
|
706
|
+
this.length = newState.length;
|
|
707
|
+
this.renderingRange = Math.round(Math.min(this.length > 100 ? this.length * 0.5 : this.length, window.innerHeight / (this.options?.itemHeight || 1)));
|
|
708
|
+
this.lastItemIndex = this.firstItemIndex + this.renderingRange;
|
|
709
|
+
for (let i2 = this.lastItemIndex;i2 >= this.firstItemIndex; i2--) {
|
|
710
|
+
if ((this.state[i2] === undefined || newState[i2] === undefined) && this.container.children[i2] !== undefined) {
|
|
711
|
+
this.container.removeChild(this.container.children[i2]);
|
|
712
|
+
continue;
|
|
713
|
+
}
|
|
714
|
+
if (JSON.stringify(this.state[i2]) === JSON.stringify(newState[i2])) {
|
|
715
|
+
continue;
|
|
716
|
+
}
|
|
717
|
+
const item = this.item(newState[i2]);
|
|
718
|
+
item.setAttribute("data-index", i2.toString());
|
|
719
|
+
if (this.container.children[i2]) {
|
|
720
|
+
this.container.replaceChild(item, this.container.children[i2]);
|
|
721
|
+
} else {
|
|
722
|
+
this.container.appendChild(item);
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
this.lastItemIndex = Number(this.container.lastElementChild?.getAttribute("data-index") || 0);
|
|
726
|
+
this.firstItemIndex = Number(this.container.firstElementChild?.getAttribute("data-index") || 0);
|
|
727
|
+
this.state = newState;
|
|
728
|
+
this.subscribers.forEach((sub) => {
|
|
729
|
+
const isComp = !isArrowFunc(sub);
|
|
730
|
+
if (isComp) {
|
|
731
|
+
compManager.recall(sub);
|
|
732
|
+
} else {
|
|
733
|
+
sub?.();
|
|
734
|
+
}
|
|
735
|
+
});
|
|
736
|
+
}
|
|
737
|
+
get data() {
|
|
738
|
+
return {
|
|
739
|
+
[Symbol.iterator]: () => {
|
|
740
|
+
return this.state[Symbol.iterator]();
|
|
741
|
+
},
|
|
742
|
+
next: () => {
|
|
743
|
+
return this.state[Symbol.iterator]().next();
|
|
744
|
+
}
|
|
745
|
+
};
|
|
746
|
+
}
|
|
747
|
+
get(index) {
|
|
748
|
+
return this.state[index];
|
|
749
|
+
}
|
|
750
|
+
indexOf(item) {
|
|
751
|
+
return this.state.indexOf(item);
|
|
752
|
+
}
|
|
753
|
+
update(index, newItemData) {
|
|
754
|
+
const newState = [...this.state];
|
|
755
|
+
if (index >= 0 && index < this.state.length && this.state[index] !== newItemData) {
|
|
756
|
+
newState[index] = newItemData;
|
|
757
|
+
}
|
|
758
|
+
this.diffDOMBeforeUpdatingState(newState);
|
|
759
|
+
}
|
|
760
|
+
push(itemData) {
|
|
761
|
+
const newState = [...this.state];
|
|
762
|
+
newState.push(itemData);
|
|
763
|
+
this.diffDOMBeforeUpdatingState(newState);
|
|
764
|
+
}
|
|
765
|
+
map(callback) {
|
|
766
|
+
const newState = [...this.state];
|
|
767
|
+
return newState.map(callback);
|
|
768
|
+
}
|
|
769
|
+
splice(index, count = 1, ...items) {
|
|
770
|
+
const newState = [...this.state];
|
|
771
|
+
if (index >= 0 && index < this.state.length && count > 0) {
|
|
772
|
+
newState.splice(index, count, ...items);
|
|
773
|
+
}
|
|
774
|
+
this.diffDOMBeforeUpdatingState(newState);
|
|
775
|
+
}
|
|
776
|
+
set(newData) {
|
|
777
|
+
const newState = [...this.state];
|
|
778
|
+
this.state = newData instanceof Function ? newData(this.state) : newData || [];
|
|
779
|
+
this.diffDOMBeforeUpdatingState(newState);
|
|
780
|
+
}
|
|
781
|
+
}
|
|
782
|
+
|
|
793
783
|
class Page {
|
|
794
784
|
_name;
|
|
795
785
|
_html;
|
|
@@ -797,12 +787,12 @@ class Page {
|
|
|
797
787
|
_unload_CB;
|
|
798
788
|
_activate_CB;
|
|
799
789
|
constructor(pageParams) {
|
|
800
|
-
const { template,
|
|
790
|
+
const { template, title } = pageParams;
|
|
801
791
|
if (typeof template !== "function") {
|
|
802
792
|
throw new Error(` ✘ Cradova err: template function for the page is not a function`);
|
|
803
793
|
}
|
|
804
794
|
this._html = template;
|
|
805
|
-
this._name =
|
|
795
|
+
this._name = title || document.title;
|
|
806
796
|
}
|
|
807
797
|
set onDeactivate(cb) {
|
|
808
798
|
this._unload_CB = cb;
|
|
@@ -848,6 +838,9 @@ class RouterBoxClass {
|
|
|
848
838
|
window.location.hash = "paused";
|
|
849
839
|
return;
|
|
850
840
|
}
|
|
841
|
+
if (url === this.lastNavigatedRoute) {
|
|
842
|
+
return;
|
|
843
|
+
}
|
|
851
844
|
if (this.nextRouteController) {
|
|
852
845
|
route = this.nextRouteController;
|
|
853
846
|
this.nextRouteController = undefined;
|
|
@@ -1101,6 +1094,7 @@ export {
|
|
|
1101
1094
|
Router,
|
|
1102
1095
|
RefInstance,
|
|
1103
1096
|
Page,
|
|
1097
|
+
List,
|
|
1104
1098
|
$switch,
|
|
1105
1099
|
$case
|
|
1106
1100
|
};
|
|
@@ -1,16 +1,4 @@
|
|
|
1
1
|
import type { browserPageType, Comp, CradovaPageType } from "./types.js";
|
|
2
|
-
declare class List<Type extends any[]> {
|
|
3
|
-
notifier: (eventType: "dataChanged" | "itemUpdated", newItemData: Type[number]) => void;
|
|
4
|
-
constructor(initialData: Type, notifier: (eventType: "dataChanged" | "itemUpdated", newItemData: Type[number]) => void);
|
|
5
|
-
get items(): IterableIterator<Type[number]>;
|
|
6
|
-
get length(): number;
|
|
7
|
-
get(index: number): any;
|
|
8
|
-
indexOf(item: Type[number]): number;
|
|
9
|
-
update(index: number, newItemData: Type[number]): void;
|
|
10
|
-
push(itemData: Type[number], index?: number): void;
|
|
11
|
-
map<T>(callback: (item: Type[number], index: number) => T): T[];
|
|
12
|
-
remove(index: number, count?: number): void;
|
|
13
|
-
}
|
|
14
2
|
/**
|
|
15
3
|
* Cradova Signal
|
|
16
4
|
* ----
|
|
@@ -21,29 +9,29 @@ declare class List<Type extends any[]> {
|
|
|
21
9
|
* - persist changes to localStorage
|
|
22
10
|
* @constructor initial: Record<string, any>, props: {persist}
|
|
23
11
|
*/
|
|
24
|
-
export declare class Signal<Type = any> {
|
|
25
|
-
|
|
26
|
-
|
|
12
|
+
export declare class Signal<Type extends Record<string, any> = any> {
|
|
13
|
+
data: Type;
|
|
14
|
+
soft: Type;
|
|
27
15
|
passers?: Record<keyof Type, [string, Signal<Type>]>;
|
|
16
|
+
private queue;
|
|
28
17
|
constructor(initial: Type, props?: {
|
|
29
18
|
persistName?: string | undefined;
|
|
30
19
|
});
|
|
31
20
|
/**
|
|
32
21
|
* Cradova Signal
|
|
33
22
|
* ----
|
|
34
|
-
*
|
|
23
|
+
* publish events to subscribers
|
|
35
24
|
*/
|
|
36
|
-
set(
|
|
25
|
+
set(data: Type): void;
|
|
37
26
|
/**
|
|
38
27
|
* Cradova Signal
|
|
39
28
|
* ----
|
|
40
|
-
* subscribe to an event
|
|
29
|
+
* subscribe a function, component to an event
|
|
41
30
|
*
|
|
42
|
-
* @param
|
|
43
|
-
* @param
|
|
31
|
+
* @param eventName of event.
|
|
32
|
+
* @param element to render.
|
|
44
33
|
*/
|
|
45
|
-
|
|
46
|
-
computed<T extends keyof Type>(eventName: (T | "dataChanged" | "itemUpdated") | (() => HTMLElement) | Comp | ((ctx: Comp) => HTMLElement), element?: (() => HTMLElement) | Comp | ((ctx: Comp) => HTMLElement)): HTMLElement | undefined;
|
|
34
|
+
computed<T extends keyof Type>(eventName: T | "__ALL__" | (() => void) | Comp | ((ctx: Comp) => HTMLElement), listener?: (() => void) | Comp | ((ctx: Comp) => HTMLElement)): HTMLElement | undefined;
|
|
47
35
|
/**
|
|
48
36
|
* Cradova Signal
|
|
49
37
|
* ----
|
|
@@ -57,6 +45,32 @@ export declare class Signal<Type = any> {
|
|
|
57
45
|
*/
|
|
58
46
|
clearPersist(): void;
|
|
59
47
|
}
|
|
48
|
+
/**
|
|
49
|
+
* Cradova List
|
|
50
|
+
* ---
|
|
51
|
+
* A virtual list store and component for efficient rendering of large lists.
|
|
52
|
+
*/
|
|
53
|
+
export declare class List<T> {
|
|
54
|
+
length: number;
|
|
55
|
+
private rendered;
|
|
56
|
+
subscribers: Function[];
|
|
57
|
+
constructor(state: T[], item?: (item: T) => HTMLElement, options?: {
|
|
58
|
+
itemHeight: number;
|
|
59
|
+
className?: string;
|
|
60
|
+
id?: string;
|
|
61
|
+
});
|
|
62
|
+
get Element(): HTMLElement;
|
|
63
|
+
computed(listener?: (() => void) | Comp | ((ctx: Comp) => HTMLElement)): HTMLElement | undefined;
|
|
64
|
+
private diffDOMBeforeUpdatingState;
|
|
65
|
+
get data(): IterableIterator<T>;
|
|
66
|
+
get(index: number): T;
|
|
67
|
+
indexOf(item: T): number;
|
|
68
|
+
update(index: number, newItemData: T): void;
|
|
69
|
+
push(itemData: T): void;
|
|
70
|
+
map<K>(callback: (item: T, index: number) => K): K[];
|
|
71
|
+
splice(index: number, count?: number, ...items: T[]): void;
|
|
72
|
+
set(newData: T[] | ((prevItem: T[]) => T[])): void;
|
|
73
|
+
}
|
|
60
74
|
/**
|
|
61
75
|
* Cradova Page
|
|
62
76
|
* ---
|
|
@@ -65,6 +79,7 @@ export declare class Signal<Type = any> {
|
|
|
65
79
|
* @param template
|
|
66
80
|
*/
|
|
67
81
|
export declare class Page {
|
|
82
|
+
_unload_CB?: (this: Page) => Promise<void> | void;
|
|
68
83
|
_activate_CB?: (this: Page) => Promise<void> | void;
|
|
69
84
|
constructor(pageParams: CradovaPageType);
|
|
70
85
|
set onDeactivate(cb: (this: Page) => Promise<void> | void);
|
|
@@ -118,10 +133,7 @@ export declare class Router {
|
|
|
118
133
|
/**
|
|
119
134
|
* Cradova Router
|
|
120
135
|
* ------
|
|
121
|
-
*
|
|
122
136
|
* return last set router params
|
|
123
|
-
*
|
|
124
|
-
* .
|
|
125
137
|
*/
|
|
126
138
|
static get PageData(): {
|
|
127
139
|
params: Record<string, string>;
|
|
@@ -152,4 +164,3 @@ export declare class RefInstance<T = unknown> {
|
|
|
152
164
|
*/
|
|
153
165
|
bind(name: string): [RefInstance<T>, string];
|
|
154
166
|
}
|
|
155
|
-
export {};
|
|
@@ -6,12 +6,13 @@ interface Attributes<E extends HTMLElement> {
|
|
|
6
6
|
style?: Partial<CSS.Properties>;
|
|
7
7
|
[key: `data-${string}`]: string | undefined;
|
|
8
8
|
[key: `aria-${string}`]: string | undefined;
|
|
9
|
-
[key: `on${string}`]: ((this: E, event:
|
|
9
|
+
[key: `on${string}`]: ((this: E, event: StandardEvents) => void) | undefined;
|
|
10
10
|
}
|
|
11
|
-
type StandardEvents
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
11
|
+
type StandardEvents = KeyboardEvent | MouseEvent | TouchEvent | WheelEvent | DragEvent | ClipboardEvent | CompositionEvent | FocusEvent | InputEvent | AnimationEvent | TransitionEvent | Event;
|
|
12
|
+
type OmitFunctions<E> = {
|
|
13
|
+
[K in keyof E as E[K] extends Function ? never : K]: E[K];
|
|
14
|
+
};
|
|
15
|
+
export type VJS_params_TYPE<E extends HTMLElement> = (undefined | undefined[] | string | string[] | HTMLElement | HTMLElement[] | DocumentFragment | DocumentFragment[] | (() => HTMLElement) | (() => HTMLElement)[] | ((ctx: Comp) => HTMLElement) | ((ctx: Comp) => HTMLElement)[] | [string, Signal<any>] | Attributes<E> | OmitFunctions<E>)[];
|
|
15
16
|
export type CradovaPageType = {
|
|
16
17
|
/**
|
|
17
18
|
* Cradova page
|
|
@@ -19,7 +20,7 @@ export type CradovaPageType = {
|
|
|
19
20
|
* title of the page
|
|
20
21
|
* .
|
|
21
22
|
*/
|
|
22
|
-
|
|
23
|
+
title?: string;
|
|
23
24
|
/**
|
|
24
25
|
* Cradova page
|
|
25
26
|
* ---
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cradova",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.15.0",
|
|
4
4
|
"description": "Build Powerful ⚡ Web Apps with Ease",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -14,9 +14,10 @@
|
|
|
14
14
|
"url": "git+https://github.com/CodeDynasty-dev/Cradova.git"
|
|
15
15
|
},
|
|
16
16
|
"scripts": {
|
|
17
|
-
"compile": "bun bundle.ts",
|
|
17
|
+
"compile": "bun bundle.ts && run clean",
|
|
18
18
|
"lint": "eslint . --fix",
|
|
19
|
-
"tsc": "tsc --target esnext tests/index.ts --watch --moduleResolution NodeNext --module NodeNext"
|
|
19
|
+
"tsc": "tsc --target esnext tests/index.ts --watch --moduleResolution NodeNext --module NodeNext",
|
|
20
|
+
"clean": "rm -rf tests/dist && cp -r dist tests/dist"
|
|
20
21
|
},
|
|
21
22
|
"keywords": [
|
|
22
23
|
"frontend library",
|
|
@@ -54,7 +55,7 @@
|
|
|
54
55
|
},
|
|
55
56
|
"homepage": "https://github.com/CodeDynasty-dev/cradova",
|
|
56
57
|
"dependencies": {
|
|
57
|
-
"csstype": "^3.1.
|
|
58
|
+
"csstype": "^3.1.3"
|
|
58
59
|
},
|
|
59
60
|
"docmach": {
|
|
60
61
|
"docs-directory": "docs/docs",
|
|
@@ -62,6 +63,6 @@
|
|
|
62
63
|
"assets-folder": "docs/assets"
|
|
63
64
|
},
|
|
64
65
|
"devDependencies": {
|
|
65
|
-
"docmach": "^1.0.
|
|
66
|
+
"docmach": "^1.0.18"
|
|
66
67
|
}
|
|
67
68
|
}
|