lahama 3.0.0 → 5.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/lahama.js +682 -4
  2. package/package.json +1 -1
package/dist/lahama.js CHANGED
@@ -1,17 +1,158 @@
1
- import 'vitest/dist/chunks/reporters.d.OXEK7y4s.d.ts';
2
-
3
1
  function withoutNulls(arr) {
4
2
  return arr.filter((item) => item != null)
5
3
  }
4
+ function arraysDiff(oldArray, newArray) {
5
+ return {
6
+ added : newArray.filter(
7
+ (newItem) => !oldArray.includes(newItem)
8
+ ),
9
+ removed : oldArray.filter(
10
+ (oldItem) => !newArray.includes(oldItem)
11
+ )
12
+ }
13
+ }
14
+ const ARRAY_DIFF_OP = {
15
+ ADD : 'add',
16
+ REMOVE : 'remove',
17
+ MOVE : 'move',
18
+ NOOP : 'noop'
19
+ };
6
20
  const a = { };
7
21
  const b = { };
8
22
  console.log(a === b);
23
+ class ArrayWithOriginalIndices {
24
+ #array = []
25
+ #originalIndices = []
26
+ #equalsFn
27
+ constructor(array, equalsFn) {
28
+ this.#array = [...array];
29
+ this.#originalIndices = array.map((_, i) => i);
30
+ this.#equalsFn = equalsFn;
31
+ }
32
+ get length() {
33
+ return this.#array.length
34
+ }
35
+ isRemoval(index, newArray) {
36
+ if (index >= this.length) {
37
+ return false
38
+ }
39
+ const item = this.#array[index];
40
+ const indexInNewArray = newArray.findIndex((newItem) =>
41
+ this.#equalsFn(item, newItem)
42
+ );
43
+ return indexInNewArray === -1
44
+ }
45
+ removeItem(index) {
46
+ const operation = {
47
+ op : ARRAY_DIFF_OP.REMOVE,
48
+ index,
49
+ item : this.#array[index],
50
+ };
51
+ this.#array.splice(index, 1);
52
+ return operation
53
+ }
54
+ isNoop(index, newArray) {
55
+ if (index >= this.length) {
56
+ return false
57
+ }
58
+ const item = this.#array[index];
59
+ const newItem = newArray[index];
60
+ return this.#equalsFn(item, newItem)
61
+ }
62
+ originalIndexAt(index) {
63
+ return this.#originalIndices[index]
64
+ }
65
+ noopItem(index) {
66
+ return {
67
+ op : ARRAY_DIFF_OP.NOOP,
68
+ originalIndex : this.originalIndexAt(index),
69
+ item : this.#array[index],
70
+ }
71
+ }
72
+ isAddition(item, fromIdx) {
73
+ return this.findIndexFrom(item, fromIdx) === -1
74
+ }
75
+ findIndexFrom(item, fromIndex) {
76
+ for (let i = fromIndex; i < this.length; i++) {
77
+ if (this.#equalsFn(item, this.#array[i])) {
78
+ return i
79
+ }
80
+ }
81
+ return -1
82
+ }
83
+ addItem(item, index) {
84
+ const operation = {
85
+ op : ARRAY_DIFF_OP.ADD,
86
+ index,
87
+ item
88
+ };
89
+ this.#array.splice(index, 0, item);
90
+ this.#originalIndices.splice(index, 0, -1);
91
+ return operation
92
+ }
93
+ moveItem(item, toIndex) {
94
+ const fromIndex = this.findIndexFrom(item, toIndex);
95
+ const operation = {
96
+ op : ARRAY_DIFF_OP.MOVE,
97
+ originalIndex : this.originalIndexAt(fromIndex),
98
+ from : fromIndex,
99
+ index : toIndex,
100
+ item : this.#array[fromIndex]
101
+ };
102
+ const [_item] = this.#array.splice(fromIndex, 1);
103
+ this.#array.splice(toIndex, 0 , _item);
104
+ const [originalIndex] =
105
+ this.#originalIndices.splice(fromIndex, 1);
106
+ this.#originalIndices.splice(toIndex, 0, originalIndex);
107
+ return operation
108
+ }
109
+ removeItemsAfter(index) {
110
+ const operations = [];
111
+ while (this.length > index) {
112
+ operations.push(this.removeItem(index));
113
+ }
114
+ return operations
115
+ }
116
+ }
117
+ function arraysDiffSequence(
118
+ oldArray,
119
+ newArray,
120
+ equalsFn = (a, b) => a === b
121
+ ) {
122
+ const sequence = [];
123
+ const array = new ArrayWithOriginalIndices(oldArray, equalsFn);
124
+ for (let index = 0; index < newArray.length; index++) {
125
+ //!REMOVE CASE
126
+ if (array.isRemoval(index, newArray)) {
127
+ sequence.push(array.removeItem(index));
128
+ index--;
129
+ continue
130
+ }
131
+ //!noop case
132
+ if (array.isNoop(index, newArray)) {
133
+ sequence.push(array.noopItem(index));
134
+ continue
135
+ }
136
+ //!addition case
137
+ const item = newArray[index];
138
+ if (array.isAddition(item , index)) {
139
+ sequence.push(array.addItem(item, index));
140
+ continue
141
+ }
142
+ //!move case
143
+ sequence.push(array.moveItem(item, index));
144
+ }
145
+ //!remove extra items
146
+ sequence.push(...array.removeItemsAfter(newArray.length));
147
+ return sequence
148
+ }
9
149
 
