@lukekaalim/act-web 0.4.5 → 1.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/entry.js ADDED
@@ -0,0 +1,6 @@
1
+ // @flow strict
2
+ export * from './renderer.js';
3
+ export * from './reconciler.js';
4
+
5
+ export * from './prop.js';
6
+ export * from './node.js';
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*/)/*: ?Node*/ => {
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 attachNodes = (parent/*: Node*/, children/*: Node[]*/, sibling/*: ?Node*/ = null) => {
23
- for (let i = 0; i < children.length; i++) {
24
- const child = children[children.length - i - 1];
25
- const prevChild = children[children.length - i] || sibling;
26
- if (parent !== child.parentNode || (prevChild && child.nextSibling !== prevChild)) {
27
- parent.insertBefore(child, prevChild);
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": "main.js",
3
+ "main": "entry.js",
4
4
  "type": "module",
5
- "version": "0.4.5",
5
+ "version": "1.2.0",
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-reconciler": "^2.0.4"
13
+ "@lukekaalim/act-renderer-core": "^3.1.1",
14
+ "@lukekaalim/act-reconciler": "^3.0.0"
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 && typeof prev === 'string')
45
+ if (next === null && prev !== null)
46
46
  element.removeAttribute(key);
47
- else if (typeof next === 'string')
48
- element.setAttribute(key, next);
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
- element.textContent = typeof content === 'string' ? content : '';
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
- }