@lukekaalim/act-web 0.4.6 → 1.2.1
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/entry.js +6 -0
- package/node.js +17 -9
- package/package.json +4 -3
- package/prop.js +12 -4
- package/reconciler.js +16 -0
- package/renderer.js +66 -0
- package/dom.js +0 -60
- package/main.js +0 -25
- package/web.js +0 -19
package/entry.js
ADDED
package/node.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
// @flow strict
|
|
2
2
|
/*:: import type { Element } from '@lukekaalim/act'; */
|
|
3
|
+
/*:: import type { RenderResult } from '@lukekaalim/act-renderer-core'; */
|
|
3
4
|
/*:: import type { CommitDiff } from '@lukekaalim/act-reconciler'; */
|
|
4
|
-
/*:: import type { RenderService } from './main.js'; */
|
|
5
5
|
|
|
6
|
-
export const createNode = (element/*: Element*/, namespace/*: string*/)/*:
|
|
6
|
+
export const createNode = (element/*: Element*/, namespace/*: string*/)/*: null | Node*/ => {
|
|
7
7
|
if (typeof element.type !== 'string')
|
|
8
8
|
return null;
|
|
9
9
|
if (element.type === 'act:null')
|
|
@@ -12,6 +12,8 @@ export const createNode = (element/*: Element*/, namespace/*: string*/)/*: ?Node
|
|
|
12
12
|
return document.createTextNode('');
|
|
13
13
|
if (element.type === 'act:context')
|
|
14
14
|
return null;
|
|
15
|
+
if (element.type === 'act:boundary')
|
|
16
|
+
return null;
|
|
15
17
|
return document.createElementNS(namespace, element.type);
|
|
16
18
|
};
|
|
17
19
|
export const removeNode = (node/*: Node*/) => {
|
|
@@ -19,12 +21,18 @@ export const removeNode = (node/*: Node*/) => {
|
|
|
19
21
|
if (parent)
|
|
20
22
|
parent.removeChild(node);
|
|
21
23
|
}
|
|
22
|
-
export const
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
24
|
+
export const setNodeChildren = (diff/*: CommitDiff*/, parent/*: Node*/, children/*: RenderResult<Node>[]*/) => {
|
|
25
|
+
const childrenToAttach = children.filter(r => !r.commit.suspension).map(r => r.node);
|
|
26
|
+
const childrenToRemove = children.filter(r => r.commit.suspension).map(r => r.node);
|
|
27
|
+
for (let i = 0; i < childrenToRemove.length; i++)
|
|
28
|
+
removeNode(childrenToRemove[i]);
|
|
29
|
+
|
|
30
|
+
// iterate backwards through the children
|
|
31
|
+
for (let i = childrenToAttach.length; i > 0; i--) {
|
|
32
|
+
const child = childrenToAttach[i - 1];
|
|
33
|
+
const rightSibling = childrenToAttach[i];
|
|
34
|
+
if (parent !== child.parentNode || (rightSibling && child.nextSibling !== rightSibling)) {
|
|
35
|
+
parent.insertBefore(child, rightSibling);
|
|
28
36
|
}
|
|
29
37
|
}
|
|
30
|
-
}
|
|
38
|
+
}
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lukekaalim/act-web",
|
|
3
|
-
"main": "
|
|
3
|
+
"main": "entry.js",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"version": "
|
|
5
|
+
"version": "1.2.1",
|
|
6
6
|
"sideEffects": false,
|
|
7
7
|
"scripts": {
|
|
8
8
|
"test": "cd ../..; npm test",
|
|
@@ -10,7 +10,8 @@
|
|
|
10
10
|
"preversion": "npm run test"
|
|
11
11
|
},
|
|
12
12
|
"dependencies": {
|
|
13
|
-
"@lukekaalim/act-
|
|
13
|
+
"@lukekaalim/act-renderer-core": "^3.1.1",
|
|
14
|
+
"@lukekaalim/act-reconciler": "^3.0.1"
|
|
14
15
|
},
|
|
15
16
|
"devDependencies": {
|
|
16
17
|
"@lukekaalim/act": "*"
|
package/prop.js
CHANGED
|
@@ -42,10 +42,17 @@ export const setAttributeProp = (
|
|
|
42
42
|
element/*: Element*/,
|
|
43
43
|
{ key, prev, next }/*: PropDiff*/
|
|
44
44
|
) => {
|
|
45
|
-
if (next === null &&
|
|
45
|
+
if (next === null && prev !== null)
|
|
46
46
|
element.removeAttribute(key);
|
|
47
|
-
else if (
|
|
48
|
-
|
|
47
|
+
else if (next !== null)
|
|
48
|
+
switch (typeof next) {
|
|
49
|
+
case 'string':
|
|
50
|
+
element.setAttribute(key, next);
|
|
51
|
+
case 'number':
|
|
52
|
+
case 'boolean':
|
|
53
|
+
element.setAttribute(key, next.toString());
|
|
54
|
+
default:
|
|
55
|
+
}
|
|
49
56
|
};
|
|
50
57
|
|
|
51
58
|
export const setHTMLProp = (
|
|
@@ -77,7 +84,8 @@ export const setTextProps = (
|
|
|
77
84
|
diff/*: CommitDiff*/
|
|
78
85
|
) => {
|
|
79
86
|
const { content } = diff.next.element.props;
|
|
80
|
-
|
|
87
|
+
if (content !== element.textContent)
|
|
88
|
+
element.textContent = typeof content === 'string' ? content : '';
|
|
81
89
|
};
|
|
82
90
|
|
|
83
91
|
export const setProps = (
|
package/reconciler.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// @flow strict
|
|
2
|
+
/*:: import type { Element } from '@lukekaalim/act'; */
|
|
3
|
+
import { createTree } from '@lukekaalim/act-reconciler';
|
|
4
|
+
import { createWebRenderer } from './renderer.js';
|
|
5
|
+
import { setNodeChildren } from "./node.js";
|
|
6
|
+
|
|
7
|
+
export const render = (element/*: Element*/, node/*: HTMLElement*/) => {
|
|
8
|
+
const web = createWebRenderer();
|
|
9
|
+
const onDiff = diff => setNodeChildren(diff, node, web.render(diff));
|
|
10
|
+
const options = {
|
|
11
|
+
onDiff,
|
|
12
|
+
scheduleWork: (c) => requestAnimationFrame(() => void c()),
|
|
13
|
+
cancelWork: (t) => cancelAnimationFrame(t),
|
|
14
|
+
};
|
|
15
|
+
createTree(element, options);
|
|
16
|
+
};
|
package/renderer.js
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
// @flow strict
|
|
2
|
+
/*:: import type { ElementType } from '@lukekaalim/act'; */
|
|
3
|
+
/*:: import type { Renderer, RenderResult } from '@lukekaalim/act-renderer-core'; */
|
|
4
|
+
import { createManagedRenderer } from '@lukekaalim/act-renderer-core';
|
|
5
|
+
import { setProps, setRef } from './prop.js';
|
|
6
|
+
import { createNode, removeNode, setNodeChildren } from './node.js';
|
|
7
|
+
|
|
8
|
+
export const createDOMRenderer = (
|
|
9
|
+
namespace/*: string*/,
|
|
10
|
+
nodeSubRenderers/*: { [type: string]: ?Renderer<Node> }*/ = {},
|
|
11
|
+
)/*: Renderer<Node>*/ => {
|
|
12
|
+
const add = (diff)/*: null | Node*/ => {
|
|
13
|
+
const node = createNode(diff.next.element, namespace);
|
|
14
|
+
if (node !== null) {
|
|
15
|
+
const parentId = diff.next.path[diff.next.path.length - 1];
|
|
16
|
+
nodeRenderer.nodesByCommitID.get(parentId);
|
|
17
|
+
}
|
|
18
|
+
return node;
|
|
19
|
+
}
|
|
20
|
+
const remove = (node) => {
|
|
21
|
+
removeNode(node);
|
|
22
|
+
};
|
|
23
|
+
const update = (node, diff, children) => {
|
|
24
|
+
setRef(node, diff);
|
|
25
|
+
|
|
26
|
+
if (diff.next.pruned)
|
|
27
|
+
return;
|
|
28
|
+
|
|
29
|
+
setProps(node, diff);
|
|
30
|
+
setNodeChildren(diff, node, children);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const next = (diff)/*: RenderResult<Node>[]*/ => {
|
|
34
|
+
const { type } = diff.next.element;
|
|
35
|
+
const subrenderer = typeof type === 'string' && nodeSubRenderers[type];
|
|
36
|
+
if (subrenderer) {
|
|
37
|
+
return subrenderer.render(diff);
|
|
38
|
+
}
|
|
39
|
+
return nodeRenderer.render(diff);
|
|
40
|
+
};
|
|
41
|
+
const getExternalNodes = (commit) => {
|
|
42
|
+
const { type } = commit.element;
|
|
43
|
+
const subrenderer = typeof type === 'string' && nodeSubRenderers[type];
|
|
44
|
+
if (subrenderer) {
|
|
45
|
+
return subrenderer.getNodes(commit);
|
|
46
|
+
}
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const nodeRenderer = createManagedRenderer({ add, remove, update, next, getExternalNodes });
|
|
51
|
+
|
|
52
|
+
return nodeRenderer;
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
export const createWebRenderer = (
|
|
56
|
+
subRenderers/*: { [type: string]: ?Renderer<Node> }*/ = {},
|
|
57
|
+
)/*: Renderer<Node>*/ => {
|
|
58
|
+
const svgRenderer = createDOMRenderer('http://www.w3.org/2000/svg')
|
|
59
|
+
|
|
60
|
+
const htmlRenderer = createDOMRenderer('http://www.w3.org/1999/xhtml', {
|
|
61
|
+
...subRenderers,
|
|
62
|
+
svg: svgRenderer,
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
return htmlRenderer;
|
|
66
|
+
}
|
package/dom.js
DELETED
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
// @flow strict
|
|
2
|
-
/*:: import type { ElementType } from '@lukekaalim/act'; */
|
|
3
|
-
/*:: import type { CommitDiff, CommitID } from '@lukekaalim/act-reconciler'; */
|
|
4
|
-
/*:: import type { RenderService } from './main.js'; */
|
|
5
|
-
import { setProps, setRef } from './prop.js';
|
|
6
|
-
import { createNode, attachNodes, removeNode } from './node.js';
|
|
7
|
-
|
|
8
|
-
export const createDOMRenderer = (
|
|
9
|
-
namespace/*: string*/,
|
|
10
|
-
subRenderers/*: Map<ElementType, RenderService>*/ = new Map(),
|
|
11
|
-
)/*: RenderService*/ => {
|
|
12
|
-
const nodeByCommit = new Map/*:: <CommitID, Node>*/();
|
|
13
|
-
|
|
14
|
-
const getNodeForDiff = (diff) => {
|
|
15
|
-
if (diff.prev.pruned)
|
|
16
|
-
return createNode(diff.next.element, namespace);
|
|
17
|
-
return nodeByCommit.get(diff.next.id);
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
const findNodesById = (commit)/*: Node[]*/ => {
|
|
21
|
-
const node = nodeByCommit.get(commit.id);
|
|
22
|
-
if (node)
|
|
23
|
-
return [node];
|
|
24
|
-
return commit.children.map(findNodesById).flat(1);
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
const renderDiffToNodes = (diff/*: CommitDiff*/)/*: Node[]*/ => {
|
|
28
|
-
if (diff.prev.version === diff.next.version)
|
|
29
|
-
return findNodesById(diff.next);
|
|
30
|
-
const node = getNodeForDiff(diff);
|
|
31
|
-
|
|
32
|
-
const children = diff.diffs.map(render).flat(1);
|
|
33
|
-
|
|
34
|
-
if (!node)
|
|
35
|
-
return children;
|
|
36
|
-
|
|
37
|
-
setRef(node, diff);
|
|
38
|
-
if (diff.next.pruned)
|
|
39
|
-
return (removeNode(node), []);
|
|
40
|
-
|
|
41
|
-
setProps(node, diff);
|
|
42
|
-
attachNodes(node, children);
|
|
43
|
-
nodeByCommit.set(diff.next.id, node);
|
|
44
|
-
|
|
45
|
-
return [node];
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
const render = (diff/*: CommitDiff*/)/*: Node[]*/ => {
|
|
49
|
-
const element = (diff.next || diff.prev || diff.curr).element;
|
|
50
|
-
|
|
51
|
-
const subRenderer = subRenderers.get(element.type);
|
|
52
|
-
if (subRenderer)
|
|
53
|
-
return subRenderer.render(diff);
|
|
54
|
-
return renderDiffToNodes(diff);
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
return {
|
|
58
|
-
render
|
|
59
|
-
};
|
|
60
|
-
};
|
package/main.js
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
// @flow strict
|
|
2
|
-
/*:: import type { Element } from '@lukekaalim/act'; */
|
|
3
|
-
/*:: import type { CommitDiff } from '@lukekaalim/act-reconciler'; */
|
|
4
|
-
import { createTree } from '@lukekaalim/act-reconciler';
|
|
5
|
-
import { attachNodes } from './node.js';
|
|
6
|
-
import { createWebRenderService } from './web.js';
|
|
7
|
-
|
|
8
|
-
/*::
|
|
9
|
-
export type RenderService = {
|
|
10
|
-
render: CommitDiff => Node[]
|
|
11
|
-
};
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
export const render = (element/*: Element*/, node/*: HTMLElement*/) => {
|
|
15
|
-
const web = createWebRenderService();
|
|
16
|
-
const onDiff = diff => attachNodes(node, web.render(diff));
|
|
17
|
-
const options = {
|
|
18
|
-
onDiff,
|
|
19
|
-
scheduleWork: (c) => requestAnimationFrame(() => void c()),
|
|
20
|
-
};
|
|
21
|
-
const tree = createTree(element, options);
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
export * from './web';
|
|
25
|
-
export * from './dom';
|
package/web.js
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
// @flow strict
|
|
2
|
-
/*:: import type { ElementType } from '@lukekaalim/act'; */
|
|
3
|
-
/*:: import type { CommitDiff } from '@lukekaalim/act-reconciler'; */
|
|
4
|
-
/*:: import type { RenderService } from './main.js'; */
|
|
5
|
-
|
|
6
|
-
import { createDOMRenderer } from "./dom";
|
|
7
|
-
|
|
8
|
-
export const createWebRenderService = (
|
|
9
|
-
subRenderers/*: Map<ElementType, RenderService>*/ = new Map(),
|
|
10
|
-
)/*: RenderService*/ => {
|
|
11
|
-
const svgRenderer = createDOMRenderer('http://www.w3.org/2000/svg')
|
|
12
|
-
|
|
13
|
-
const htmlRenderer = createDOMRenderer('http://www.w3.org/1999/xhtml', new Map([
|
|
14
|
-
...subRenderers,
|
|
15
|
-
['svg', svgRenderer],
|
|
16
|
-
]));
|
|
17
|
-
|
|
18
|
-
return htmlRenderer;
|
|
19
|
-
}
|