10
150
  const DOM_TYPES = {
11
151
  TEXT : 'text',
12
152
  ELEMENT : 'element',
13
153
  FRAGMENT : 'fragment',
14
154
  COMPONENT : 'component',
155
+ SLOT : 'slot'
15
156
  };
16
157
  function h(tag, props = {} , children = []) {
17
158
  const type =
@@ -36,6 +177,17 @@ function hFragment(vNodes) {
36
177
  children : mapTextNodes(withoutNulls(vNodes)),
37
178
  }
38
179
  }
180
+ let hSlotCalled = false;
181
+ function didCreateSlot() {
182
+ return hSlotCalled
183
+ }
184
+ function resetDidCreateSlot() {
185
+ hSlotCalled = false;
186
+ }
187
+ function hSlot(children = []) {
188
+ hSlotCalled = true;
189
+ return { type : DOM_TYPES.SLOT, children}
190
+ }
39
191
 
40
192
  function addEventListener(
41
193
  eventName,
@@ -100,6 +252,9 @@ function setClass(el, className) {
100
252
  function setStyle(el, name, value) {
101
253
  el.style[name] = value;
102
254
  }
255
+ function removeStyle(el, name) {
256
+ el.style[name] = null;
257
+ }
103
258
  function removeAttributeCustom(el, name) {
104
259
  el[name] = null;
105
260
  el.removeAttribute(name);
@@ -120,6 +275,40 @@ function extractPropsAndEvents(vdom) {
120
275
  return { props, events }
121
276
  }
122
277
 
278
+ let isScheduled = false;
279
+ const jobs = [];
280
+ function enqueueJob(job) {
281
+ jobs.push(job);
282
+ scheduleUpdate();
283
+ }
284
+ function scheduleUpdate() {
285
+ if (isScheduled) return
286
+ isScheduled = true;
287
+ queueMicrotask(processJobs);
288
+ }
289
+ function processJobs() {
290
+ while (jobs.length > 0) {
291
+ const job = jobs.shift();
292
+ const result = job();
293
+ Promise.resolve(result).then(
294
+ () => {
295
+ },
296
+ (error) => {
297
+ console.error(`[scheduler]: ${error}`);
298
+ }
299
+ );
300
+ job();
301
+ }
302
+ isScheduled = false;
303
+ }
304
+ function nextTick() {
305
+ scheduleUpdate();
306
+ return flushPromises()
307
+ }
308
+ function flushPromises() {
309
+ return new Promise((resolve) => setTimeout(resolve))
310
+ }
311
+
123
312
  function mountDom(
124
313
  vdom,
125
314
  parentEl,
@@ -141,6 +330,7 @@ function mountDom(
141
330
  }
142
331
  case DOM_TYPES.COMPONENT : {
143
332
  createComponentNode(vdom, parentEl, index, hostComponent);
333
+ enqueueJob(() => vdom.component.onMounted());
144
334
  break
145
335
  }
146
336
  default : {
@@ -190,9 +380,10 @@ function createFragmentNodes(vdom, parentEl, index, hostComponent) {
190
380
  children.forEach((child, i) => mountDom(child, parentEl, index ? index + i : null, hostComponent));
191
381
  }
192
382
  function createComponentNode(vdom, parentEl, index, hostComponent) {
193
- const Component = vdom.tag;
383
+ const { tag : Component, children } = vdom;
194
384
  const { props, events } = extractPropsAndEvents(vdom);
195
385
  const component = new Component(props, events, hostComponent);
386
+ component.setExternalContent(children);
196
387
  component.mount(parentEl, index);
197
388
  vdom.component = component;
198
389
  vdom.el = component.firstElement;
@@ -215,6 +406,7 @@ function destroyDom(vdom) {
215
406
  }
216
407
  case DOM_TYPES.COMPONENT : {
217
408
  vdom.component.unmount();
409
+ enqueueJob(() => vdom.component.onUnMounted());
218
410
  break
219
411
  }
220
412
  default : {
@@ -270,4 +462,490 @@ function createApp(RootComponent, props = {}) {
270
462
  }
271
463
  }
272
464
 
273
- export { DOM_TYPES, createApp, h, hFragment, hString };
465
+ function areNodesEqual(nodeOne, nodeTwo) {
466
+ if (nodeOne.type !== nodeTwo.type) {
467
+ return false
468
+ }
469
+ if (nodeOne.type === DOM_TYPES.ELEMENT) {
470
+ const {
471
+ tag : tagOne,
472
+ props : { key : keyOne}
473
+ } = nodeOne;
474
+ const {
475
+ tag : tagTwo,
476
+ props : { key : keyTwo}
477
+ } = nodeTwo;
478
+ return tagOne === tagTwo && keyOne === keyTwo
479
+ }
480
+ if (nodeOne.type === DOM_TYPES.COMPONENT) {
481
+ const {
482
+ tag : componentOne,
483
+ props : { key : keyOne},
484
+ } = nodeOne;
485
+ const {
486
+ tag : componentTwo,
487
+ props : {key : keyTwo},
488
+ } = nodeTwo;
489
+ return componentOne === componentTwo && keyOne === keyTwo
490
+ }
491
+ return true
492
+ }
493
+
494
+ function objectsDiff(oldObj, newObj) {
495
+ const oldKeys = Object.keys(oldObj);
496
+ const newKeys = Object.keys(newObj);
497
+ return {
498
+ added : newKeys.filter((key) => !(key in oldObj)),
499
+ removed : oldKeys.filter((key) => !(key in newObj)),
500
+ updated : newKeys.filter(
501
+ (key) => key in oldObj && oldObj[key] !== newObj[key]
502
+ ),
503
+ }
504
+ }
505
+ function hasOwnProperty(obj, prop) {
506
+ return Object.prototype.hasOwnProperty.call(obj, prop)
507
+ }
508
+
509
+ function isNotEmptyString(str) {
510
+ return str !== ''
511
+ }
512
+ function isNotBlankOrEmptyString(str) {
513
+ return isNotEmptyString(str.trim())
514
+ }
515
+
516
+ function patchDOM(oldVdom, newVdom, parentEl, hostComponent = null) {
517
+ if (!areNodesEqual(oldVdom, newVdom)) {
518
+ const index = findIndexInParent(parentEl, oldVdom.el);
519
+ destroyDom(oldVdom);
520
+ mountDom(newVdom, parentEl, index, hostComponent);
521
+ return newVdom
522
+ }
523
+ newVdom.el = oldVdom.el;
524
+ switch (newVdom.type) {
525
+ case DOM_TYPES.TEXT: {
526
+ patchText(oldVdom, newVdom);
527
+ return newVdom
528
+ }
529
+ case DOM_TYPES.ELEMENT: {
530
+ patchElement(oldVdom, newVdom, hostComponent);
531
+ break
532
+ }
533
+ case DOM_TYPES.COMPONENT: {
534
+ patchComponent(oldVdom, newVdom);
535
+ break
536
+ }
537
+ }
538
+ patchChildren(oldVdom, newVdom, hostComponent);
539
+ return newVdom
540
+ }
541
+ function patchText(oldVdom, newVdom) {
542
+ const el = oldVdom.el;
543
+ const { value : oldText} = oldVdom;
544
+ const { value : newText} = newVdom;
545
+ if (oldText !== newText) {
546
+ el.nodeValue = newText;
547
+ }
548
+ }
549
+ function findIndexInParent(parentEl, el) {
550
+ const index = Array.from(parentEl.childNodes).indexOf(el);
551
+ if (index < 0) {
552
+ return null
553
+ }
554
+ return index
555
+ }
556
+ function patchElement(oldVdom, newVdom, hostComponent) {
557
+ const el = oldVdom.el;
558
+ const {
559
+ class : oldClass,
560
+ style : oldStyle,
561
+ on: oldEvents,
562
+ ...oldAttrs
563
+ } = oldVdom.props;
564
+ const {
565
+ class: newClass,
566
+ style: newStyle,
567
+ on: newEvents,
568
+ ...newAttrs
569
+ } = newVdom.props;
570
+ const { listeners: oldListeners } = oldVdom;
571
+ patchAttrs(el, oldAttrs, newAttrs);
572
+ patchClasses(el, oldClass, newClass);
573
+ patchStyles(el, oldStyle, newStyle);
574
+ newVdom.listeners = patchEvents(
575
+ el,
576
+ oldListeners,
577
+ oldEvents,
578
+ newEvents,
579
+ hostComponent
580
+ );
581
+ }
582
+ function patchAttrs(el, oldAttrs, newAttrs) {
583
+ const { added, removed, updated } = objectsDiff(oldAttrs, newAttrs);
584
+ for (const attr of removed) {
585
+ removeAttributeCustom(el, attr);
586
+ }
587
+ for (const attr of added.concat(updated)) {
588
+ setAttribute(el, attr, newAttrs[attr]);
589
+ }
590
+ }
591
+ function patchClasses(el, oldClass, newClass) {
592
+ const oldClasses = toClassList(oldClass);
593
+ const newClasses = toClassList(newClass);
594
+ const {added, removed} =
595
+ arraysDiff(oldClasses, newClasses);
596
+ if (removed.length > 0) {
597
+ el.classList.remove(...removed);
598
+ }
599
+ if (added.length > 0) {
600
+ el.classList.add(...added);
601
+ }
602
+ }
603
+ function toClassList(classes = '') {
604
+ return Array.isArray(classes)
605
+ ? classes.filter(isNotBlankOrEmptyString)
606
+ : classes.split(/(\s+)/)
607
+ .filter(isNotBlankOrEmptyString)
608
+ }
609
+ function patchStyles(el, oldStyle = {}, newStyle = {}) {
610
+ const {added, removed, updated } = objectsDiff(oldStyle, newStyle);
611
+ for (const style of removed) {
612
+ removeStyle(el, style);
613
+ }
614
+ for (const style of added.concat(updated)) {
615
+ setStyle(el, style, newStyle[style]);
616
+ }
617
+ }
618
+ function patchEvents(
619
+ el,
620
+ oldListeners = {},
621
+ oldEvents = {},
622
+ newEvents = {},
623
+ hostComponent
624
+ ) {
625
+ const { removed, added, updated} =
626
+ objectsDiff(oldEvents, newEvents);
627
+ for (const eventName of removed.concat(updated)) {
628
+ el.removeEventListener(eventName, oldListeners[eventName]);
629
+ }
630
+ const addedListeners = {};
631
+ for (const eventName of added.concat(updated)) {
632
+ const listener = addEventListener(
633
+ eventName,
634
+ newEvents[eventName],
635
+ el,
636
+ hostComponent
637
+ );
638
+ addedListeners[eventName] = listener;
639
+ }
640
+ return addedListeners
641
+ }
642
+ function patchComponent(oldVdom, newVdom) {
643
+ const { component } = oldVdom;
644
+ const { children } = newVdom;
645
+ const { props } = extractPropsAndEvents(newVdom);
646
+ component.setExternalContent(children);
647
+ component.updateProps(props);
648
+ newVdom.component = component;
649
+ newVdom.el = component.firstElement;
650
+ }
651
+ function extractChildren(vdom) {
652
+ if (vdom.children == null) {
653
+ return []
654
+ }
655
+ const children = [];
656
+ for (const child of vdom.children) {
657
+ if (child.type === DOM_TYPES.FRAGMENT) {
658
+ children.push(...extractChildren(child));
659
+ } else {
660
+ children.push(child);
661
+ }
662
+ }
663
+ return children
664
+ }
665
+ function patchChildren(oldVdom, newVdom, hostComponent) {
666
+ const oldChildren = extractChildren(oldVdom);
667
+ const newChildren = extractChildren(newVdom);
668
+ const parentEl = oldVdom.el;
669
+ const diffSeq = arraysDiffSequence(oldChildren, newChildren, areNodesEqual);
670
+ for (const operation of diffSeq) {
671
+ const { originalIndex, index, item} = operation;
672
+ const offset = hostComponent?.offset ?? 0;
673
+ switch (operation.op) {
674
+ case ARRAY_DIFF_OP.ADD: {
675
+ mountDom(item, parentEl, index + offset, hostComponent);
676
+ break
677
+ }
678
+ case ARRAY_DIFF_OP.REMOVE: {
679
+ destroyDom(item);
680
+ break
681
+ }
682
+ case ARRAY_DIFF_OP.MOVE: {
683
+ const oldChild = oldChildren[originalIndex];
684
+ const newChild = newChildren[index];
685
+ const el = oldChild.el;
686
+ const elAtTargetIndex = parentEl.childNodes[index + offset];
687
+ parentEl.insertBefore(el, elAtTargetIndex);
688
+ patchDOM(oldChildren[originalIndex], newChild, parentEl, hostComponent);
689
+ break
690
+ }
691
+ case ARRAY_DIFF_OP.NOOP : {
692
+ patchDOM(oldChildren[originalIndex], newChildren[index], parentEl, hostComponent);
693
+ break
694
+ }
695
+ }
696
+ }
697
+ }
698
+
699
+ function getDefaultExportFromCjs (x) {
700
+ return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
701
+ }
702
+
703
+ var fastDeepEqual;
704
+ var hasRequiredFastDeepEqual;
705
+ function requireFastDeepEqual () {
706
+ if (hasRequiredFastDeepEqual) return fastDeepEqual;
707
+ hasRequiredFastDeepEqual = 1;
708
+ fastDeepEqual = function equal(a, b) {
709
+ if (a === b) return true;
710
+ if (a && b && typeof a == 'object' && typeof b == 'object') {
711
+ if (a.constructor !== b.constructor) return false;
712
+ var length, i, keys;
713
+ if (Array.isArray(a)) {
714
+ length = a.length;
715
+ if (length != b.length) return false;
716
+ for (i = length; i-- !== 0;)
717
+ if (!equal(a[i], b[i])) return false;
718
+ return true;
719
+ }
720
+ if (a.constructor === RegExp) return a.source === b.source && a.flags === b.flags;
721
+ if (a.valueOf !== Object.prototype.valueOf) return a.valueOf() === b.valueOf();
722
+ if (a.toString !== Object.prototype.toString) return a.toString() === b.toString();
723
+ keys = Object.keys(a);
724
+ length = keys.length;
725
+ if (length !== Object.keys(b).length) return false;
726
+ for (i = length; i-- !== 0;)
727
+ if (!Object.prototype.hasOwnProperty.call(b, keys[i])) return false;
728
+ for (i = length; i-- !== 0;) {
729
+ var key = keys[i];
730
+ if (!equal(a[key], b[key])) return false;
731
+ }
732
+ return true;
733
+ }
734
+ return a!==a && b!==b;
735
+ };
736
+ return fastDeepEqual;
737
+ }
738
+
739
+ var fastDeepEqualExports = requireFastDeepEqual();
740
+ var equal = /*@__PURE__*/getDefaultExportFromCjs(fastDeepEqualExports);
741
+
742
+ class Dispatcher {
743
+ #subs = new Map()
744
+ #afterHandlers = []
745
+ subscribe(commandName, handler) {
746
+ if (!this.#subs.has(commandName)) {
747
+ this.#subs.set(commandName, []);
748
+ }
749
+ const handlersArray = this.#subs.get(commandName);
750
+ if (handlersArray.includes(handler)) {
751
+ return () => {
752
+ }
753
+ }
754
+ handlersArray.push(handler);
755
+ return () => {
756
+ const idx = handlersArray.indexOf(handler);
757
+ handlersArray.splice(idx, 1);
758
+ }
759
+ }
760
+ afterEveryCommand(handler) {
761
+ this.#afterHandlers.push(handler);
762
+ return () => {
763
+ const idx = this.#afterHandlers.indexOf(handler);
764
+ this.#afterHandlers.splice(idx, 1);
765
+ }
766
+ }
767
+ dispatch(commandName, payload) {
768
+ if (this.#subs.has(commandName)) {
769
+ this.#subs.get(commandName).forEach((handler) => handler(payload));
770
+ } else {
771
+ console.warn(`No handlers for command : ${commandName}`);
772
+ }
773
+ this.#afterHandlers.forEach((handler) => handler());
774
+ }
775
+ }
776
+
777
+ function traverseDFS(
778
+ vdom,
779
+ processNode,
780
+ shouldSkipBranch = () => false,
781
+ parentNode,
782
+ index = null
783
+ ) {
784
+ if (shouldSkipBranch(vdom)) return
785
+ processNode(vdom, parentNode, index);
786
+ if (vdom.children) {
787
+ vdom.children.forEach((child, i) =>
788
+ traverseDFS(child, processNode, shouldSkipBranch, vdom, i)
789
+ );
790
+ }
791
+ }
792
+
793
+ function fillSlots(vdom, externalContent = []) {
794
+ function processNode(node, parent, index) {
795
+ insertViewInSlot(node, parent, index, externalContent);
796
+ }
797
+ traverseDFS(vdom, processNode, shouldSkipBranch);
798
+ }
799
+ function insertViewInSlot(node, parent, index, externalContent) {
800
+ if (node.type !== DOM_TYPES.SLOT) return
801
+ const defaultContent = node.children;
802
+ const views = externalContent.length > 0 ? externalContent : defaultContent;
803
+ const hasContent = views.length > 0;
804
+ if (hasContent) {
805
+ parent.children.splice(index, 1, hFragment(views));
806
+ } else {
807
+ parent.children(index, 1);
808
+ }
809
+ }
810
+ function shouldSkipBranch(node) {
811
+ return node.type === DOM_TYPES.COMPONENT
812
+ }
813
+
814
+ const emptyFn = () => {};
815
+ function defineComponent({
816
+ render,
817
+ state,
818
+ onMounted = emptyFn,
819
+ onUnmounted = emptyFn,
820
+ ...methods
821
+ }) {
822
+ class Component {
823
+ #isMounted = false
824
+ #vdom = null
825
+ #hostEl = null
826
+ #eventHandlers = null
827
+ #parentComponent = null
828
+ #dispatcher = new Dispatcher()
829
+ #subscriptions = []
830
+ #children = []
831
+ setExternalContent(children) {
832
+ this.#children = children;
833
+ }
834
+ constructor(
835
+ props = {},
836
+ eventHandlers = {},
837
+ parentComponent = null
838
+ ) {
839
+ this.props = props;
840
+ this.state = state ? state(props) : {};
841
+ this.#eventHandlers = eventHandlers;
842
+ this.#parentComponent = parentComponent;
843
+ }
844
+ onMounted() {
845
+ return Promise.resolve(onMounted.call(this))
846
+ }
847
+ onUnMounted() {
848
+ return Promise.resolve(onUnmounted.call(this))
849
+ }
850
+ get elements() {
851
+ if (this.#vdom == null) {
852
+ return []
853
+ }
854
+ if (this.#vdom.type === DOM_TYPES.FRAGMENT) {
855
+ return extractChildren(this.#vdom).flatMap((child) => {
856
+ if (child.type === DOM_TYPES.COMPONENT) ;
857
+ return [child.el]
858
+ })
859
+ }
860
+ return [this.#vdom.el]
861
+ }
862
+ get firstElement() {
863
+ return this.elements[0]
864
+ }
865
+ get offset() {
866
+ if (this.#vdom.type === DOM_TYPES.ELEMENT) {
867
+ return Array.from(this.#hostEl.children).indexOf(this.firstElement)
868
+ }
869
+ return 0
870
+ }
871
+ emit(eventName, payload) {
872
+ this.#dispatcher.dispatch(eventName, payload);
873
+ }
874
+ updateProps(props) {
875
+ //! creates a new props object by merging the old and new props
876
+ const newProps = { ...this.props, ...props};
877
+ if (equal(this.props, newProps)) {
878
+ return
879
+ }
880
+ this.props = newProps;
881
+ this.#patch();
882
+ }
883
+ updateState(state) {
884
+ this.state = { ...this.state, ...state};
885
+ this.#patch();
886
+ }
887
+ render() {
888
+ const vdom = render.call(this);
889
+ if (didCreateSlot()) {
890
+ fillSlots(vdom, this.#children);
891
+ resetDidCreateSlot();
892
+ }
893
+ return vdom
894
+ }
895
+ mount(hostEl, index = null) {
896
+ if (this.#isMounted) {
897
+ throw new Error('Component is already mounted')
898
+ }
899
+ this.#vdom = this.render();
900
+ mountDom(this.#vdom, hostEl, index, this); //!this - passes the component reference to the mountDOM fucntion
901
+ this.#wireEventHandlers();
902
+ this.#hostEl = hostEl;
903
+ this.#isMounted = true;
904
+ }
905
+ #patch() {
906
+ if (!this.#isMounted) {
907
+ throw new Error('Component is not mounted')
908
+ }
909
+ const vdom = this.render();
910
+ this.#vdom = patchDOM(this.#vdom, vdom, this.#hostEl, this);
911
+ }
912
+ unmount() {
913
+ if (!this.#isMounted) {
914
+ throw new Error(`Component is not mounted`)
915
+ }
916
+ destroyDom(this.#vdom);
917
+ this.#subscriptions.forEach((unsubscribe) => unsubscribe());
918
+ this.#vdom = null;
919
+ this.#hostEl = null;
920
+ this.#isMounted = false;
921
+ this.#subscriptions = [];
922
+ }
923
+ #wireEventHandlers() {
924
+ this.#subscriptions = Object.entries(this.#eventHandlers).map(
925
+ ([eventName, handler]) => {
926
+ this.#wireEventHandlers(eventName, handler);
927
+ }
928
+ );
929
+ }
930
+ #wireEventHandler(eventName, handler) {
931
+ return this.#dispatcher.subscribe(eventName, (payload) => {
932
+ if (this.#parentComponent) {
933
+ handler.call(this.#parentComponent, payload);
934
+ } else {
935
+ handler(payload);
936
+ }
937
+ })
938
+ }
939
+ }
940
+ for (const methodName in methods) {
941
+ if (hasOwnProperty(Component, methodName)) {
942
+ throw new Error(
943
+ `Method "${methodName}()" already exists in the component.`
944
+ )
945
+ }
946
+ Component.prototype[methodName] = methods[methodName];
947
+ }
948
+ return Component;
949
+ }
950
+
951
+ export { DOM_TYPES, createApp, defineComponent, h, hFragment, hSlot, hString, nextTick };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lahama",
3
- "version": "3.0.0",
3
+ "version": "5.0.0",
4
4
  "description": "",
5
5
  "main": "dist/lahama.js",
6
6
  "files": [