lithent 0.36.0 → 0.36.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +27 -22
- package/dist/lithent.mjs +61 -97
- package/dist/lithent.mjs.map +1 -1
- package/dist/lithent.umd.js +1 -1
- package/dist/lithent.umd.js.map +1 -1
- package/dist/render.d.ts +0 -11
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/predicator.d.ts +2 -13
- package/dist/utils/universalRef.d.ts +0 -1
- package/examples/dist/assets/index.f15c0062.js +2 -0
- package/examples/dist/assets/index.f15c0062.js.map +1 -0
- package/examples/dist/index.html +1 -1
- package/package.json +4 -3
- package/src/diff.ts +7 -14
- package/src/render.ts +54 -85
- package/src/utils/index.ts +5 -10
- package/src/utils/predicator.ts +33 -45
- package/src/utils/universalRef.ts +1 -1
- package/examples/dist/assets/index.cf0229da.js +0 -2
- package/examples/dist/assets/index.cf0229da.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,24 +1,26 @@
|
|
|
1
1
|
# lithent
|
|
2
2
|
|
|
3
|
-
>
|
|
3
|
+
> An extensible virtual DOM library for lightweight use in a variety of environments.
|
|
4
4
|
|
|
5
5
|
Lithent were developed to make it easy to insert Virtual DOM component
|
|
6
6
|
fragments into pages already drawn with SSR, and are intended to be
|
|
7
|
-
used lightly
|
|
7
|
+
used lightly in a variety of situations.
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
- https://superlucky84.github.io/lithent
|
|
10
|
+
- (This guide page is written in lithent.)
|
|
11
|
+
|
|
12
|
+
`(9.47 KiB / gzip: 3.49 KiB)`
|
|
11
13
|
|
|
12
|
-
`(9.54 KiB / gzip: 3.54 KiB)`
|
|
13
14
|
|
|
14
15
|
## 🚩 Table of Contents
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
16
|
+
|
|
17
|
+
- [Why Use Lithent](#why-use-lithent)
|
|
18
|
+
- [Basic Guide](#basic-guide)
|
|
19
|
+
- [How To Install](#how-to-install)
|
|
20
|
+
- [With HTM](#with-htm)
|
|
21
|
+
- [With JSX](#with-jsx)
|
|
22
|
+
- [Examples](#examples)
|
|
23
|
+
- [Develop Guide](#develop-guide)
|
|
22
24
|
|
|
23
25
|
## Why use Lithent?
|
|
24
26
|
|
|
@@ -30,31 +32,31 @@ However, in the real world of development, there are times when you need to buil
|
|
|
30
32
|
|
|
31
33
|
Lithent has implemented the bare minimum functionality needed to create and update virtual DOM in general (we only need to know 'render', 'mounter', 'updater', 'renewer', 'mountCallback', and 'updateCallback').
|
|
32
34
|
|
|
33
|
-
We provide code
|
|
34
|
-
|
|
35
|
+
We provide code in the form of 'helpers' that extend the basic functionality, but using the helpers is only optional and talented users can extend and develop custom helpers for their own projects.
|
|
35
36
|
|
|
36
37
|
### Approach with the developer-friendly concept of closures between "component mounter" and "renderer"
|
|
37
38
|
|
|
38
39
|
Many existing UI libraries have their advantages, but they also create rules that are too strong and rigid for fear of users making mistakes.
|
|
39
40
|
|
|
40
|
-
JavaScript users are used to using closures and love to develop with them.
|
|
41
|
-
|
|
42
|
-
"Lithent" provide a familiar approach to real-world JavaScript development because they leverage the properties of higher-order functions and closures in the component mounter to define the properties of the component and get the mounted information from the renderer.
|
|
41
|
+
JavaScript users are used to using closures and love to develop with them.
|
|
43
42
|
|
|
43
|
+
"Lithent" provides a familiar approach to my JavaScript development, as it leverages the properties of higher-order functions and closures to define and recycle the state of a component.
|
|
44
44
|
|
|
45
45
|
## Basic Guide
|
|
46
46
|
|
|
47
|
-
|
|
47
|
+
- https://superlucky84.github.io/lithent/
|
|
48
48
|
|
|
49
49
|
## How To Install
|
|
50
50
|
|
|
51
51
|
```bash
|
|
52
|
-
pnpm add lithent
|
|
52
|
+
pnpm add lithent
|
|
53
53
|
```
|
|
54
54
|
|
|
55
|
+
It's easier to use lithent with JSX or HTM.
|
|
56
|
+
|
|
55
57
|
#### With HTM
|
|
56
58
|
|
|
57
|
-
|
|
59
|
+
- [Htm Github](https://github.com/developit/htm)
|
|
58
60
|
|
|
59
61
|
```bash
|
|
60
62
|
pnpm add -D htm
|
|
@@ -68,11 +70,11 @@ const html = htm.bind(h);
|
|
|
68
70
|
|
|
69
71
|
#### With JSX
|
|
70
72
|
|
|
71
|
-
|
|
73
|
+
- [Setting Guide](https://superlucky84.github.io/lithent/#install)
|
|
72
74
|
|
|
73
75
|
## Examples
|
|
74
76
|
|
|
75
|
-
|
|
77
|
+
- [More Examples](https://superlucky84.github.io/lithent/#examples)
|
|
76
78
|
|
|
77
79
|
```js
|
|
78
80
|
import { h, render, mount, Fragment } from 'lithent';
|
|
@@ -112,6 +114,7 @@ npm install -g pnpm
|
|
|
112
114
|
```
|
|
113
115
|
|
|
114
116
|
### project install
|
|
117
|
+
|
|
115
118
|
```bash
|
|
116
119
|
git clone https://github.com/superlucky84/lithent.git
|
|
117
120
|
|
|
@@ -121,11 +124,13 @@ pnpm install
|
|
|
121
124
|
```
|
|
122
125
|
|
|
123
126
|
### project build
|
|
127
|
+
|
|
124
128
|
```bash
|
|
125
129
|
pnpm build
|
|
126
130
|
```
|
|
127
131
|
|
|
128
132
|
### Running the development environment
|
|
133
|
+
|
|
129
134
|
```bash
|
|
130
135
|
pnpm dev // or pnpm dev:core
|
|
131
136
|
```
|
package/dist/lithent.mjs
CHANGED
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
const checkCustemComponentFunction = (target) => typeof target === "function" && !checkFragmentFunction(target) || typeof target === "object" && "resolve" in target;
|
|
2
|
-
const checkFragmentFunction = (target) => typeof target === "function" && target === Fragment;
|
|
3
1
|
const checkPlainWDomType = (wDom) => typeof wDom === "object" && !("resolve" in wDom);
|
|
4
2
|
const checkPlainType = (wDom, typeName) => checkPlainWDomType(wDom) && wDom.type === typeName;
|
|
5
|
-
const checkEmptyElement = (wDom) => checkPlainWDomType(wDom) && !wDom.type;
|
|
6
3
|
const checkSameCustomComponent = (newWDom, originalWDom) => newWDom.constructor === (originalWDom == null ? void 0 : originalWDom.constructor);
|
|
7
4
|
const checkSameFragment = (newWDom, originalWDom) => {
|
|
8
5
|
var _a, _b;
|
|
@@ -16,24 +13,18 @@ const checkNormalTypeElement = (newWDom, originalWDom) => {
|
|
|
16
13
|
var _a, _b;
|
|
17
14
|
return checkPlainWDomType(newWDom) && (originalWDom == null ? void 0 : originalWDom.type) === newWDom.type && (((_a = originalWDom == null ? void 0 : originalWDom.children) == null ? void 0 : _a.length) === ((_b = newWDom == null ? void 0 : newWDom.children) == null ? void 0 : _b.length) || newWDom.type === "loop");
|
|
18
15
|
};
|
|
16
|
+
const checkCustemComponentFunction = (target) => typeof target === "function" && !checkFragmentFunction(target) || typeof target === "object" && "resolve" in target;
|
|
17
|
+
const checkFragmentFunction = (target) => typeof target === "function" && target === Fragment;
|
|
18
|
+
const checkEmptyElement = (wDom) => checkPlainWDomType(wDom) && !wDom.type;
|
|
19
19
|
const checkExisty = (value) => value !== null && value !== void 0;
|
|
20
20
|
const checkStyleData = (dataKey, dataValue) => dataKey === "style" && typeof dataValue === "object";
|
|
21
21
|
const checkRefData = (dataKey, dataValue) => dataKey === "ref" && typeof dataValue === "object";
|
|
22
|
-
const checkOptionElement = (element) =>
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
const checkTextareaElement = (element) => {
|
|
26
|
-
return element.nodeType === 1 && element.tagName === "TEXTAREA";
|
|
27
|
-
};
|
|
28
|
-
const checkCheckboxElement = (element) => {
|
|
29
|
-
return element.nodeType === 1 && element.type === "checkbox";
|
|
30
|
-
};
|
|
31
|
-
const checkRadioElement = (element) => {
|
|
32
|
-
return element.nodeType === 1 && element.type === "radio";
|
|
33
|
-
};
|
|
22
|
+
const checkOptionElement = (element) => element.nodeType === 1 && element.tagName === "OPTION";
|
|
23
|
+
const checkTextareaElement = (element) => element.nodeType === 1 && element.tagName === "TEXTAREA";
|
|
24
|
+
const checkCheckableElement = (element) => element.nodeType === 1 && ["radio", "checkbox"].includes(element.type);
|
|
34
25
|
const checkNormalAttribute = (dataValue) => typeof dataValue === "number" || typeof dataValue === "string";
|
|
35
26
|
const getWDomType = (wDom) => {
|
|
36
|
-
let result;
|
|
27
|
+
let result = "et";
|
|
37
28
|
if (checkCustemComponentFunction(wDom)) {
|
|
38
29
|
result = "c";
|
|
39
30
|
} else if (checkPlainType(wDom, "fragment")) {
|
|
@@ -59,9 +50,6 @@ const checkSameWDomWithOriginal = {
|
|
|
59
50
|
};
|
|
60
51
|
const getParent = (vDom) => {
|
|
61
52
|
const parentVDom = vDom.getParent && vDom.getParent();
|
|
62
|
-
if (!parentVDom) {
|
|
63
|
-
throw Error("Not found parent vDom");
|
|
64
|
-
}
|
|
65
53
|
return parentVDom;
|
|
66
54
|
};
|
|
67
55
|
const reRender = (vDom, infoVdom) => {
|
|
@@ -74,11 +62,9 @@ const reRender = (vDom, infoVdom) => {
|
|
|
74
62
|
updateChildren(children, infoChidren);
|
|
75
63
|
}
|
|
76
64
|
const newVDom = vDom.reRender && vDom.reRender();
|
|
77
|
-
if (!newVDom) {
|
|
78
|
-
throw Error("Unable reRender");
|
|
79
|
-
}
|
|
80
65
|
return newVDom;
|
|
81
66
|
};
|
|
67
|
+
const getEventName = (eventKey) => eventKey.replace(/^on(.*)/, (_match, p1) => p1.toLowerCase());
|
|
82
68
|
const updateProps$1 = (props, infoProps) => {
|
|
83
69
|
if (props && infoProps !== props) {
|
|
84
70
|
Object.keys(props).forEach((key) => delete props[key]);
|
|
@@ -260,12 +246,10 @@ const runUpdatedQueueFromWDom = (newWDom) => {
|
|
|
260
246
|
};
|
|
261
247
|
const checkNeedPushQueue = (originalDefs, newDefs) => !originalDefs.length && !originalDefs.length ? true : originalDefs.some((def, index) => def !== newDefs[index]);
|
|
262
248
|
const render = (wDom, wrapElement, afterElement) => {
|
|
263
|
-
|
|
264
|
-
throw Error("WrapELement is null");
|
|
265
|
-
}
|
|
249
|
+
wrapElement != null ? wrapElement : wrapElement = document.body;
|
|
266
250
|
wDom.isRoot = true;
|
|
267
251
|
wDom.wrapElement = wrapElement;
|
|
268
|
-
const Dom = wDomToDom(wDom
|
|
252
|
+
const Dom = wDomToDom(wDom);
|
|
269
253
|
if (afterElement) {
|
|
270
254
|
wDom.afterElement = afterElement;
|
|
271
255
|
wrapElement.insertBefore(Dom, afterElement);
|
|
@@ -287,15 +271,14 @@ const render = (wDom, wrapElement, afterElement) => {
|
|
|
287
271
|
const wDomUpdate = (newWDomTree) => {
|
|
288
272
|
const { needRerender } = newWDomTree;
|
|
289
273
|
if (needRerender && needRerender !== "N") {
|
|
290
|
-
|
|
274
|
+
({
|
|
291
275
|
A: typeAdd,
|
|
292
276
|
D: typeDelete,
|
|
293
277
|
R: typeReplace,
|
|
294
278
|
U: typeUpdate,
|
|
295
279
|
SR: typeSortedReplace,
|
|
296
280
|
SU: typeSortedUpdate
|
|
297
|
-
}[needRerender];
|
|
298
|
-
exec(newWDomTree);
|
|
281
|
+
})[needRerender](newWDomTree);
|
|
299
282
|
}
|
|
300
283
|
};
|
|
301
284
|
const recursiveRemoveEvent = (originalWDom) => {
|
|
@@ -307,16 +290,16 @@ const recursiveRemoveEvent = (originalWDom) => {
|
|
|
307
290
|
});
|
|
308
291
|
};
|
|
309
292
|
const rootDelete = (newWDom) => {
|
|
310
|
-
|
|
311
|
-
deleteRealDom(newWDom, parent);
|
|
293
|
+
deleteRealDom(newWDom, newWDom.wrapElement);
|
|
312
294
|
};
|
|
313
295
|
const typeDelete = (newWDom) => {
|
|
314
|
-
const parentWDom = getParent(newWDom);
|
|
315
|
-
const parent = findRealParentElement(parentWDom);
|
|
316
296
|
if (newWDom.oldProps && newWDom.el) {
|
|
317
297
|
removeEvent(newWDom.oldProps, newWDom.el);
|
|
318
298
|
}
|
|
319
|
-
deleteRealDom(
|
|
299
|
+
deleteRealDom(
|
|
300
|
+
newWDom,
|
|
301
|
+
findRealParentElement(getParent(newWDom))
|
|
302
|
+
);
|
|
320
303
|
};
|
|
321
304
|
const deleteRealDom = (newWDom, parent) => {
|
|
322
305
|
var _a, _b;
|
|
@@ -349,18 +332,13 @@ const typeSortedUpdate = (newWDom) => {
|
|
|
349
332
|
};
|
|
350
333
|
const typeAdd = (newWDom, newElement) => {
|
|
351
334
|
if (!newElement) {
|
|
352
|
-
newElement = wDomToDom(newWDom
|
|
335
|
+
newElement = wDomToDom(newWDom);
|
|
353
336
|
}
|
|
354
337
|
const parentWDom = getParent(newWDom);
|
|
355
338
|
if (parentWDom.type) {
|
|
356
339
|
const parentEl = findRealParentElement(parentWDom);
|
|
357
340
|
const isLoop = parentWDom.type === "loop";
|
|
358
|
-
|
|
359
|
-
if (isLoop) {
|
|
360
|
-
nextEl = startFindNextBrotherElement(parentWDom, getParent(parentWDom));
|
|
361
|
-
} else {
|
|
362
|
-
nextEl = startFindNextBrotherElement(newWDom, parentWDom);
|
|
363
|
-
}
|
|
341
|
+
const nextEl = isLoop ? startFindNextBrotherElement(parentWDom, getParent(parentWDom)) : startFindNextBrotherElement(newWDom, parentWDom);
|
|
364
342
|
if (newElement && parentEl) {
|
|
365
343
|
if (nextEl) {
|
|
366
344
|
parentEl.insertBefore(newElement, nextEl);
|
|
@@ -412,7 +390,7 @@ const typeReplace = (newWDom) => {
|
|
|
412
390
|
typeSortedReplace(newWDom);
|
|
413
391
|
} else {
|
|
414
392
|
const parentElement = findRealParentElement(parentWDom);
|
|
415
|
-
const newElement = wDomToDom(newWDom
|
|
393
|
+
const newElement = wDomToDom(newWDom);
|
|
416
394
|
if (parentElement) {
|
|
417
395
|
parentElement.replaceChild(newElement, orignalElement);
|
|
418
396
|
}
|
|
@@ -421,22 +399,16 @@ const typeReplace = (newWDom) => {
|
|
|
421
399
|
runMountedQueueFromWDom(newWDom);
|
|
422
400
|
};
|
|
423
401
|
const removeEvent = (oldProps, element) => {
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
(
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
);
|
|
432
|
-
element.removeEventListener(
|
|
433
|
-
eventName,
|
|
434
|
-
dataValue
|
|
435
|
-
);
|
|
436
|
-
}
|
|
402
|
+
Object.entries(oldProps || {}).forEach(
|
|
403
|
+
([dataKey, dataValue]) => {
|
|
404
|
+
if (dataKey.match(/^on/)) {
|
|
405
|
+
element.removeEventListener(
|
|
406
|
+
getEventName(dataKey),
|
|
407
|
+
dataValue
|
|
408
|
+
);
|
|
437
409
|
}
|
|
438
|
-
|
|
439
|
-
|
|
410
|
+
}
|
|
411
|
+
);
|
|
440
412
|
};
|
|
441
413
|
const typeUpdate = (newWDom) => {
|
|
442
414
|
var _a;
|
|
@@ -471,9 +443,11 @@ const updateProps = (props, element, oldProps) => {
|
|
|
471
443
|
else if (dataKey === "innerHTML" && element && typeof dataValue === "string") {
|
|
472
444
|
element.innerHTML = dataValue;
|
|
473
445
|
} else if (checkStyleData(dataKey, dataValue)) {
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
446
|
+
updateStyle(
|
|
447
|
+
dataValue,
|
|
448
|
+
checkStyleData(dataKey, originalProps.style) ? originalProps.style : {},
|
|
449
|
+
element
|
|
450
|
+
);
|
|
477
451
|
} else if (checkRefData(dataKey, dataValue)) {
|
|
478
452
|
dataValue.value = element;
|
|
479
453
|
} else if (dataKey.match(/^on/)) {
|
|
@@ -483,9 +457,7 @@ const updateProps = (props, element, oldProps) => {
|
|
|
483
457
|
dataValue,
|
|
484
458
|
originalProps[dataKey]
|
|
485
459
|
);
|
|
486
|
-
} else if (
|
|
487
|
-
element.checked = !!dataValue;
|
|
488
|
-
} else if (checkCheckboxElement(element) && dataKey === "checked") {
|
|
460
|
+
} else if (checkCheckableElement(element) && dataKey === "checked") {
|
|
489
461
|
element.checked = !!dataValue;
|
|
490
462
|
} else if (checkTextareaElement(element) && dataKey === "value") {
|
|
491
463
|
element.value = dataValue;
|
|
@@ -501,7 +473,7 @@ const updateProps = (props, element, oldProps) => {
|
|
|
501
473
|
(dataKey) => element.removeAttribute(dataKey)
|
|
502
474
|
);
|
|
503
475
|
};
|
|
504
|
-
const wDomToDom = (wDom
|
|
476
|
+
const wDomToDom = (wDom) => {
|
|
505
477
|
let element;
|
|
506
478
|
const { type, tag, text, props, children = [] } = wDom;
|
|
507
479
|
const isVirtualType = type === "fragment" || type === "loop";
|
|
@@ -511,34 +483,31 @@ const wDomToDom = (wDom, init) => {
|
|
|
511
483
|
element = document.createElement(tag);
|
|
512
484
|
} else if (type === "text" && checkExisty(text)) {
|
|
513
485
|
element = document.createTextNode(String(text));
|
|
486
|
+
} else {
|
|
487
|
+
element = document.createElement("e");
|
|
514
488
|
}
|
|
515
|
-
wDomChildrenToDom(children, element
|
|
489
|
+
wDomChildrenToDom(children, element);
|
|
516
490
|
updateProps(props, element);
|
|
517
491
|
wDom.el = element;
|
|
518
492
|
runMountedQueueFromWDom(wDom);
|
|
519
|
-
return element
|
|
520
|
-
};
|
|
521
|
-
const wDomChildrenToDom = (children, parentElement
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
(
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
parentElement.appendChild(elementChildren);
|
|
534
|
-
}
|
|
493
|
+
return element;
|
|
494
|
+
};
|
|
495
|
+
const wDomChildrenToDom = (children, parentElement) => {
|
|
496
|
+
const elementChildren = children.reduce(
|
|
497
|
+
(acc, childItem) => {
|
|
498
|
+
if (childItem.type) {
|
|
499
|
+
acc.appendChild(wDomToDom(childItem));
|
|
500
|
+
}
|
|
501
|
+
return acc;
|
|
502
|
+
},
|
|
503
|
+
new DocumentFragment()
|
|
504
|
+
);
|
|
505
|
+
if (parentElement && elementChildren.hasChildNodes()) {
|
|
506
|
+
parentElement.appendChild(elementChildren);
|
|
535
507
|
}
|
|
536
508
|
};
|
|
537
509
|
const updateEvent = (element, eventKey, newEventHandler, oldEventHandler) => {
|
|
538
|
-
const eventName = eventKey
|
|
539
|
-
/^on(.*)/,
|
|
540
|
-
(_match, p1) => p1.toLowerCase()
|
|
541
|
-
);
|
|
510
|
+
const eventName = getEventName(eventKey);
|
|
542
511
|
if (oldEventHandler !== newEventHandler) {
|
|
543
512
|
if (oldEventHandler) {
|
|
544
513
|
element.removeEventListener(eventName, oldEventHandler);
|
|
@@ -569,18 +538,13 @@ const findRealParentElement = (vDom) => {
|
|
|
569
538
|
if (!isVirtualType) {
|
|
570
539
|
return vDom.el;
|
|
571
540
|
}
|
|
572
|
-
|
|
573
|
-
return findRealParentElement(parentVDom);
|
|
574
|
-
};
|
|
575
|
-
const makeNewWDomTree = (newWDom, originalWDom) => {
|
|
576
|
-
const type = getWDomType(newWDom);
|
|
577
|
-
if (!type) {
|
|
578
|
-
throw new Error("Unknown type wdom");
|
|
579
|
-
}
|
|
580
|
-
const isSameType = checkSameWDomWithOriginal[type](newWDom, originalWDom);
|
|
581
|
-
const result = remakeNewWDom(newWDom, isSameType, originalWDom);
|
|
582
|
-
return result;
|
|
541
|
+
return findRealParentElement(getParent(vDom));
|
|
583
542
|
};
|
|
543
|
+
const makeNewWDomTree = (newWDom, originalWDom) => remakeNewWDom(
|
|
544
|
+
newWDom,
|
|
545
|
+
checkSameWDomWithOriginal[getWDomType(newWDom)](newWDom, originalWDom),
|
|
546
|
+
originalWDom
|
|
547
|
+
);
|
|
584
548
|
const remakeNewWDom = (newWDom, isSameType, originalWDom) => {
|
|
585
549
|
const remakeWDom = generalize(newWDom, isSameType, originalWDom);
|
|
586
550
|
remakeWDom.children = remakeChildrenForDiff(
|
|
@@ -659,7 +623,7 @@ const remakeChildrenForLoopUpdate = (newWDom, originalWDom) => {
|
|
|
659
623
|
);
|
|
660
624
|
unUsedChildren.map((unusedItem) => {
|
|
661
625
|
const el = unusedItem.el;
|
|
662
|
-
if (el
|
|
626
|
+
if (el == null ? void 0 : el.parentNode) {
|
|
663
627
|
el.parentNode.removeChild(el);
|
|
664
628
|
}
|
|
665
629
|
});
|