lithent 0.1.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/LICENSE +21 -0
- package/README.md +202 -0
- package/dist/diff.d.ts +14 -0
- package/dist/hook/mountCallback.d.ts +3 -0
- package/dist/hook/ref.d.ts +3 -0
- package/dist/hook/unmount.d.ts +3 -0
- package/dist/hook/updateCallback.d.ts +2 -0
- package/dist/hook/useUpdate.d.ts +3 -0
- package/dist/index.d.ts +29 -0
- package/dist/lithent.mjs +867 -0
- package/dist/lithent.mjs.map +1 -0
- package/dist/lithent.umd.js +2 -0
- package/dist/lithent.umd.js.map +1 -0
- package/dist/render.d.ts +15 -0
- package/dist/types/index.d.ts +65 -0
- package/dist/utils/index.d.ts +3 -0
- package/dist/utils/predicator.d.ts +36 -0
- package/dist/utils/universalRef.d.ts +59 -0
- package/dist/wDom.d.ts +17 -0
- package/examples/dist/assets/index.e76a0ef8.js +2 -0
- package/examples/dist/assets/index.e76a0ef8.js.map +1 -0
- package/examples/dist/index.html +13 -0
- package/examples/package.json +33 -0
- package/examples/src/index.tsx +109 -0
- package/helper/dist/hook/computed.d.ts +4 -0
- package/helper/dist/hook/effect.d.ts +1 -0
- package/helper/dist/hook/state.d.ts +4 -0
- package/helper/dist/hook/store.d.ts +8 -0
- package/helper/dist/index.d.ts +4 -0
- package/helper/dist/lithentHelper.mjs +56 -0
- package/helper/dist/lithentHelper.mjs.map +1 -0
- package/helper/dist/lithentHelper.umd.js +2 -0
- package/helper/dist/lithentHelper.umd.js.map +1 -0
- package/helper/package.json +32 -0
- package/helper/src/hook/computed.ts +23 -0
- package/helper/src/hook/effect.ts +20 -0
- package/helper/src/hook/state.ts +26 -0
- package/helper/src/hook/store.ts +25 -0
- package/helper/src/index.ts +4 -0
- package/package.json +90 -0
- package/router/dist/Router.d.ts +4 -0
- package/router/dist/Router.mjs +56 -0
- package/router/dist/Router.mjs.map +1 -0
- package/router/dist/Router.umd.js +2 -0
- package/router/dist/Router.umd.js.map +1 -0
- package/router/dist/hook/params.d.ts +2 -0
- package/router/package.json +37 -0
- package/router/src/Router.tsx +63 -0
- package/router/src/components/Main.tsx +14 -0
- package/router/src/components/Sub.tsx +7 -0
- package/router/src/components/Sub2.tsx +17 -0
- package/router/src/example.tsx +19 -0
- package/router/src/hook/params.ts +9 -0
- package/src/diff.ts +235 -0
- package/src/examples/callback.tsx +81 -0
- package/src/examples/insert.tsx +36 -0
- package/src/examples/loop.tsx +33 -0
- package/src/examples/nested.tsx +44 -0
- package/src/examples/renew.tsx +29 -0
- package/src/examples/selectbox.tsx +42 -0
- package/src/examples/textarea.tsx +24 -0
- package/src/hook/mountCallback.ts +41 -0
- package/src/hook/ref.ts +1 -0
- package/src/hook/unmount.ts +26 -0
- package/src/hook/updateCallback.ts +29 -0
- package/src/hook/useUpdate.ts +51 -0
- package/src/index.ts +50 -0
- package/src/render.ts +409 -0
- package/src/types/index.ts +107 -0
- package/src/utils/index.ts +52 -0
- package/src/utils/predicator.ts +119 -0
- package/src/utils/universalRef.ts +137 -0
- package/src/wDom.ts +284 -0
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import {
|
|
2
|
+
UseDataStoreValue,
|
|
3
|
+
ComponentRef,
|
|
4
|
+
ComponentSubKey,
|
|
5
|
+
Props,
|
|
6
|
+
NodeChildKey,
|
|
7
|
+
} from '@/types';
|
|
8
|
+
|
|
9
|
+
type redrawQueueList = {
|
|
10
|
+
componentKey: Props;
|
|
11
|
+
nodeChildKey: Props[];
|
|
12
|
+
exec: () => void;
|
|
13
|
+
}[];
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Common
|
|
17
|
+
*/
|
|
18
|
+
export const componentKeyRef: { value: Props } = { value: {} };
|
|
19
|
+
export const needDiffRef: { value: boolean } = { value: false };
|
|
20
|
+
export const componentRef: ComponentRef = new WeakMap();
|
|
21
|
+
export const redrawQueue: {
|
|
22
|
+
value: { componentKey: Props; nodeChildKey: Props[]; exec: () => void }[];
|
|
23
|
+
} = { value: [] };
|
|
24
|
+
export const redrawQueueTimeout: { value: null | number } = { value: null };
|
|
25
|
+
export const nodeChildKeyList: { value: NodeChildKey[] } = { value: [] };
|
|
26
|
+
|
|
27
|
+
export const pushNodeChildKey = (key: Props) =>
|
|
28
|
+
nodeChildKeyList.value.forEach(item => item.value.push(key));
|
|
29
|
+
|
|
30
|
+
export const removeNodeChildKey = (item: NodeChildKey) => {
|
|
31
|
+
nodeChildKeyList.value.splice(nodeChildKeyList.value.indexOf(item), 1);
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export const cleanNodeChildKey = () => (nodeChildKeyList.value = []);
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* DataStore
|
|
38
|
+
*/
|
|
39
|
+
export const dataStoreStore: { [key: string]: UseDataStoreValue } = {};
|
|
40
|
+
export const dataStoreRenderQueue: {
|
|
41
|
+
[key: string]: (() => boolean)[];
|
|
42
|
+
} = {};
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Router
|
|
46
|
+
*/
|
|
47
|
+
export const routerParams: { value: { [key: string]: string } } = { value: {} };
|
|
48
|
+
|
|
49
|
+
export const componentRender = (componentKey: Props) => () => {
|
|
50
|
+
const up = componentRef.get(componentKey)?.up;
|
|
51
|
+
if (up) {
|
|
52
|
+
up();
|
|
53
|
+
return true;
|
|
54
|
+
} else {
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
export const setComponetRef = (componentKey: Props) => {
|
|
60
|
+
componentRef.set(componentKey, {
|
|
61
|
+
up: () => {},
|
|
62
|
+
upR: [],
|
|
63
|
+
upS: { value: 0 },
|
|
64
|
+
upD: [],
|
|
65
|
+
upCB: [],
|
|
66
|
+
mts: [],
|
|
67
|
+
umts: [],
|
|
68
|
+
});
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
export const getComponentKey = () => componentKeyRef.value;
|
|
72
|
+
|
|
73
|
+
export const getComponentSubInfo = (
|
|
74
|
+
componentKey: Props,
|
|
75
|
+
subKey: ComponentSubKey
|
|
76
|
+
) => componentRef.get(componentKey)![subKey];
|
|
77
|
+
|
|
78
|
+
export const setRedrawAction = ({
|
|
79
|
+
componentKey,
|
|
80
|
+
nodeChildKey,
|
|
81
|
+
exec,
|
|
82
|
+
}: {
|
|
83
|
+
componentKey: Props;
|
|
84
|
+
nodeChildKey: { value: Props[] };
|
|
85
|
+
exec: () => void;
|
|
86
|
+
}) => {
|
|
87
|
+
componentRef.get(componentKey)!.up = () => {
|
|
88
|
+
redrawQueue.value.push({
|
|
89
|
+
componentKey,
|
|
90
|
+
nodeChildKey: nodeChildKey.value,
|
|
91
|
+
exec,
|
|
92
|
+
});
|
|
93
|
+
if (!redrawQueueTimeout.value) {
|
|
94
|
+
redrawQueueTimeout.value = setTimeout(execRedrawQueue);
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
export const initUpdateHookState = (componentKey: Props) =>
|
|
100
|
+
(componentKeyRef.value = componentKey);
|
|
101
|
+
|
|
102
|
+
export const initMountHookState = (componentKey: Props) => {
|
|
103
|
+
componentKeyRef.value = componentKey;
|
|
104
|
+
setComponetRef(componentKey);
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
const execRedrawQueue = () => {
|
|
108
|
+
let childItemList: Props[] = [];
|
|
109
|
+
|
|
110
|
+
redrawQueue.value.forEach(item => {
|
|
111
|
+
childItemList = childItemList.concat(item.nodeChildKey);
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
const addedKey: Props[] = [];
|
|
115
|
+
const result = redrawQueue.value.reduce((acc, item) => {
|
|
116
|
+
const { componentKey } = item;
|
|
117
|
+
|
|
118
|
+
if (
|
|
119
|
+
childItemList.includes(componentKey) ||
|
|
120
|
+
addedKey.includes(componentKey)
|
|
121
|
+
) {
|
|
122
|
+
return acc;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
addedKey.push(componentKey);
|
|
126
|
+
acc.push(item);
|
|
127
|
+
|
|
128
|
+
return acc;
|
|
129
|
+
}, [] as redrawQueueList);
|
|
130
|
+
|
|
131
|
+
while (result.length) {
|
|
132
|
+
const action = result.shift();
|
|
133
|
+
if (action) {
|
|
134
|
+
action.exec();
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
};
|
package/src/wDom.ts
ADDED
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
import {
|
|
2
|
+
WDom,
|
|
3
|
+
TagFunction,
|
|
4
|
+
FragmentFunction,
|
|
5
|
+
Props,
|
|
6
|
+
MiddleStateWDomChildren,
|
|
7
|
+
MiddleStateWDom,
|
|
8
|
+
NodePointer,
|
|
9
|
+
NodeChildKey,
|
|
10
|
+
Component,
|
|
11
|
+
} from '@/types';
|
|
12
|
+
|
|
13
|
+
import { makeNewWDomTree } from '@/diff';
|
|
14
|
+
import { wDomUpdate } from '@/render';
|
|
15
|
+
import {
|
|
16
|
+
initUpdateHookState,
|
|
17
|
+
initMountHookState,
|
|
18
|
+
setRedrawAction,
|
|
19
|
+
needDiffRef,
|
|
20
|
+
pushNodeChildKey,
|
|
21
|
+
nodeChildKeyList,
|
|
22
|
+
removeNodeChildKey,
|
|
23
|
+
cleanNodeChildKey,
|
|
24
|
+
componentRender,
|
|
25
|
+
} from '@/utils/universalRef';
|
|
26
|
+
import { runUpdateCallback } from '@/hook/updateCallback';
|
|
27
|
+
import {
|
|
28
|
+
checkFragmentFunction,
|
|
29
|
+
checkCustemComponentFunction,
|
|
30
|
+
} from '@/utils/predicator';
|
|
31
|
+
|
|
32
|
+
export type Children = WDom[];
|
|
33
|
+
|
|
34
|
+
type WDomInfoParam = {
|
|
35
|
+
componentMaker: () => WDom;
|
|
36
|
+
componentKey: Props;
|
|
37
|
+
tag: TagFunction;
|
|
38
|
+
props: Props;
|
|
39
|
+
children: WDom[];
|
|
40
|
+
nodeChildKey: { value: Props[] };
|
|
41
|
+
};
|
|
42
|
+
type WDomInfoWithRenderParam = WDomInfoParam & {
|
|
43
|
+
reRender: () => WDom;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
export const Fragment = (_props: Props, ...children: WDom[]) => ({
|
|
47
|
+
type: 'fragment',
|
|
48
|
+
children,
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
export const h = (
|
|
52
|
+
tag: TagFunction | FragmentFunction | string,
|
|
53
|
+
props: Props,
|
|
54
|
+
...children: MiddleStateWDomChildren
|
|
55
|
+
) => {
|
|
56
|
+
const nodeParentPointer: NodePointer = { value: undefined };
|
|
57
|
+
const newProps = props || {};
|
|
58
|
+
const newChildren = remakeChildren(nodeParentPointer, children);
|
|
59
|
+
const node = makeNode({
|
|
60
|
+
tag,
|
|
61
|
+
props: newProps,
|
|
62
|
+
children: newChildren,
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
if (!checkCustemComponentFunction(node)) {
|
|
66
|
+
nodeParentPointer.value = node;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return node;
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
export const mount =
|
|
73
|
+
<T>(component: Component<T>) =>
|
|
74
|
+
(_props: T, _children: WDom[]) =>
|
|
75
|
+
component;
|
|
76
|
+
|
|
77
|
+
const reRenderCustomComponent = ({
|
|
78
|
+
tag,
|
|
79
|
+
props,
|
|
80
|
+
children,
|
|
81
|
+
originalWDom,
|
|
82
|
+
}: {
|
|
83
|
+
tag: TagFunction;
|
|
84
|
+
props: Props;
|
|
85
|
+
children: WDom[];
|
|
86
|
+
originalWDom: WDom;
|
|
87
|
+
}) => {
|
|
88
|
+
needDiffRef.value = true;
|
|
89
|
+
cleanNodeChildKey();
|
|
90
|
+
|
|
91
|
+
const newWDom = makeWDomResolver({ tag, props, children });
|
|
92
|
+
const newWDomTree = makeNewWDomTree({ originalWDom, newWDom });
|
|
93
|
+
const { isRoot, getParent, wrapElement } = originalWDom;
|
|
94
|
+
|
|
95
|
+
newWDomTree.getParent = getParent;
|
|
96
|
+
|
|
97
|
+
if (!isRoot && getParent) {
|
|
98
|
+
const brothers = getParent()?.children || [];
|
|
99
|
+
const index = brothers.indexOf(originalWDom);
|
|
100
|
+
|
|
101
|
+
brothers.splice(index, 1, newWDomTree);
|
|
102
|
+
} else {
|
|
103
|
+
newWDomTree.isRoot = true;
|
|
104
|
+
newWDomTree.wrapElement = wrapElement;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
wDomUpdate(newWDomTree);
|
|
108
|
+
|
|
109
|
+
needDiffRef.value = false;
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
const makeWDomResolver = ({
|
|
113
|
+
tag,
|
|
114
|
+
props,
|
|
115
|
+
children,
|
|
116
|
+
}: {
|
|
117
|
+
tag: TagFunction;
|
|
118
|
+
props: Props;
|
|
119
|
+
children: WDom[];
|
|
120
|
+
}) => {
|
|
121
|
+
const tagName = tag.name;
|
|
122
|
+
const constructor = tag;
|
|
123
|
+
// 리졸브는 컴포넌트를 새로 만든다.
|
|
124
|
+
const resolve = (componentKey = props) => {
|
|
125
|
+
initMountHookState(componentKey);
|
|
126
|
+
|
|
127
|
+
const nodeChildKey: NodeChildKey = { value: [] };
|
|
128
|
+
pushNodeChildKey(componentKey);
|
|
129
|
+
nodeChildKeyList.value.push(nodeChildKey);
|
|
130
|
+
|
|
131
|
+
const component = tag(props, children);
|
|
132
|
+
const componentMaker = component(
|
|
133
|
+
componentRender(componentKey),
|
|
134
|
+
props,
|
|
135
|
+
children
|
|
136
|
+
);
|
|
137
|
+
|
|
138
|
+
const customNode = makeCustomNode({
|
|
139
|
+
componentMaker,
|
|
140
|
+
componentKey,
|
|
141
|
+
tag,
|
|
142
|
+
props,
|
|
143
|
+
children,
|
|
144
|
+
nodeChildKey,
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
const originalWDom = customNode;
|
|
148
|
+
|
|
149
|
+
setRedrawAction({
|
|
150
|
+
componentKey,
|
|
151
|
+
nodeChildKey,
|
|
152
|
+
exec: () =>
|
|
153
|
+
reRenderCustomComponent({ tag, props, children, originalWDom }),
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
// update의 경우 diff 에서 제거
|
|
157
|
+
if (!needDiffRef.value) {
|
|
158
|
+
removeNodeChildKey(nodeChildKey);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
return customNode;
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
return { tagName, constructor, props, children, resolve };
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
const makeCustomNode = (wDomInfo: WDomInfoParam) => {
|
|
168
|
+
const { componentMaker } = wDomInfo;
|
|
169
|
+
const customNode = componentMaker();
|
|
170
|
+
const reRender = makeReRender(wDomInfo);
|
|
171
|
+
|
|
172
|
+
addComponentProps(customNode, { ...wDomInfo, reRender });
|
|
173
|
+
|
|
174
|
+
return customNode;
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
const makeReRender = (wDomInfo: WDomInfoParam) => {
|
|
178
|
+
const reRender = () => wDomMaker({ ...wDomInfo, reRender });
|
|
179
|
+
|
|
180
|
+
return reRender;
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
const wDomMaker = (wDomInfo: WDomInfoWithRenderParam) => {
|
|
184
|
+
const { componentMaker, componentKey, tag, props, children } = wDomInfo;
|
|
185
|
+
|
|
186
|
+
initUpdateHookState(componentKey);
|
|
187
|
+
runUpdateCallback();
|
|
188
|
+
|
|
189
|
+
const nodeChildKey: NodeChildKey = { value: [] };
|
|
190
|
+
pushNodeChildKey(componentKey);
|
|
191
|
+
nodeChildKeyList.value.push(nodeChildKey);
|
|
192
|
+
|
|
193
|
+
const originalWDom = componentMaker();
|
|
194
|
+
|
|
195
|
+
wDomInfo.nodeChildKey = nodeChildKey;
|
|
196
|
+
|
|
197
|
+
setRedrawAction({
|
|
198
|
+
componentKey,
|
|
199
|
+
nodeChildKey,
|
|
200
|
+
exec: () => reRenderCustomComponent({ tag, props, children, originalWDom }),
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
addComponentProps(originalWDom, wDomInfo);
|
|
204
|
+
|
|
205
|
+
// update의 경우 diff 에서 제거
|
|
206
|
+
if (!needDiffRef.value) {
|
|
207
|
+
removeNodeChildKey(nodeChildKey);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
return originalWDom;
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
const addComponentProps = (wDom: WDom, info: WDomInfoWithRenderParam) => {
|
|
214
|
+
const { componentKey, tag, props, children, reRender, nodeChildKey } = info;
|
|
215
|
+
|
|
216
|
+
Object.assign(wDom, {
|
|
217
|
+
componentProps: props,
|
|
218
|
+
componentChildren: children,
|
|
219
|
+
constructor: tag,
|
|
220
|
+
tagName: tag.name,
|
|
221
|
+
componentKey,
|
|
222
|
+
nodeChildKey,
|
|
223
|
+
reRender,
|
|
224
|
+
});
|
|
225
|
+
};
|
|
226
|
+
|
|
227
|
+
const makeNode = ({
|
|
228
|
+
tag,
|
|
229
|
+
props,
|
|
230
|
+
children,
|
|
231
|
+
}: {
|
|
232
|
+
tag: TagFunction | FragmentFunction | string;
|
|
233
|
+
props: Props;
|
|
234
|
+
children: WDom[];
|
|
235
|
+
}) => {
|
|
236
|
+
if (checkFragmentFunction(tag)) {
|
|
237
|
+
return Fragment(props, ...children);
|
|
238
|
+
} else if (checkCustemComponentFunction(tag)) {
|
|
239
|
+
const componetMakeResolver = makeWDomResolver({ tag, props, children });
|
|
240
|
+
|
|
241
|
+
return needDiffRef.value
|
|
242
|
+
? componetMakeResolver
|
|
243
|
+
: componetMakeResolver.resolve();
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
return {
|
|
247
|
+
type: 'element',
|
|
248
|
+
tag,
|
|
249
|
+
props,
|
|
250
|
+
children,
|
|
251
|
+
};
|
|
252
|
+
};
|
|
253
|
+
|
|
254
|
+
const remakeChildren = (
|
|
255
|
+
nodeParentPointer: NodePointer,
|
|
256
|
+
children: MiddleStateWDomChildren
|
|
257
|
+
): WDom[] =>
|
|
258
|
+
children.map((item: MiddleStateWDom) => {
|
|
259
|
+
const childItem = makeChildrenItem(item);
|
|
260
|
+
|
|
261
|
+
childItem.getParent = () => nodeParentPointer.value;
|
|
262
|
+
|
|
263
|
+
return childItem;
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
const makeChildrenItem = (item: MiddleStateWDom): WDom => {
|
|
267
|
+
if (item === null || item === undefined || item === false) {
|
|
268
|
+
return { type: null };
|
|
269
|
+
} else if (Array.isArray(item)) {
|
|
270
|
+
const nodeParentPointer: NodePointer = { value: undefined };
|
|
271
|
+
const children = remakeChildren(nodeParentPointer, item);
|
|
272
|
+
const node = {
|
|
273
|
+
type: 'loop',
|
|
274
|
+
children,
|
|
275
|
+
};
|
|
276
|
+
nodeParentPointer.value = node;
|
|
277
|
+
|
|
278
|
+
return node;
|
|
279
|
+
} else if (typeof item === 'string' || typeof item === 'number') {
|
|
280
|
+
return { type: 'text', text: item };
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
return item;
|
|
284
|
+
};
|