lahama 2.0.0 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/lahama.js +345 -7
- package/package.json +1 -1
package/dist/lahama.js
CHANGED
|
@@ -1,9 +1,146 @@
|
|
|
1
1
|
function withoutNulls(arr) {
|
|
2
2
|
return arr.filter((item) => item != null)
|
|
3
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
|
+
};
|
|
4
20
|
const a = { };
|
|
5
21
|
const b = { };
|
|
6
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
|
+
if (array.isRemoval(index, newArray)) {
|
|
126
|
+
sequence.push(array.removeItem(index));
|
|
127
|
+
index--;
|
|
128
|
+
continue
|
|
129
|
+
}
|
|
130
|
+
if (array.isNoop(index, newArray)) {
|
|
131
|
+
sequence.push(array.noopItem(index));
|
|
132
|
+
continue
|
|
133
|
+
}
|
|
134
|
+
const item = newArray[index];
|
|
135
|
+
if (array.isAddition(item , index)) {
|
|
136
|
+
sequence.push(array.addItem(item, index));
|
|
137
|
+
continue
|
|
138
|
+
}
|
|
139
|
+
sequence.push(array.moveItem(item, index));
|
|
140
|
+
}
|
|
141
|
+
sequence.push(...array.removeItemsAfter(newArray.length));
|
|
142
|
+
return sequence
|
|
143
|
+
}
|
|
7
144
|
|
|
8
145
|
const DOM_TYPES = {
|
|
9
146
|
TEXT : 'text',
|
|
@@ -32,14 +169,14 @@ function hFragment(vNodes) {
|
|
|
32
169
|
}
|
|
33
170
|
}
|
|
34
171
|
|
|
35
|
-
function addEventListener(eventName, handler, el) {
|
|
172
|
+
function addEventListener$1(eventName, handler, el) {
|
|
36
173
|
el.addEventListener(eventName, handler);
|
|
37
174
|
return handler
|
|
38
175
|
}
|
|
39
176
|
function addEventListeners(listeners = {}, el) {
|
|
40
177
|
const addedListeners = {};
|
|
41
178
|
Object.entries(listeners).forEach(([eventName, handler]) => {
|
|
42
|
-
addedListeners[eventName] = addEventListener(eventName, handler, el);
|
|
179
|
+
addedListeners[eventName] = addEventListener$1(eventName, handler, el);
|
|
43
180
|
});
|
|
44
181
|
return addedListeners
|
|
45
182
|
}
|
|
@@ -114,6 +251,9 @@ function setClass(el, className) {
|
|
|
114
251
|
function setStyle(el, name, value) {
|
|
115
252
|
el.style[name] = value;
|
|
116
253
|
}
|
|
254
|
+
function removeStyle(el, name) {
|
|
255
|
+
el.style[name] = null;
|
|
256
|
+
}
|
|
117
257
|
function removeAttributeCustom(el, name) {
|
|
118
258
|
el[name] = null;
|
|
119
259
|
el.removeAttribute(name);
|
|
@@ -224,6 +364,206 @@ class Dispatcher {
|
|
|
224
364
|
}
|
|
225
365
|
}
|
|
226
366
|
|
|
367
|
+
function areNodesEqual(nodeOne, nodeTwo) {
|
|
368
|
+
if (nodeOne.type !== nodeTwo.type) {
|
|
369
|
+
return false
|
|
370
|
+
}
|
|
371
|
+
if (nodeOne.type === DOM_TYPES.ELEMENT) {
|
|
372
|
+
const { tag : tagOne } = nodeOne;
|
|
373
|
+
const { tag : tagTwo} = nodeTwo;
|
|
374
|
+
return tagOne === tagTwo
|
|
375
|
+
}
|
|
376
|
+
return true
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
function objectsDiff(oldObj, newObj) {
|
|
380
|
+
const oldKeys = Object.keys(oldObj);
|
|
381
|
+
const newKeys = Object.keys(newObj);
|
|
382
|
+
return {
|
|
383
|
+
added : newKeys.filter((key) => !(key in oldObj)),
|
|
384
|
+
removed : oldKeys.filter((key) => !(key in newObj)),
|
|
385
|
+
updated : newKeys.filter(
|
|
386
|
+
(key) => key in oldObj && oldObj[key] !== newObj[key]
|
|
387
|
+
),
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
function isNotEmptyString(str) {
|
|
392
|
+
return str !== ''
|
|
393
|
+
}
|
|
394
|
+
function isNotBlankOrEmptyString(str) {
|
|
395
|
+
return isNotEmptyString(str.trim())
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
function patchDOM(oldVdom, newVdom, parentEl) {
|
|
399
|
+
if (!areNodesEqual(oldVdom, newVdom)) {
|
|
400
|
+
const index = findIndexInParent(parentEl, oldVdom.el);
|
|
401
|
+
destroyDom(oldVdom);
|
|
402
|
+
mountDom(newVdom, parentEl, index);
|
|
403
|
+
return newVdom
|
|
404
|
+
}
|
|
405
|
+
newVdom.el = oldVdom.el;
|
|
406
|
+
switch (newVdom.type) {
|
|
407
|
+
case DOM_TYPES.TEXT : {
|
|
408
|
+
patchText(oldVdom, newVdom);
|
|
409
|
+
return newVdom
|
|
410
|
+
}
|
|
411
|
+
case DOM_TYPES.ELEMENT : {
|
|
412
|
+
patchElement(oldVdom, newVdom);
|
|
413
|
+
break
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
patchChildren(oldVdom, newVdom);
|
|
417
|
+
return newVdom
|
|
418
|
+
}
|
|
419
|
+
function patchText(oldVdom, newVdom) {
|
|
420
|
+
const el = oldVdom.el;
|
|
421
|
+
const { value : oldText} = oldVdom;
|
|
422
|
+
const { value : newText} = newVdom;
|
|
423
|
+
if (oldText !== newText) {
|
|
424
|
+
el.nodeValue = newText;
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
function findIndexInParent(parentEl, el) {
|
|
428
|
+
const index = Array.from(parentEl.childNodes).indexOf(el);
|
|
429
|
+
if (index < 0) {
|
|
430
|
+
return null
|
|
431
|
+
}
|
|
432
|
+
return index
|
|
433
|
+
}
|
|
434
|
+
function patchElement(oldVdom, newVdom) {
|
|
435
|
+
const el = oldVdom.el;
|
|
436
|
+
const {
|
|
437
|
+
class : oldClass,
|
|
438
|
+
style : oldStyle,
|
|
439
|
+
on : oldEvents,
|
|
440
|
+
...oldAttrs
|
|
441
|
+
} = oldVdom.props;
|
|
442
|
+
const {
|
|
443
|
+
class : newClass,
|
|
444
|
+
style : newStyle,
|
|
445
|
+
on : newEvents,
|
|
446
|
+
...newAttrs
|
|
447
|
+
} = newVdom.props;
|
|
448
|
+
const { listeners : oldListeners } = oldVdom;
|
|
449
|
+
patchAttrs(el, oldAttrs, newAttrs);
|
|
450
|
+
patchClasses(el, oldClass, newClass);
|
|
451
|
+
patchStyles(el, oldStyle, newStyle);
|
|
452
|
+
newVdom.listeners = patchEvents(el, oldListeners, oldEvents, newEvents);
|
|
453
|
+
}
|
|
454
|
+
function patchAttrs(el, oldAttrs, newAttrs) {
|
|
455
|
+
const { added, removed, updated } = objectsDiff(oldAttrs, newAttrs);
|
|
456
|
+
for (const attr of removed) {
|
|
457
|
+
removeAttributeCustom(el, attr);
|
|
458
|
+
}
|
|
459
|
+
for (const attr of added.concat(updated)) {
|
|
460
|
+
setAttribute(el, attr, newAttrs[attr]);
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
function patchClasses(el, oldClass, newClass) {
|
|
464
|
+
const oldClasses = toClassList(oldClass);
|
|
465
|
+
const newClasses = toClassList(newClass);
|
|
466
|
+
const {added, removed} =
|
|
467
|
+
arraysDiff(oldClasses, newClasses);
|
|
468
|
+
if (removed.length > 0) {
|
|
469
|
+
el.classList.remove(...removed);
|
|
470
|
+
}
|
|
471
|
+
if (added.length > 0) {
|
|
472
|
+
el.classList.add(...added);
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
function toClassList(classes = '') {
|
|
476
|
+
return Array.isArray(classes)
|
|
477
|
+
? classes.filter(isNotBlankOrEmptyString)
|
|
478
|
+
: classes.split(/(\s+)/)
|
|
479
|
+
.filter(isNotBlankOrEmptyString)
|
|
480
|
+
}
|
|
481
|
+
function patchStyles(el, oldStyle = {}, newStyle = {}) {
|
|
482
|
+
const {added, removed, updated } = objectsDiff(oldStyle, newStyle);
|
|
483
|
+
for (const style of removed) {
|
|
484
|
+
removeStyle(el, style);
|
|
485
|
+
}
|
|
486
|
+
for (const style of added.concat(updated)) {
|
|
487
|
+
setStyle(el, style, newStyle[style]);
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
function addEventListener(eventName, handler, el) {
|
|
491
|
+
function boundHandler(event) {
|
|
492
|
+
handler(event);
|
|
493
|
+
}
|
|
494
|
+
el.addEventListener(eventName, boundHandler);
|
|
495
|
+
//!el.addEventListener("click", boundHandler) {
|
|
496
|
+
//! Element: el
|
|
497
|
+
//! Event: "click"
|
|
498
|
+
//! Listener : boundHandler!}
|
|
499
|
+
return boundHandler
|
|
500
|
+
}
|
|
501
|
+
function patchEvents(
|
|
502
|
+
el,
|
|
503
|
+
oldListeners = {},
|
|
504
|
+
oldEvents = {},
|
|
505
|
+
newEvents = {},
|
|
506
|
+
) {
|
|
507
|
+
const { removed, added, updated} =
|
|
508
|
+
objectsDiff(oldEvents, newEvents);
|
|
509
|
+
for (const eventName of removed.concat(updated)) {
|
|
510
|
+
el.removeEventListener(eventName, oldListeners[eventName]);
|
|
511
|
+
}
|
|
512
|
+
const addedListeners = {};
|
|
513
|
+
for (const eventName of added.concat(updated)) {
|
|
514
|
+
const listener =
|
|
515
|
+
addEventListener(eventName, newEvents[eventName], el);
|
|
516
|
+
addedListeners[eventName] = listener;
|
|
517
|
+
}
|
|
518
|
+
return addedListeners
|
|
519
|
+
}
|
|
520
|
+
function extractChildren(vdom) {
|
|
521
|
+
if (vdom.children == null) {
|
|
522
|
+
return []
|
|
523
|
+
}
|
|
524
|
+
const children = [];
|
|
525
|
+
for (const child of vdom.children) {
|
|
526
|
+
if (child.type === DOM_TYPES.FRAGMENT) {
|
|
527
|
+
children.push(...extractChildren(child));
|
|
528
|
+
} else {
|
|
529
|
+
children.push(child);
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
return children
|
|
533
|
+
}
|
|
534
|
+
function patchChildren(oldVdom, newVdom) {
|
|
535
|
+
const oldChildren = extractChildren(oldVdom);
|
|
536
|
+
const newChildren = extractChildren(newVdom);
|
|
537
|
+
const parentEl = oldVdom.el;
|
|
538
|
+
const diffSeq = arraysDiffSequence(oldChildren, newChildren, areNodesEqual);
|
|
539
|
+
for (const operation of diffSeq) {
|
|
540
|
+
const { originalIndex, index, item} = operation;
|
|
541
|
+
switch (operation.op) {
|
|
542
|
+
case ARRAY_DIFF_OP.ADD: {
|
|
543
|
+
mountDom(item, parentEl, index);
|
|
544
|
+
break
|
|
545
|
+
}
|
|
546
|
+
case ARRAY_DIFF_OP.REMOVE: {
|
|
547
|
+
destroyDom(item);
|
|
548
|
+
break
|
|
549
|
+
}
|
|
550
|
+
case ARRAY_DIFF_OP.MOVE: {
|
|
551
|
+
const oldChild = oldChildren[originalIndex];
|
|
552
|
+
const newChild = newChildren[index];
|
|
553
|
+
const el = oldChild.el;
|
|
554
|
+
const elAtTargetIndex = parentEl.childNodes[index];
|
|
555
|
+
parentEl.insertBefore(el, elAtTargetIndex);
|
|
556
|
+
patchDOM(oldChildren[originalIndex], newChild, parentEl);
|
|
557
|
+
break
|
|
558
|
+
}
|
|
559
|
+
case ARRAY_DIFF_OP.NOOP : {
|
|
560
|
+
patchDOM(oldChildren[originalIndex], newChildren[index], parentEl);
|
|
561
|
+
break
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
|
|
227
567
|
function createApp({ state, view, reducers = {} }) {
|
|
228
568
|
let parentEl = null;
|
|
229
569
|
let vdom = null;
|
|
@@ -241,8 +581,8 @@ function createApp({ state, view, reducers = {} }) {
|
|
|
241
581
|
subscriptions.push(subs);
|
|
242
582
|
}
|
|
243
583
|
function renderApp() {
|
|
244
|
-
view(state, emit);
|
|
245
|
-
vdom =
|
|
584
|
+
const newVdom = view(state, emit);
|
|
585
|
+
vdom = patchDOM(vdom, newVdom, parentEl);
|
|
246
586
|
}
|
|
247
587
|
return {
|
|
248
588
|
mount(_parentEl) {
|
|
@@ -262,7 +602,5 @@ function createApp({ state, view, reducers = {} }) {
|
|
|
262
602
|
},
|
|
263
603
|
}
|
|
264
604
|
}
|
|
265
|
-
function patchDom(vdom, newVdom, parentEl) {
|
|
266
|
-
}
|
|
267
605
|
|
|
268
|
-
export { createApp, h, hFragment, hString };
|
|
606
|
+
export { DOM_TYPES, createApp, h, hFragment, hString };
|