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 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].notify([child[0]], () => {
17
+ child[1].computed(child[0], () => {
18
18
  element.innerHTML = "";
19
19
  element.appendChild(unroll_child_list([
20
- child[1].store[child[0]]
20
+ child[1].data[child[0]]
21
21
  ]));
22
22
  });
23
- element.appendChild(unroll_child_list([child[1].store[child[0]]]));
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.notify([eventName], () => {
65
- element.setAttribute(prop, signalInstance.store[eventName]);
64
+ signalInstance.computed([eventName], () => {
65
+ element.setAttribute(prop, signalInstance.data[eventName]);
66
66
  });
67
- element.setAttribute(prop, signalInstance.store[eventName]);
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
- setTimeout(() => {
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
- store;
610
- silentStore = undefined;
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 array or object");
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
- if (typeof restored === "object" && !Array.isArray(restored)) {
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
- publish(eventName) {
647
- this.subscribers[eventName]?.forEach((c) => {
648
- if (c.published) {
649
- compManager.recall(c);
650
- } else {
651
- c();
652
- }
653
- });
654
- this.subscribers["__ALL__"]?.forEach((c) => {
655
- if (c.published) {
656
- compManager.recall(c);
657
- } else {
658
- c();
659
- }
660
- });
661
- if (this.pn) {
662
- localStorage.setItem(this.pn, JSON.stringify(this.isList ? this.store.items : this.store.$_internal_data));
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
- set(NEW) {
527
+ publish() {
666
528
  const s = new Set;
667
- const events = this.store._set(NEW);
668
- for (const event of events) {
669
- const subs2 = this.subscribers[event];
670
- if (subs2) {
671
- for (const fn of subs2) {
672
- s.add(fn);
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
- if (this.subscribers["__ALL__"]) {
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.isList ? this.store.items : this.store.$_internal_data));
553
+ localStorage.setItem(this.pn, JSON.stringify(this.picker));
690
554
  }
691
555
  }
692
- notify(eventName, listener) {
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
- if (this.isList) {
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
- if (!isArrowFunc(listener)) {
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(element);
740
- } else {
741
- el = element?.();
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
- listener.element.insertAdjacentElement("beforebegin", newEl);
764
- listener.element.remove();
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 el;
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.store);
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, name } = pageParams;
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 = name || document.title;
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
- store: Type extends Array<any> ? List<Type> : Type extends Record<string, any> ? Type : never;
26
- silentStore: Type extends Array<any> ? never : Type;
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
- * fires actions if any available
23
+ * publish events to subscribers
35
24
  */
36
- set(NEW: Type): void;
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 name of event.
43
- * @param callback function to call.
31
+ * @param eventName of event.
32
+ * @param element to render.
44
33
  */
45
- notify<T extends keyof Type>(eventName: (T | "dataChanged" | "itemUpdated" | T[]) | (() => HTMLElement | void) | Comp | ((ctx: Comp) => HTMLElement), listener?: (() => HTMLElement | void) | Comp | ((this: Comp) => HTMLElement)): void;
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: Event) => void) | undefined;
9
+ [key: `on${string}`]: ((this: E, event: StandardEvents) => void) | undefined;
10
10
  }
11
- type StandardEvents<E extends HTMLElement> = {
12
- [key in keyof E]: E[key] extends (this: E, event: Event) => void ? key : never;
13
- }[keyof E];
14
- 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> & Omit<Partial<E>, keyof Attributes<E> | StandardEvents<E>>))[];
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
- name?: string;
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.13.2",
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.2"
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.16"
66
+ "docmach": "^1.0.18"
66
67
  }
67
68
  }