lithent 1.0.0 → 1.0.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 +28 -17
- package/dist/lithent.mjs +135 -140
- package/dist/lithent.mjs.map +1 -1
- package/dist/lithent.umd.js +1 -1
- package/dist/lithent.umd.js.map +1 -1
- package/dist/types/index.d.ts +6 -6
- package/dist/utils/index.d.ts +16 -0
- package/dist/utils/predicator.d.ts +1 -0
- package/dist/utils/universalRef.d.ts +6 -6
- package/dist/wDom.d.ts +2 -2
- package/examples/dist/assets/index.1e9792b7.js +2 -0
- package/examples/dist/assets/index.1e9792b7.js.map +1 -0
- package/examples/dist/index.html +1 -1
- package/examples/src/index.tsx +1 -1
- package/examples/src/sharedStore.tsx +1 -1
- package/package.json +3 -2
- package/src/diff.ts +22 -24
- package/src/hook/mountCallback.ts +6 -6
- package/src/hook/unmount.ts +7 -7
- package/src/hook/useUpdate.ts +6 -6
- package/src/render.ts +51 -57
- package/src/tests/fragment.tsx +38 -0
- package/src/tests/loopWithoutKey.tsx +55 -0
- package/src/tests/{example17.tsx → test17.tsx} +1 -1
- package/src/types/index.ts +6 -6
- package/src/utils/index.ts +7 -5
- package/src/utils/predicator.ts +10 -2
- package/src/utils/universalRef.ts +23 -28
- package/src/wDom.ts +25 -30
- package/examples/dist/assets/index.2b484d3b.js +0 -2
- package/examples/dist/assets/index.2b484d3b.js.map +0 -1
- /package/src/tests/{example1.tsx → test1.tsx} +0 -0
- /package/src/tests/{example10.tsx → test10.tsx} +0 -0
- /package/src/tests/{example11.tsx → test11.tsx} +0 -0
- /package/src/tests/{example12.tsx → test12.tsx} +0 -0
- /package/src/tests/{example13.tsx → test13.tsx} +0 -0
- /package/src/tests/{example14.tsx → test14.tsx} +0 -0
- /package/src/tests/{example15.tsx → test15.tsx} +0 -0
- /package/src/tests/{example16.tsx → test16.tsx} +0 -0
- /package/src/tests/{example2.tsx → test2.tsx} +0 -0
- /package/src/tests/{example3.tsx → test3.tsx} +0 -0
- /package/src/tests/{example4.tsx → test4.tsx} +0 -0
- /package/src/tests/{example5.tsx → test5.tsx} +0 -0
- /package/src/tests/{example6.tsx → test6.tsx} +0 -0
- /package/src/tests/{example7.tsx → test7.tsx} +0 -0
- /package/src/tests/{example8.tsx → test8.tsx} +0 -0
- /package/src/tests/{example9.tsx → test9.tsx} +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lithent",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "An extensible virtual DOM library for lightweight use in a variety of environments.",
|
|
5
5
|
"packageManager": "pnpm@7.6.0",
|
|
6
6
|
"main": "./dist/lithent.umd.js",
|
|
@@ -17,7 +17,8 @@
|
|
|
17
17
|
"build": "pnpm build:core && pnpm build:helper && pnpm build:examples && pnpm build:docs",
|
|
18
18
|
"build:p": "pnpm build:core && pnpm -r build",
|
|
19
19
|
"dev": "pnpm watch:core & pnpm watch:helper & pnpm dev:examples",
|
|
20
|
-
"test": "vitest",
|
|
20
|
+
"test": "vitest run --reporter verbose",
|
|
21
|
+
"test:dev": "vitest",
|
|
21
22
|
"coverage": "vitest run --coverage",
|
|
22
23
|
"clean": "pnpm clean:dist && pnpm clean:module",
|
|
23
24
|
"clean:dist": "pnpm -r exec rm -rf dist && rm -rf dist",
|
package/src/diff.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { WDom, TagFunctionResolver, RenderType } from '@/types';
|
|
2
|
-
import { checkCustemComponentFunction } from '@/utils/predicator';
|
|
2
|
+
import { checkCustemComponentFunction, getKey } from '@/utils/predicator';
|
|
3
3
|
import { getParent, reRender } from '@/utils';
|
|
4
4
|
import { recursiveRemoveEvent } from '@/render';
|
|
5
5
|
import {
|
|
@@ -27,38 +27,39 @@ const remakeNewWDom = (
|
|
|
27
27
|
originalWDom?: WDom
|
|
28
28
|
) => {
|
|
29
29
|
const remakeWDom = generalize(newWDom, isSameType, originalWDom);
|
|
30
|
-
|
|
31
|
-
remakeWDom.children = remakeChildrenForDiff(
|
|
32
|
-
remakeWDom,
|
|
33
|
-
isSameType,
|
|
34
|
-
originalWDom
|
|
35
|
-
);
|
|
36
|
-
|
|
37
|
-
const needRerender = addReRenderTypeProperty(
|
|
30
|
+
const param: [newWDom: WDom, isSameType: boolean, originalWDom?: WDom] = [
|
|
38
31
|
remakeWDom,
|
|
39
32
|
isSameType,
|
|
40
|
-
originalWDom
|
|
41
|
-
|
|
33
|
+
originalWDom,
|
|
34
|
+
];
|
|
35
|
+
const needRerender = addReRenderTypeProperty(...param);
|
|
42
36
|
|
|
37
|
+
remakeWDom.children = remakeChildrenForDiff(...param);
|
|
43
38
|
remakeWDom.needRerender = needRerender;
|
|
44
39
|
|
|
40
|
+
inheritPropForRender(remakeWDom, originalWDom, needRerender);
|
|
41
|
+
|
|
42
|
+
return remakeWDom;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
const inheritPropForRender = (
|
|
46
|
+
remakeWDom: WDom,
|
|
47
|
+
originalWDom?: WDom,
|
|
48
|
+
needRerender?: RenderType
|
|
49
|
+
) => {
|
|
45
50
|
if (needRerender !== 'A' && originalWDom) {
|
|
46
51
|
remakeWDom.el = originalWDom.el;
|
|
47
52
|
}
|
|
48
53
|
|
|
49
|
-
if (
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
recursiveRemoveEvent(originalWDom);
|
|
56
|
-
remakeWDom.oldChildren = originalWDom.children;
|
|
54
|
+
if (needRerender && ['D', 'R', 'SR'].includes(needRerender)) {
|
|
55
|
+
if (originalWDom?.compKey) {
|
|
56
|
+
runUnmountQueueFromWDom(originalWDom);
|
|
57
|
+
recursiveRemoveEvent(originalWDom);
|
|
58
|
+
}
|
|
59
|
+
remakeWDom.oldChildren = originalWDom?.children;
|
|
57
60
|
}
|
|
58
61
|
|
|
59
62
|
remakeWDom.oldProps = originalWDom?.props;
|
|
60
|
-
|
|
61
|
-
return remakeWDom;
|
|
62
63
|
};
|
|
63
64
|
|
|
64
65
|
const addReRenderTypeProperty = (
|
|
@@ -185,6 +186,3 @@ const findSameKeyOriginalItem = (item: WDom, originalChildren: WDom[]) =>
|
|
|
185
186
|
originalChildren.find(
|
|
186
187
|
orignalChildItem => getKey(orignalChildItem) === getKey(item)
|
|
187
188
|
);
|
|
188
|
-
|
|
189
|
-
const getKey = (target: WDom) =>
|
|
190
|
-
target?.componentProps?.key ?? target?.props?.key;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { WDom } from '@/types';
|
|
2
2
|
import {
|
|
3
|
-
|
|
3
|
+
compKeyRef,
|
|
4
4
|
componentRef,
|
|
5
5
|
getComponentKey,
|
|
6
6
|
} from '@/utils/universalRef';
|
|
@@ -13,7 +13,7 @@ export const execMountedQueue = () => {
|
|
|
13
13
|
mountedQueue = [];
|
|
14
14
|
};
|
|
15
15
|
export const addMountedQueue = (wDom: WDom) => {
|
|
16
|
-
if (wDom.
|
|
16
|
+
if (wDom.compKey) {
|
|
17
17
|
mountedQueue.push(wDom);
|
|
18
18
|
}
|
|
19
19
|
};
|
|
@@ -21,14 +21,14 @@ export const mountCallback = (effectAction: () => void) =>
|
|
|
21
21
|
componentRef.get(getComponentKey())!.mts.push(effectAction);
|
|
22
22
|
|
|
23
23
|
export const runMountedQueueFromWDom = (newWDom: WDom) => {
|
|
24
|
-
const {
|
|
24
|
+
const { compKey } = newWDom;
|
|
25
25
|
|
|
26
|
-
if (
|
|
27
|
-
const component = componentRef.get(
|
|
26
|
+
if (compKey) {
|
|
27
|
+
const component = componentRef.get(compKey);
|
|
28
28
|
const queue = component?.mts;
|
|
29
29
|
const sequence = component?.upS;
|
|
30
30
|
|
|
31
|
-
|
|
31
|
+
compKeyRef.value = compKey;
|
|
32
32
|
|
|
33
33
|
if (sequence) {
|
|
34
34
|
sequence.value = 0;
|
package/src/hook/unmount.ts
CHANGED
|
@@ -6,17 +6,17 @@ export const unmount = (effectAction: () => void) => {
|
|
|
6
6
|
};
|
|
7
7
|
|
|
8
8
|
export const runUnmountQueueFromWDom = (newWDom: WDom) => {
|
|
9
|
-
const {
|
|
9
|
+
const { compKey } = newWDom;
|
|
10
10
|
|
|
11
|
-
if (
|
|
12
|
-
removeItem(
|
|
11
|
+
if (compKey) {
|
|
12
|
+
removeItem(compKey);
|
|
13
13
|
}
|
|
14
14
|
recursiveRunUnmount(newWDom);
|
|
15
15
|
};
|
|
16
16
|
|
|
17
17
|
const recursiveRunUnmount = (wDom: WDom) => {
|
|
18
18
|
(wDom.children || []).forEach(item => {
|
|
19
|
-
const childComKey = item.
|
|
19
|
+
const childComKey = item.compKey;
|
|
20
20
|
if (childComKey) {
|
|
21
21
|
runUnmountQueueFromWDom(item);
|
|
22
22
|
} else {
|
|
@@ -25,11 +25,11 @@ const recursiveRunUnmount = (wDom: WDom) => {
|
|
|
25
25
|
});
|
|
26
26
|
};
|
|
27
27
|
|
|
28
|
-
const removeItem = (
|
|
29
|
-
const subInfo = componentRef.get(
|
|
28
|
+
const removeItem = (compKey: Props) => {
|
|
29
|
+
const subInfo = componentRef.get(compKey);
|
|
30
30
|
if (subInfo) {
|
|
31
31
|
subInfo!.umts.forEach(effect => effect());
|
|
32
32
|
subInfo!.umts = [];
|
|
33
|
-
componentRef.delete(
|
|
33
|
+
componentRef.delete(compKey);
|
|
34
34
|
}
|
|
35
35
|
};
|
package/src/hook/useUpdate.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { WDom } from '@/types';
|
|
2
2
|
import {
|
|
3
|
-
|
|
3
|
+
compKeyRef,
|
|
4
4
|
componentRef,
|
|
5
5
|
getComponentKey,
|
|
6
6
|
} from '@/utils/universalRef';
|
|
@@ -25,20 +25,20 @@ export const useUpdated = (
|
|
|
25
25
|
};
|
|
26
26
|
|
|
27
27
|
export const runUpdatedQueueFromWDom = (newWDom: WDom) => {
|
|
28
|
-
const {
|
|
28
|
+
const { compKey } = newWDom;
|
|
29
29
|
|
|
30
|
-
if (
|
|
31
|
-
const component = componentRef.get(
|
|
30
|
+
if (compKey) {
|
|
31
|
+
const component = componentRef.get(compKey);
|
|
32
32
|
const queue = component?.upCB;
|
|
33
33
|
const sequence = component?.upS;
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
compKeyRef.value = compKey;
|
|
36
36
|
|
|
37
37
|
if (sequence) {
|
|
38
38
|
sequence.value = 0;
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
if (newWDom.
|
|
41
|
+
if (newWDom.ctor && queue) {
|
|
42
42
|
component.upCB = [];
|
|
43
43
|
queue.forEach((effect: Function) => effect());
|
|
44
44
|
}
|
package/src/render.ts
CHANGED
|
@@ -14,7 +14,7 @@ import { componentRef, xmlnsRef } from '@/utils/universalRef';
|
|
|
14
14
|
import { runUnmountQueueFromWDom } from '@/hook/unmount';
|
|
15
15
|
import { execMountedQueue, addMountedQueue } from '@/hook/mountCallback';
|
|
16
16
|
import { runUpdatedQueueFromWDom } from '@/hook/useUpdate';
|
|
17
|
-
import { getParent, getEventName, getAttrKey } from '@/utils';
|
|
17
|
+
import { getParent, getEventName, getAttrKey, entries, keys } from '@/utils';
|
|
18
18
|
|
|
19
19
|
export const render = (
|
|
20
20
|
wDom: WDom,
|
|
@@ -37,7 +37,7 @@ export const render = (
|
|
|
37
37
|
execMountedQueue();
|
|
38
38
|
|
|
39
39
|
return () => {
|
|
40
|
-
const component = componentRef.get(wDom.
|
|
40
|
+
const component = componentRef.get(wDom.compProps || {})?.vd.value;
|
|
41
41
|
if (component) {
|
|
42
42
|
runUnmountQueueFromWDom(component);
|
|
43
43
|
recursiveRemoveEvent(component);
|
|
@@ -218,16 +218,14 @@ const removeEvent = (
|
|
|
218
218
|
oldProps: Props,
|
|
219
219
|
element: HTMLElement | DocumentFragment | Text
|
|
220
220
|
) => {
|
|
221
|
-
|
|
222
|
-
(
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
);
|
|
228
|
-
}
|
|
221
|
+
entries(oldProps || {}).forEach(([dataKey, dataValue]: [string, unknown]) => {
|
|
222
|
+
if (dataKey.match(/^on/)) {
|
|
223
|
+
element.removeEventListener(
|
|
224
|
+
getEventName(dataKey),
|
|
225
|
+
dataValue as (e: Event) => void
|
|
226
|
+
);
|
|
229
227
|
}
|
|
230
|
-
);
|
|
228
|
+
});
|
|
231
229
|
};
|
|
232
230
|
|
|
233
231
|
const typeUpdate = (newWDom: WDom) => {
|
|
@@ -271,55 +269,51 @@ const updateProps = (
|
|
|
271
269
|
) => {
|
|
272
270
|
const originalProps = { ...oldProps };
|
|
273
271
|
|
|
274
|
-
|
|
275
|
-
(
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
272
|
+
entries(props || {}).forEach(([dataKey, dataValue]: [string, unknown]) => {
|
|
273
|
+
if (dataKey === 'key') {
|
|
274
|
+
// Do nothing
|
|
275
|
+
} else if (dataKey === 'innerHTML' && typeof dataValue === 'string') {
|
|
276
|
+
(element as HTMLElement).innerHTML = dataValue;
|
|
277
|
+
} else if (checkStyleData(dataKey, dataValue)) {
|
|
278
|
+
updateStyle(
|
|
279
|
+
dataValue,
|
|
280
|
+
checkStyleData(dataKey, originalProps.style) ? originalProps.style : {},
|
|
281
|
+
element
|
|
282
|
+
);
|
|
283
|
+
} else if (checkRefData(dataKey, dataValue)) {
|
|
284
|
+
dataValue.value = element;
|
|
285
|
+
} else if (dataKey.match(/^on/)) {
|
|
286
|
+
updateEvent(
|
|
287
|
+
element as HTMLElement,
|
|
288
|
+
dataKey,
|
|
289
|
+
dataValue as (e: Event) => void,
|
|
290
|
+
originalProps[dataKey] as (e: Event) => void
|
|
291
|
+
);
|
|
292
|
+
} else if (checkCheckableElement(element) && dataKey === 'checked') {
|
|
293
|
+
(element as HTMLInputElement).checked = !!dataValue;
|
|
294
|
+
} else if (checkTextareaElement(element) && dataKey === 'value') {
|
|
295
|
+
(element as HTMLInputElement).value = dataValue as string;
|
|
296
|
+
} else if (checkOptionElement(element) && dataKey === 'selected') {
|
|
297
|
+
(element as HTMLOptionElement).selected = !!dataValue;
|
|
298
|
+
} else if (checkNormalAttribute(dataValue)) {
|
|
299
|
+
if (xmlnsRef.value && dataKey !== 'xmlns') {
|
|
300
|
+
(element as HTMLElement).setAttributeNS(
|
|
301
|
+
null,
|
|
302
|
+
getAttrKey(dataKey),
|
|
303
|
+
String(dataValue)
|
|
287
304
|
);
|
|
288
|
-
} else
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
element as HTMLElement,
|
|
293
|
-
dataKey,
|
|
294
|
-
dataValue as (e: Event) => void,
|
|
295
|
-
originalProps[dataKey] as (e: Event) => void
|
|
305
|
+
} else {
|
|
306
|
+
(element as HTMLElement).setAttribute(
|
|
307
|
+
getAttrKey(dataKey),
|
|
308
|
+
String(dataValue)
|
|
296
309
|
);
|
|
297
|
-
} else if (checkCheckableElement(element) && dataKey === 'checked') {
|
|
298
|
-
(element as HTMLInputElement).checked = !!dataValue;
|
|
299
|
-
} else if (checkTextareaElement(element) && dataKey === 'value') {
|
|
300
|
-
(element as HTMLInputElement).value = dataValue as string;
|
|
301
|
-
} else if (checkOptionElement(element) && dataKey === 'selected') {
|
|
302
|
-
(element as HTMLOptionElement).selected = !!dataValue;
|
|
303
|
-
} else if (checkNormalAttribute(dataValue)) {
|
|
304
|
-
if (xmlnsRef.value && dataKey !== 'xmlns') {
|
|
305
|
-
(element as HTMLElement).setAttributeNS(
|
|
306
|
-
null,
|
|
307
|
-
getAttrKey(dataKey),
|
|
308
|
-
String(dataValue)
|
|
309
|
-
);
|
|
310
|
-
} else {
|
|
311
|
-
(element as HTMLElement).setAttribute(
|
|
312
|
-
getAttrKey(dataKey),
|
|
313
|
-
String(dataValue)
|
|
314
|
-
);
|
|
315
|
-
}
|
|
316
310
|
}
|
|
317
|
-
|
|
318
|
-
delete originalProps[dataKey];
|
|
319
311
|
}
|
|
320
|
-
);
|
|
321
312
|
|
|
322
|
-
|
|
313
|
+
delete originalProps[dataKey];
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
keys(originalProps).forEach(dataKey =>
|
|
323
317
|
(element as HTMLElement).removeAttribute(dataKey)
|
|
324
318
|
);
|
|
325
319
|
};
|
|
@@ -407,12 +401,12 @@ const updateStyle = (
|
|
|
407
401
|
const elementStyle = (element as HTMLElement)?.style;
|
|
408
402
|
|
|
409
403
|
if (elementStyle) {
|
|
410
|
-
|
|
404
|
+
entries(style).forEach(([styleKey, dataValue]) => {
|
|
411
405
|
(elementStyle as any)[styleKey] = dataValue;
|
|
412
406
|
delete originalStyle[styleKey];
|
|
413
407
|
});
|
|
414
408
|
|
|
415
|
-
|
|
409
|
+
entries(originalStyle).forEach(
|
|
416
410
|
([styleKey]) => ((elementStyle as any)[styleKey] = '')
|
|
417
411
|
);
|
|
418
412
|
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { mount, render, Fragment, h } from '@/index';
|
|
2
|
+
|
|
3
|
+
const Loop = mount(function (renew) {
|
|
4
|
+
let pType: boolean = true;
|
|
5
|
+
const handle = () => {
|
|
6
|
+
pType = false;
|
|
7
|
+
renew();
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
return () => (
|
|
11
|
+
<div>
|
|
12
|
+
<button onClick={handle}>handle</button>
|
|
13
|
+
<div>start</div>
|
|
14
|
+
{pType ? (
|
|
15
|
+
<Fragment>
|
|
16
|
+
<div>1</div>
|
|
17
|
+
<div>2</div>
|
|
18
|
+
<div>3</div>
|
|
19
|
+
<div>4</div>
|
|
20
|
+
</Fragment>
|
|
21
|
+
) : (
|
|
22
|
+
<Fragment>
|
|
23
|
+
<div>two</div>
|
|
24
|
+
<div>three</div>
|
|
25
|
+
<div>four</div>
|
|
26
|
+
</Fragment>
|
|
27
|
+
)}
|
|
28
|
+
<div>end</div>
|
|
29
|
+
</div>
|
|
30
|
+
);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
const Root = <Loop />;
|
|
34
|
+
|
|
35
|
+
//@ts-ignore
|
|
36
|
+
window.root = Root;
|
|
37
|
+
|
|
38
|
+
render(Root, document.getElementById('root'));
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { mount, render, Fragment, ref, h, nextTick } from '@/index';
|
|
2
|
+
const testChangeRef = ref<null | (() => void)>(null);
|
|
3
|
+
|
|
4
|
+
const Loop = mount(function (renew) {
|
|
5
|
+
let list: { value: string }[] = [
|
|
6
|
+
{ value: '일' },
|
|
7
|
+
{ value: '이' },
|
|
8
|
+
{ value: '삼' },
|
|
9
|
+
{ value: '사' },
|
|
10
|
+
];
|
|
11
|
+
const handle = () => {
|
|
12
|
+
list = [{ value: '사사' }, { value: '삼삼' }, { value: '이이' }];
|
|
13
|
+
renew();
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
testChangeRef.value = () => {
|
|
17
|
+
handle();
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
return () => (
|
|
21
|
+
<Fragment>
|
|
22
|
+
<button onClick={handle}>handle</button>
|
|
23
|
+
<div>first</div>
|
|
24
|
+
{list.map(item => (
|
|
25
|
+
<div>{item.value}</div>
|
|
26
|
+
))}
|
|
27
|
+
<div>end</div>
|
|
28
|
+
</Fragment>
|
|
29
|
+
);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
const testWrap =
|
|
33
|
+
document.getElementById('root') || document.createElement('div');
|
|
34
|
+
|
|
35
|
+
render(<Loop />, testWrap);
|
|
36
|
+
|
|
37
|
+
if (import.meta.vitest) {
|
|
38
|
+
const { it, expect } = import.meta.vitest;
|
|
39
|
+
it('It should be reflected in the DOM exactly in the order of the loop initialization.', () => {
|
|
40
|
+
expect(testWrap.outerHTML).toBe(
|
|
41
|
+
'<div><button>handle</button><div>first</div><div>일</div><div>이</div><div>삼</div><div>사</div><div>end</div></div>'
|
|
42
|
+
);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it('Even if there are no keys in the loop, "replace" should be reflected correctly.', () => {
|
|
46
|
+
if (testChangeRef.value) {
|
|
47
|
+
testChangeRef.value();
|
|
48
|
+
}
|
|
49
|
+
nextTick().then(() => {
|
|
50
|
+
expect(testWrap.outerHTML).toBe(
|
|
51
|
+
'<div><button>handle</button><div>first</div><div>사사</div><div>삼삼</div><div>이이</div><div>end</div></div>'
|
|
52
|
+
);
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
}
|
|
@@ -42,7 +42,7 @@ render(<Root />, testWrap);
|
|
|
42
42
|
|
|
43
43
|
if (import.meta.vitest) {
|
|
44
44
|
const { it, expect } = import.meta.vitest;
|
|
45
|
-
it('
|
|
45
|
+
it('Lithent draws the svg correctly.', () => {
|
|
46
46
|
expect(testWrap.outerHTML).toBe(
|
|
47
47
|
'<div><svg id="toggleSidebarMobileClose" class="w-6 h-6 " fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd"></path></svg><svg class="w-6 h-6" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M3 5a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zM3 10a1 1 0 011-1h6a1 1 0 110 2H4a1 1 0 01-1-1zM3 15a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1z" clip-rule="evenodd"></path><path fill-rule="evenodd" d="M3 5a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zM3 10a1 1 0 011-1h6a1 1 0 110 2H4a1 1 0 01-1-1zM3 15a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1z" clip-rule="evenodd"></path></svg></div>'
|
|
48
48
|
);
|
package/src/types/index.ts
CHANGED
|
@@ -16,10 +16,10 @@ export type Component<T> = (
|
|
|
16
16
|
|
|
17
17
|
export type TagFunctionResolver = {
|
|
18
18
|
tagName: string;
|
|
19
|
-
|
|
19
|
+
ctor: Function;
|
|
20
20
|
props: Props;
|
|
21
21
|
children: WDom[];
|
|
22
|
-
resolve: (
|
|
22
|
+
resolve: (compKey?: Props) => WDom;
|
|
23
23
|
};
|
|
24
24
|
|
|
25
25
|
export type FragmentFunction = (props: Props, children: WDom[]) => WDom;
|
|
@@ -46,15 +46,15 @@ export interface WDom {
|
|
|
46
46
|
props?: Props;
|
|
47
47
|
oldProps?: Props;
|
|
48
48
|
tagName?: string;
|
|
49
|
-
|
|
49
|
+
ctor?: Function;
|
|
50
50
|
children?: WDom[];
|
|
51
51
|
oldChildren?: WDom[];
|
|
52
52
|
getParent?: () => WDom | undefined;
|
|
53
53
|
text?: string | number;
|
|
54
|
-
|
|
54
|
+
compKey?: Props;
|
|
55
55
|
reRender?: () => WDom;
|
|
56
|
-
|
|
57
|
-
|
|
56
|
+
compProps?: Props;
|
|
57
|
+
compChild?: WDom[];
|
|
58
58
|
wrapElement?: HTMLElement;
|
|
59
59
|
afterElement?: HTMLElement;
|
|
60
60
|
el?: HTMLElement | DocumentFragment | Text;
|
package/src/utils/index.ts
CHANGED
|
@@ -7,7 +7,7 @@ export const getParent = (vDom: WDom) => {
|
|
|
7
7
|
};
|
|
8
8
|
|
|
9
9
|
export const reRender = (vDom: WDom, infoVdom: TagFunctionResolver) => {
|
|
10
|
-
const {
|
|
10
|
+
const { compProps: props, compChild: children } = vDom;
|
|
11
11
|
const { props: infoProps, children: infoChidren } = infoVdom;
|
|
12
12
|
|
|
13
13
|
if (props) {
|
|
@@ -29,13 +29,15 @@ export const getEventName = (eventKey: string) =>
|
|
|
29
29
|
export const getAttrKey = (keyName: string) =>
|
|
30
30
|
keyName === 'className' ? 'class' : keyName;
|
|
31
31
|
|
|
32
|
+
export const entries = Object.entries;
|
|
33
|
+
export const keys = Object.keys;
|
|
34
|
+
export const assign = Object.assign;
|
|
35
|
+
|
|
32
36
|
const updateProps = (props: Props, infoProps: Props) => {
|
|
33
37
|
if (props && infoProps !== props) {
|
|
34
|
-
|
|
38
|
+
keys(props).forEach(key => delete props[key]);
|
|
35
39
|
|
|
36
|
-
|
|
37
|
-
([key, value]) => (props[key] = value)
|
|
38
|
-
);
|
|
40
|
+
entries(infoProps || {}).forEach(([key, value]) => (props[key] = value));
|
|
39
41
|
}
|
|
40
42
|
};
|
|
41
43
|
|
package/src/utils/predicator.ts
CHANGED
|
@@ -27,7 +27,10 @@ const checkPlainType = (wDom: WDomParam, typeName: string) =>
|
|
|
27
27
|
const checkSameCustomComponent = (
|
|
28
28
|
newWDom: WDom | TagFunction | TagFunctionResolver,
|
|
29
29
|
originalWDom?: WDom
|
|
30
|
-
) =>
|
|
30
|
+
) =>
|
|
31
|
+
'ctor' in newWDom
|
|
32
|
+
? newWDom.ctor === originalWDom?.ctor
|
|
33
|
+
: newWDom === originalWDom?.ctor;
|
|
31
34
|
|
|
32
35
|
const checkSameFragment = (
|
|
33
36
|
newWDom: WDom | TagFunction | TagFunctionResolver,
|
|
@@ -53,7 +56,12 @@ const checkNormalTypeElement = (
|
|
|
53
56
|
checkPlainWDomType(newWDom) &&
|
|
54
57
|
originalWDom?.type === newWDom.type &&
|
|
55
58
|
(originalWDom?.children?.length === newWDom?.children?.length ||
|
|
56
|
-
newWDom.type === 'loop'
|
|
59
|
+
(newWDom.type === 'loop' &&
|
|
60
|
+
checkExisty(getKey((newWDom.children || [])[0])) &&
|
|
61
|
+
checkExisty(getKey((originalWDom.children || [])[0]))));
|
|
62
|
+
|
|
63
|
+
export const getKey = (target: WDom) =>
|
|
64
|
+
target?.compProps?.key ?? target?.props?.key;
|
|
57
65
|
|
|
58
66
|
export const checkVirtualType = (type: string | null) =>
|
|
59
67
|
type && ['fragment', 'loop'].includes(type);
|
|
@@ -1,23 +1,23 @@
|
|
|
1
1
|
import { ComponentRef, ComponentSubKey, Props, WDom } from '@/types';
|
|
2
2
|
|
|
3
3
|
type RedrawQueueList = {
|
|
4
|
-
|
|
4
|
+
compKey: Props;
|
|
5
5
|
exec: () => void;
|
|
6
6
|
}[];
|
|
7
7
|
|
|
8
|
-
let redrawQueue: {
|
|
8
|
+
let redrawQueue: { compKey: Props; exec: () => void }[] = [];
|
|
9
9
|
let redrawQueueTimeout: boolean = false;
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* Common
|
|
13
13
|
*/
|
|
14
14
|
export const xmlnsRef: { value: string } = { value: '' };
|
|
15
|
-
export const
|
|
15
|
+
export const compKeyRef: { value: Props } = { value: {} };
|
|
16
16
|
export const needDiffRef: { value: boolean } = { value: false };
|
|
17
17
|
export const componentRef: ComponentRef = new WeakMap();
|
|
18
18
|
|
|
19
|
-
export const componentRender = (
|
|
20
|
-
const up = componentRef.get(
|
|
19
|
+
export const componentRender = (compKey: Props) => () => {
|
|
20
|
+
const up = componentRef.get(compKey)?.up;
|
|
21
21
|
let result = false;
|
|
22
22
|
if (up) {
|
|
23
23
|
up();
|
|
@@ -27,8 +27,8 @@ export const componentRender = (componentKey: Props) => () => {
|
|
|
27
27
|
return result;
|
|
28
28
|
};
|
|
29
29
|
|
|
30
|
-
const setComponetRef = (
|
|
31
|
-
componentRef.set(
|
|
30
|
+
const setComponetRef = (compKey: Props) => {
|
|
31
|
+
componentRef.set(compKey, {
|
|
32
32
|
vd: { value: null },
|
|
33
33
|
up: () => {},
|
|
34
34
|
upR: [],
|
|
@@ -40,17 +40,15 @@ const setComponetRef = (componentKey: Props) => {
|
|
|
40
40
|
});
|
|
41
41
|
};
|
|
42
42
|
|
|
43
|
-
export const getComponentKey = () =>
|
|
43
|
+
export const getComponentKey = () => compKeyRef.value;
|
|
44
44
|
|
|
45
|
-
export const getComponentSubInfo = (
|
|
46
|
-
|
|
47
|
-
subKey: ComponentSubKey
|
|
48
|
-
) => componentRef.get(componentKey)![subKey];
|
|
45
|
+
export const getComponentSubInfo = (compKey: Props, subKey: ComponentSubKey) =>
|
|
46
|
+
componentRef.get(compKey)![subKey];
|
|
49
47
|
|
|
50
|
-
export const setRedrawAction = (
|
|
51
|
-
componentRef.get(
|
|
48
|
+
export const setRedrawAction = (compKey: Props, exec: () => void) => {
|
|
49
|
+
componentRef.get(compKey)!.up = () => {
|
|
52
50
|
redrawQueue.push({
|
|
53
|
-
|
|
51
|
+
compKey,
|
|
54
52
|
exec,
|
|
55
53
|
});
|
|
56
54
|
|
|
@@ -61,17 +59,17 @@ export const setRedrawAction = (componentKey: Props, exec: () => void) => {
|
|
|
61
59
|
};
|
|
62
60
|
};
|
|
63
61
|
|
|
64
|
-
export const initUpdateHookState = (
|
|
65
|
-
(
|
|
62
|
+
export const initUpdateHookState = (compKey: Props) =>
|
|
63
|
+
(compKeyRef.value = compKey);
|
|
66
64
|
|
|
67
|
-
export const initMountHookState = (
|
|
68
|
-
|
|
69
|
-
setComponetRef(
|
|
65
|
+
export const initMountHookState = (compKey: Props) => {
|
|
66
|
+
compKeyRef.value = compKey;
|
|
67
|
+
setComponetRef(compKey);
|
|
70
68
|
};
|
|
71
69
|
|
|
72
70
|
const recursiveGetChildKeys = (wDom: WDom, result: Props[]) => {
|
|
73
71
|
(wDom.children || []).forEach(item => {
|
|
74
|
-
const childComKey = item.
|
|
72
|
+
const childComKey = item.compKey;
|
|
75
73
|
if (childComKey) {
|
|
76
74
|
result.push(childComKey);
|
|
77
75
|
}
|
|
@@ -84,7 +82,7 @@ const execRedrawQueue = () => {
|
|
|
84
82
|
let childItemList: Props[] = [];
|
|
85
83
|
|
|
86
84
|
redrawQueue.forEach(item => {
|
|
87
|
-
const childVd = componentRef.get(item.
|
|
85
|
+
const childVd = componentRef.get(item.compKey)?.vd?.value;
|
|
88
86
|
if (childVd) {
|
|
89
87
|
recursiveGetChildKeys(childVd, childItemList);
|
|
90
88
|
}
|
|
@@ -92,16 +90,13 @@ const execRedrawQueue = () => {
|
|
|
92
90
|
|
|
93
91
|
const addedKey: Props[] = [];
|
|
94
92
|
const result = redrawQueue.reduce((acc, item) => {
|
|
95
|
-
const {
|
|
93
|
+
const { compKey } = item;
|
|
96
94
|
|
|
97
|
-
if (
|
|
98
|
-
childItemList.includes(componentKey) ||
|
|
99
|
-
addedKey.includes(componentKey)
|
|
100
|
-
) {
|
|
95
|
+
if (childItemList.includes(compKey) || addedKey.includes(compKey)) {
|
|
101
96
|
return acc;
|
|
102
97
|
}
|
|
103
98
|
|
|
104
|
-
addedKey.push(
|
|
99
|
+
addedKey.push(compKey);
|
|
105
100
|
acc.push(item);
|
|
106
101
|
|
|
107
102
|
return acc;
|