@lukekaalim/act-web 2.1.0 → 2.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/node.js CHANGED
@@ -1,27 +1,21 @@
1
1
  // @flow strict
2
2
  /*:: import type { Element } from '@lukekaalim/act'; */
3
- /*:: import type { RenderResult } from '@lukekaalim/act-renderer-core'; */
3
+ /*:: import type { RenderResult, RenderResult2 } from '@lukekaalim/act-renderer-core'; */
4
4
  /*:: import type { CommitDiff } from '@lukekaalim/act-reconciler'; */
5
5
 
6
- export const createNode = (element/*: Element*/, namespace/*: string*/)/*: null | Node*/ => {
7
- if (typeof element.type !== 'string')
8
- return null;
9
- if (element.type === 'act:null')
10
- return null;
11
- if (element.type === 'act:string')
6
+ import { calculateIndexChanges } from "@lukekaalim/act-reconciler/util";
7
+
8
+ export const createNode = (type/*: string*/, namespace/*: string*/)/*: Node*/ => {
9
+ if (type === 'act:string')
12
10
  return document.createTextNode('');
13
- if (element.type === 'act:context')
14
- return null;
15
- if (element.type === 'act:boundary')
16
- return null;
17
- return document.createElementNS(namespace, element.type);
11
+ return document.createElementNS(namespace, type);
18
12
  };
19
13
  export const removeNode = (node/*: Node*/) => {
20
14
  const parent = node.parentNode;
21
15
  if (parent)
22
16
  parent.removeChild(node);
23
17
  }
24
- export const setNodeChildren = (diff/*: CommitDiff*/, parent/*: Node*/, children/*: RenderResult<Node>[]*/) => {
18
+ export const setNodeChildren = (parent/*: Node*/, children/*: RenderResult<Node>[]*/) => {
25
19
  const childrenToAttach = children.filter(r => !r.commit.suspension).map(r => r.node);
26
20
  const childrenToRemove = children.filter(r => r.commit.suspension).map(r => r.node);
27
21
  for (let i = 0; i < childrenToRemove.length; i++)
@@ -36,3 +30,25 @@ export const setNodeChildren = (diff/*: CommitDiff*/, parent/*: Node*/, children
36
30
  }
37
31
  }
38
32
  }
33
+
34
+ export const setNodeChildren2 = (parent/*: Node*/, children/*: Node[]*/) => {
35
+ const parentNodeLength = parent.childNodes.length;
36
+ const parentNodes = [...parent.childNodes];
37
+
38
+ for (let i = 0; i < parentNodeLength; i++) {
39
+ if (!children.includes(parentNodes[i]))
40
+ parent.removeChild(parentNodes[i]);
41
+ }
42
+
43
+ for (let i = 0; i < children.length; i++) {
44
+ const prevChild = parent.childNodes[i] || null;
45
+ const nextChild = children[i] || null;
46
+
47
+ if (prevChild !== nextChild) {
48
+ if (!prevChild)
49
+ parent.appendChild(nextChild)
50
+ else
51
+ parent.replaceChild(nextChild, prevChild);
52
+ }
53
+ }
54
+ }
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "main": "entry.js",
4
4
  "types": "entry.d.ts",
5
5
  "type": "module",
6
- "version": "2.1.0",
6
+ "version": "2.2.0",
7
7
  "sideEffects": false,
8
8
  "scripts": {
9
9
  "test": "cd ../..; npm test",
@@ -12,7 +12,7 @@
12
12
  },
13
13
  "dependencies": {
14
14
  "@lukekaalim/act-renderer-core": "^3.2.2",
15
- "@lukekaalim/act-reconciler": "^3.0.1"
15
+ "@lukekaalim/act-reconciler": "^3.1.0"
16
16
  },
17
17
  "devDependencies": {
18
18
  "@lukekaalim/act": "*"
package/prop.js CHANGED
@@ -1,6 +1,11 @@
1
1
  // @flow strict
2
- /*:: import type { PropDiff, CommitDiff } from '@lukekaalim/act-reconciler'; */
3
- import { calculatePropsDiff } from '@lukekaalim/act-reconciler'
2
+ /*::
3
+ import type { Commit3 } from "../../reconciler/commit3";
4
+ import type { Diff3, DiffSet } from "../../reconciler/diff";
5
+ import type { CommitDiff } from '@lukekaalim/act-reconciler';
6
+ import type { PropDiff, PropDiffRegistry } from '@lukekaalim/act-renderer-core';
7
+ */
8
+ import { calculatePropsDiff } from '@lukekaalim/act-renderer-core'
4
9
 
5
10
  const propBlacklist = new Set(['ref', 'key', 'children']);
6
11
 
@@ -12,9 +17,9 @@ export const setStylesProp = (
12
17
  const prevRules = typeof prev === 'object' && prev || {};
13
18
  const nextRules = typeof next === 'object' && next || {};
14
19
 
15
- const diff = calculatePropsDiff(prevRules, nextRules);
20
+ const reg = calculatePropsDiff(prevRules, nextRules);
16
21
 
17
- for (const [rule, { next }] of diff.entries()) {
22
+ for (const [rule, { next }] of reg.map) {
18
23
  const nextRuleValue = (typeof next === 'string' || typeof next === 'number') ? next : null;
19
24
  if (typeof (style/*: any*/)[rule] !== 'undefined')
20
25
  (style/*: any*/)[rule] = nextRuleValue;
@@ -93,18 +98,17 @@ export const setHTMLProp = (
93
98
 
94
99
  export const setHTMLProps = (
95
100
  element/*: HTMLElement | SVGElement*/,
96
- diff/*: CommitDiff*/
101
+ registry/*: PropDiffRegistry*/
97
102
  ) => {
98
- const propDiffs = calculatePropsDiff(diff.prev.element.props, diff.next.element.props)
99
- for (const [_, propDiff] of propDiffs)
103
+ for (const [_, propDiff] of registry.map)
100
104
  setHTMLProp(element, propDiff);
101
105
  };
102
106
 
103
107
  export const setTextProps = (
104
108
  element/*: Text*/,
105
- diff/*: CommitDiff*/
109
+ registry/*: PropDiffRegistry*/
106
110
  ) => {
107
- const { content } = diff.next.element.props;
111
+ const content = registry.prop('content', '').next;
108
112
  if (content !== element.textContent)
109
113
  element.textContent = typeof content === 'string' ? content : '';
110
114
  };
@@ -113,12 +117,26 @@ export const setProps = (
113
117
  element/*: ?Node*/,
114
118
  diff/*: CommitDiff*/
115
119
  ) => {
120
+ const propDiff = calculatePropsDiff(diff.prev.element.props, diff.next.element.props);
116
121
  if (element instanceof HTMLElement || element instanceof SVGElement)
117
- setHTMLProps(element, diff);
122
+ setHTMLProps(element, propDiff);
118
123
  if (element instanceof Text)
119
- setTextProps(element, diff);
124
+ setTextProps(element, propDiff);
120
125
  };
121
126
 
127
+ export const setWebProps2 = (
128
+ element/*: Node*/,
129
+ set/*: DiffSet*/,
130
+ diff/*: Diff3*/,
131
+ ) => {
132
+ const prev = set.prevs.map.get(diff.commit.id);
133
+ const propDiff = calculatePropsDiff(prev ? prev.element.props : {}, diff.commit.element.props);
134
+ if (element instanceof HTMLElement || element instanceof SVGElement)
135
+ setHTMLProps(element, propDiff);
136
+ if (element instanceof Text)
137
+ setTextProps(element, propDiff);
138
+ }
139
+
122
140
  export const setRef = (
123
141
  node/*: ?Node*/,
124
142
  diff/*: CommitDiff*/
@@ -135,4 +153,4 @@ export const setRef = (
135
153
  else if (diff.next.pruned)
136
154
  ref['current'] = null;
137
155
  }
138
- };
156
+ };
package/reconciler.js CHANGED
@@ -1,16 +1,36 @@
1
1
  // @flow strict
2
2
  /*:: import type { Element } from '@lukekaalim/act'; */
3
- import { createTree } from '@lukekaalim/act-reconciler';
3
+ import { createBoundaryService, createEffectService, createReconciler, createSchedule2, createTree, createTreeService2 } from '@lukekaalim/act-reconciler';
4
4
  import { createWebRenderer } from './renderer.js';
5
- import { setNodeChildren } from "./node.js";
5
+ import { setNodeChildren2 } from "./node.js";
6
6
 
7
7
  export const render = (element/*: Element*/, node/*: HTMLElement*/) => {
8
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),
9
+
10
+ const onScheduleRequest = (callback) => {
11
+ const id = requestAnimationFrame(() => callback(5));
12
+ return () => cancelAnimationFrame(id);
14
13
  };
15
- createTree(element, options);
14
+ const scheduler = createSchedule2(onScheduleRequest)
15
+ const effect = createEffectService(scheduler);
16
+ const boundary = createBoundaryService();
17
+ const reconciler = createReconciler(scheduler);
18
+
19
+ reconciler.diff.subscribeDiff((set) => {
20
+ performance.mark('act:web:nodes:start')
21
+ setNodeChildren2(node, web.render(set, set.root));
22
+ performance.mark('act:web:nodes:end')
23
+ performance.measure('act:web:nodes', 'act:web:nodes:start', 'act:web:nodes:end')
24
+ performance.mark('act:web:effects:start')
25
+ reconciler.tree.live.registry = effect.runEffectRegistry(set.registry);
26
+ performance.mark('act:web:effects:end')
27
+ performance.measure('act:web:effects', 'act:web:effects:start', 'act:web:effects:end')
28
+
29
+ performance.mark('act:web:suspense:start')
30
+ const map = boundary.calcBoundaryMap(set);
31
+ boundary.getRootBoundaryValue(set.suspensions, set, map);
32
+ performance.mark('act:web:suspense:end')
33
+ performance.measure('act:web:suspense', 'act:web:suspense:start', 'act:web:suspense:end')
34
+ });
35
+ reconciler.tree.mount(element);
16
36
  };
package/renderer.js CHANGED
@@ -2,80 +2,77 @@
2
2
  /*::
3
3
  import type { ElementType } from '@lukekaalim/act';
4
4
  import type { CommitDiff, Commit } from '@lukekaalim/act-reconciler';
5
+ import type { Renderer2 } from "../core/renderer2";
5
6
  */
6
7
  /*:: import type { Renderer, RenderResult } from '@lukekaalim/act-renderer-core'; */
7
8
  import { createManagedRenderer } from '@lukekaalim/act-renderer-core';
8
- import { setProps, setRef } from './prop.js';
9
- import { createNode, removeNode, setNodeChildren } from './node.js';
9
+ import { setProps, setRef, setWebProps2 } from './prop.js';
10
+ import { createNode, removeNode, setNodeChildren, setNodeChildren2 } from './node.js';
11
+ import { createRenderer2 } from '@lukekaalim/act-renderer-core/renderer2.js';
12
+ import { setRef2 } from "../core/props";
10
13
 
11
14
  export const createDOMRenderer = (
12
15
  namespace/*: string*/,
13
- nextDOMNode/*: ?((diff: CommitDiff) => RenderResult<Node>[])*/ = null,
14
- getExternalDOMNode/*: ?((diff: Commit) => null | RenderResult<Node>[])*/ = null,
15
- )/*: Renderer<Node>*/ => {
16
- const add = (diff)/*: null | Node*/ => {
17
- const node = createNode(diff.next.element, namespace);
18
- if (node !== null) {
19
- const parentId = diff.next.path[diff.next.path.length - 1];
20
- nodeRenderer.nodesByCommitID.get(parentId);
21
- }
22
- return node;
16
+ getNextRenderer/*: null | (ElementType => null | Renderer2<Node>)*/ = null,
17
+ )/*: Renderer2<Node>*/ => {
18
+ const create = (type) => {
19
+ return createNode(type, namespace);
23
20
  }
24
- const remove = (node) => {
21
+ const remove = (node, children, diff) => {
22
+ setRef2(node, diff.commit, diff.change);
25
23
  removeNode(node);
26
24
  };
27
- const update = (node, diff, children) => {
28
- setRef(node, diff);
25
+ const update = (node, set, diff) => {
26
+ if (diff.change.type === 'create')
27
+ setRef2(node, diff.commit, diff.change);
29
28
 
30
- if (diff.next.pruned)
29
+ setWebProps2(node, set, diff);
30
+ }
31
+ const attach = (node, set, diff, children) => {
32
+ if (diff.commit.element.props["ignoreChildren"])
31
33
  return;
34
+ setNodeChildren2(node, children);
35
+ }
32
36
 
33
- setProps(node, diff);
34
- setNodeChildren(diff, node, children);
37
+ const getRenderer = (set, commitId) => {
38
+ const commit = set.nexts.get(commitId);
39
+ return getNextRenderer && getNextRenderer(commit.element.type) || nodeRenderer;
35
40
  }
36
41
 
37
- const getExternalNodes = (commit) => {
38
- if (getExternalDOMNode) {
39
- return getExternalDOMNode(commit);
40
- }
41
- return null;
42
+ const getNodes = (set, commitId) => {
43
+ const renderer = getRenderer(set, commitId)
44
+ return renderer.getNodes(set, commitId);
42
45
  }
43
46
 
44
- const next = (diff) => {
45
- if (nextDOMNode) {
46
- return nextDOMNode(diff)
47
- }
48
- return nodeRenderer.render(diff);
47
+ const render = (set, commitId) => {
48
+ const renderer = getRenderer(set, commitId)
49
+ return renderer.render(set, commitId);
49
50
  }
50
51
 
51
- const nodeRenderer = createManagedRenderer({ add, remove, update, next, getExternalNodes });
52
+ const nodeRenderer = createRenderer2({
53
+ create,
54
+ update,
55
+ remove,
56
+ attach,
57
+ }, {
58
+ getNodes,
59
+ render,
60
+ });
52
61
 
53
62
  return nodeRenderer;
54
63
  };
55
64
 
56
65
  export const createWebRenderer = (
57
- nextDOMNode/*: ?((diff: CommitDiff) => RenderResult<Node>[])*/ = null,
58
- getExternalDOMNode/*: ?((diff: Commit) => null | RenderResult<Node>[])*/ = null,
59
- )/*: Renderer<Node>*/ => {
66
+ getNextRenderer/*: null | (ElementType => null | Renderer2<Node>)*/ = null,
67
+ )/*: Renderer2<Node>*/ => {
60
68
  const svgRenderer = createDOMRenderer('http://www.w3.org/2000/svg')
61
69
 
62
- const htmlRenderer = createDOMRenderer('http://www.w3.org/1999/xhtml', diff => {
63
- switch (diff.next.element.type) {
64
- case 'svg':
65
- return svgRenderer.render(diff);
66
- default:
67
- if (nextDOMNode)
68
- return nextDOMNode(diff);
69
- return htmlRenderer.render(diff)
70
- }
71
- }, commit => {
72
- switch (commit.element.type) {
70
+ const htmlRenderer = createDOMRenderer('http://www.w3.org/1999/xhtml', type => {
71
+ switch (type) {
73
72
  case 'svg':
74
- return svgRenderer.getNodes(commit);
73
+ return svgRenderer;
75
74
  default:
76
- if (getExternalDOMNode)
77
- return getExternalDOMNode(commit);
78
- return null;
75
+ return getNextRenderer && getNextRenderer(type);
79
76
  }
80
77
  });
81
78