@lukekaalim/act-web 2.5.5 → 3.0.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/element.ts ADDED
@@ -0,0 +1,55 @@
1
+ import * as act from '@lukekaalim/act';
2
+ import { HTMLTagName } from "./tags";
3
+
4
+ type EventMap = {
5
+ onClick: "click",
6
+
7
+ onMouseEnter: "mouseenter",
8
+ onMouseMove: "mousemove",
9
+ onMouseLeave: "mouseleave",
10
+
11
+ onPointerEnter: "pointerenter",
12
+ onPointerMove: "pointermove",
13
+ onPointerLeave: "pointerleave",
14
+
15
+ onKeyDown: "keydown",
16
+ onKeyUp: "keyup",
17
+
18
+ onFocus: "focus",
19
+ onBlur: 'blur',
20
+
21
+ onInput: "input",
22
+ onChange: "change",
23
+ }
24
+
25
+ type ElementMap = {
26
+ "button": HTMLButtonElement,
27
+ "div": HTMLDivElement,
28
+ "form": HTMLFormElement,
29
+ "input": HTMLInputElement,
30
+ "pre": HTMLPreElement,
31
+ "canvas": HTMLCanvasElement,
32
+ }
33
+
34
+ export const createSpiderElement = <Type extends HTMLTagName>(
35
+ type: Type,
36
+ props?: {
37
+ ref?: act.Ref<null | HTMLElement>,
38
+ key?: string | number,
39
+ style?: { [key in keyof CSSStyleDeclaration]?: number | string },
40
+ classList?: readonly (string | boolean | null | void)[],
41
+ className?: string,
42
+ }
43
+ & Record<string, unknown>
44
+ & {
45
+ //[key in keyof HTMLElement]?: HTMLElement[key] extends Function ? never : HTMLElement[key]
46
+ }
47
+ & {
48
+ [key in keyof EventMap]?: (this: HTMLElement, ev: HTMLElementEventMap[EventMap[key]]) => unknown
49
+ },
50
+ children?: act.Node,
51
+ ): act.Element => {
52
+ return act.createElement(type, props, children)
53
+ };
54
+
55
+ export const hs = createSpiderElement;
package/mod.ts ADDED
@@ -0,0 +1,4 @@
1
+ export * from './space.ts';
2
+ export * from './element.ts';
3
+ export * from './props.ts';
4
+ export * from './render.ts';
package/package.json CHANGED
@@ -1,23 +1,11 @@
1
1
  {
2
2
  "name": "@lukekaalim/act-web",
3
- "main": "entry.js",
4
- "types": "entry.d.ts",
3
+ "version": "3.0.0",
5
4
  "type": "module",
6
- "version": "2.5.5",
7
- "sideEffects": false,
8
- "scripts": {
9
- "test": "cd ../..; npm test",
10
- "postversion": "../../scripts/postversion.sh",
11
- "preversion": "npm run test"
12
- },
5
+ "main": "mod.ts",
13
6
  "dependencies": {
14
- "@lukekaalim/act-renderer-core": "^3.5.5",
15
- "@lukekaalim/act-reconciler": "^3.7.5"
16
- },
17
- "devDependencies": {
18
- "@lukekaalim/act": "*"
19
- },
20
- "peerDependencies": {
21
- "@lukekaalim/act": "^2.5.0"
7
+ "@lukekaalim/act": "^3.0.0",
8
+ "@lukekaalim/act-recon": "^1.0.0",
9
+ "@lukekaalim/act-backstage": "^1.0.0"
22
10
  }
23
- }
11
+ }
package/props.ts ADDED
@@ -0,0 +1,119 @@
1
+ import * as act from '@lukekaalim/act';
2
+
3
+ export const setProps = (
4
+ node: HTMLElement | SVGElement | Text,
5
+
6
+ next: act.Element,
7
+ prev: null | act.Element
8
+ ) => {
9
+ if (node instanceof HTMLElement) {
10
+ setHTMLElementProps(node, next, prev);
11
+ }
12
+ if (node instanceof SVGElement) {
13
+ setSVGElementProps(node, next, prev);
14
+ }
15
+ if (node instanceof Text) {
16
+ if (node.textContent !== next.props.value)
17
+ node.textContent = next.props.value as string
18
+ }
19
+ }
20
+
21
+ export const setSVGElementProps = (
22
+ node: SVGElement,
23
+
24
+ next: act.Element,
25
+ prev: null | act.Element
26
+ ) => {
27
+ setPropObject(node as any, next.props, prev && prev.props, (name, next, prev) => {
28
+ if (name.startsWith('on')) {
29
+ const eventName = name.slice(2).toLocaleLowerCase();
30
+ setEventProp(node as any, eventName, next, prev);
31
+ return true;
32
+ }
33
+ switch (name) {
34
+ case 'ref':
35
+ (next as any).current = node;
36
+ return true;
37
+ default:
38
+ node.setAttribute(name, next as any);
39
+ return true;
40
+ };
41
+ });
42
+ }
43
+
44
+ export const setHTMLElementProps = (
45
+ node: HTMLElement,
46
+
47
+ next: act.Element,
48
+ prev: null | act.Element
49
+ ) => {
50
+ setPropObject(node as any, next.props, prev && prev.props, (name, next, prev) => {
51
+ if (name.startsWith('on')) {
52
+ const eventName = name.slice(2).toLocaleLowerCase();
53
+ setEventProp(node as any, eventName, next, prev);
54
+ return true;
55
+ }
56
+ switch (name) {
57
+ case 'ref':
58
+ (next as any).current = node;
59
+ return true;
60
+ case 'style':
61
+ return (setStyleProp(node.style, next as any, prev as any), true);
62
+ case 'className':
63
+ node.className = next as string;
64
+ return true;
65
+ case 'classList':
66
+ const classNames = (next as string[]).filter(Boolean).join(' ');
67
+ node.className = classNames;
68
+ return true;
69
+ default:
70
+ return false;
71
+ }
72
+ })
73
+ }
74
+
75
+ export const setEventProp = (
76
+ node: EventSource,
77
+ type: string,
78
+ next: unknown,
79
+ prev: unknown,
80
+ ) => {
81
+ if (prev === next)
82
+ return;
83
+ if (prev) {
84
+ node.removeEventListener(type, prev as any)
85
+ }
86
+ if (next) {
87
+ node.addEventListener(type, next as any)
88
+ }
89
+ }
90
+
91
+ export const setStyleProp = (
92
+ node: CSSStyleDeclaration,
93
+ style: null | Record<keyof CSSStyleDeclaration, string | number>,
94
+ prevStyle: null | Record<keyof CSSStyleDeclaration, string | number>,
95
+ ) => {
96
+ setPropObject(node as any, style, prevStyle)
97
+ }
98
+
99
+ const setPropObject = (
100
+ target: Record<string, unknown>,
101
+ next: null | Record<string, unknown>,
102
+ prev: null | Record<string, unknown>,
103
+ assign: null | ((name: string, next: unknown, prev: unknown) => boolean) = null,
104
+ ) => {
105
+ const names = new Set([
106
+ ...Object.keys(next || {}),
107
+ ...Object.keys(prev || {})
108
+ ]);
109
+
110
+ for (const name of names) {
111
+ const nextValue = (next || {})[name];
112
+ const successfulAssign = assign && assign(name, nextValue, (prev || {})[name]);
113
+ if (!successfulAssign) {
114
+ if (target[name] !== nextValue) {
115
+ target[name] = nextValue;
116
+ }
117
+ }
118
+ }
119
+ }
package/render.ts ADDED
@@ -0,0 +1,10 @@
1
+ import { createWebSpace } from "./space";
2
+ import { createRenderFunction, Scheduler } from "@lukekaalim/act-backstage";
3
+
4
+ const intervalScheduler: Scheduler<NodeJS.Timeout> = {
5
+ duration: 10,
6
+ request: func => setInterval(func, 10),
7
+ cancel: id => clearInterval(id),
8
+ }
9
+
10
+ export const render = createRenderFunction(intervalScheduler, createWebSpace);
package/space.ts ADDED
@@ -0,0 +1,59 @@
1
+ import * as act from '@lukekaalim/act';
2
+ import * as recon from '@lukekaalim/act-recon';
3
+
4
+ import { createSimpleRenderSpace } from '@lukekaalim/act-backstage/mod.ts';
5
+
6
+ import { setProps } from './props.ts';
7
+
8
+ export const HTML: act.Component = ({ children }) => act.h(act.primitiveNodeTypes.render, { type: 'web:html' }, children);
9
+ export const SVG: act.Component = ({ children }) => act.h(act.primitiveNodeTypes.render, { type: 'web:svg' }, children);
10
+
11
+ export const createWebSpace = (tree: recon.CommitTree, root: HTMLElement, document: Document = window.document) => {
12
+ return createSimpleRenderSpace(tree, {
13
+ rootTypes: new Set(['web:html', 'web:svg']),
14
+ create(element, rootType) {
15
+ const tag = element.type;
16
+
17
+ switch (typeof tag) {
18
+ case 'symbol': {
19
+ switch (tag) {
20
+ case act.primitiveNodeTypes.string:
21
+ return document.createTextNode("");
22
+ default:
23
+ return null;
24
+ }
25
+ }
26
+ case 'string': {
27
+ switch (rootType) {
28
+ case 'web:html':
29
+ return document.createElementNS('http://www.w3.org/1999/xhtml', tag);
30
+ case 'web:svg':
31
+ return document.createElementNS('http://www.w3.org/2000/svg', tag);
32
+ }
33
+ }
34
+ default:
35
+ return null;
36
+ }
37
+ },
38
+ update(el, next, prev) {
39
+ setProps(el, next, prev);
40
+ },
41
+ link(el, parent) {
42
+ (parent || root).appendChild(el);
43
+ },
44
+ sort(el, newChildren) {
45
+ if (el instanceof Text)
46
+ return;
47
+ if (newChildren.length < 2)
48
+ return;
49
+
50
+ for (let i = 0; i < newChildren.length; i++)
51
+ if (el.children[i] !== newChildren[i])
52
+ el.insertBefore(newChildren[i], el.children[i])
53
+ },
54
+ destroy(prev) {
55
+ if (prev.parentNode)
56
+ prev.parentNode.removeChild(prev);
57
+ },
58
+ });
59
+ };
package/tags.ts ADDED
@@ -0,0 +1,31 @@
1
+ export const htmlTagNames = new Set([
2
+ "div", "span",
3
+ "img", "picture", "canvas",
4
+ "details", "summary", "section",
5
+ "video", "audio",
6
+ "h1", "h2", "h3", "h4", "h5", "h6",
7
+ "hl",
8
+ 'p',
9
+ "ol", "ul", "li",
10
+ "table", 'td', 'tr', 'th',
11
+ "pre",
12
+
13
+ 'article', 'code', 'a',
14
+
15
+ "form", "input", "label", "button", "select", "textarea",
16
+ ] as const);
17
+ export const svgTagName = new Set([
18
+ "svg",
19
+ "line",
20
+ "path",
21
+ "polyline",
22
+ "circle",
23
+ "rect",
24
+ "g",
25
+ "text",
26
+ ] as const);
27
+
28
+ type SetValue<T extends Set<string>> = T extends Set<infer X> ? X : never;
29
+
30
+ export type HTMLTagName = SetValue<typeof htmlTagNames>;
31
+ export type SVGTagName = SetValue<typeof svgTagName>;
package/README.md DELETED
@@ -1,24 +0,0 @@
1
- # Act-Web
2
- The web renderer for Act, turning components into HTML or SVG elements.
3
- > ⚠️ Warning: This library is designed as an experiment, and should not be used for production.
4
-
5
- > ⚠️ Warning: This library is only available as an ESM.
6
-
7
- ## API
8
- ### `render`
9
- ```
10
- (root: Element, htmlRoot: HTMLElement) => void
11
- ```
12
- Starts the rendering of a root Act element, under a htmlRoot parent. You can create Act elements from the `@lukekaalim/act`'s `createElement` function.
13
-
14
- ```js
15
- import { h } from '@lukekaalim/act';
16
- import { render } from '@lukekaalim/act-web';
17
-
18
- const App = () => [
19
- h('h1', {}, 'Hello, World!'),
20
- h('p', {}, 'Welcome to my first webpage!'),
21
- ];
22
-
23
- render(h(App), document.body);
24
- ```
package/entry.d.ts DELETED
@@ -1,7 +0,0 @@
1
- import { Element } from "@lukekaalim/act";
2
-
3
- export const render: (actElement: Element, htmlElement: HTMLElement) => void
4
-
5
- export * from './renderer.js';
6
- export * from './props.js';
7
- export * from './node.js';
package/entry.js DELETED
@@ -1,6 +0,0 @@
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.d.ts DELETED
@@ -1 +0,0 @@
1
- export declare function setNodeChildren2(parent: Node, children: Node[]): void
package/node.js DELETED
@@ -1,54 +0,0 @@
1
- // @flow strict
2
- /*:: import type { Element } from '@lukekaalim/act'; */
3
- /*:: import type { RenderResult, RenderResult2 } from '@lukekaalim/act-renderer-core'; */
4
- /*:: import type { CommitDiff } from '@lukekaalim/act-reconciler'; */
5
-
6
- import { calculateIndexChanges } from "@lukekaalim/act-reconciler/util";
7
-
8
- export const createNode = (type/*: string*/, namespace/*: string*/)/*: Node*/ => {
9
- if (type === 'act:string')
10
- return document.createTextNode('');
11
- return document.createElementNS(namespace, type);
12
- };
13
- export const removeNode = (node/*: Node*/) => {
14
- const parent = node.parentNode;
15
- if (parent)
16
- parent.removeChild(node);
17
- }
18
- export const setNodeChildren = (parent/*: Node*/, children/*: RenderResult<Node>[]*/) => {
19
- const childrenToAttach = children.filter(r => !r.commit.suspension).map(r => r.node);
20
- const childrenToRemove = children.filter(r => r.commit.suspension).map(r => r.node);
21
- for (let i = 0; i < childrenToRemove.length; i++)
22
- removeNode(childrenToRemove[i]);
23
-
24
- // iterate backwards through the children
25
- for (let i = childrenToAttach.length; i > 0; i--) {
26
- const child = childrenToAttach[i - 1];
27
- const rightSibling = childrenToAttach[i];
28
- if (parent !== child.parentNode || (rightSibling && child.nextSibling !== rightSibling)) {
29
- parent.insertBefore(child, rightSibling);
30
- }
31
- }
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/prop.js DELETED
@@ -1,156 +0,0 @@
1
- // @flow strict
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'
9
-
10
- const propBlacklist = new Set(['ref', 'key', 'children']);
11
-
12
- export const setStylesProp = (
13
- element/*: HTMLElement | SVGElement*/,
14
- { prev, next }/*: PropDiff*/
15
- ) => {
16
- const style = element.style;
17
- const prevRules = typeof prev === 'object' && prev || {};
18
- const nextRules = typeof next === 'object' && next || {};
19
-
20
- const reg = calculatePropsDiff(prevRules, nextRules);
21
-
22
- for (const [rule, { next }] of reg.map) {
23
- const nextRuleValue = (typeof next === 'string' || typeof next === 'number') ? next : null;
24
- if (typeof (style/*: any*/)[rule] !== 'undefined')
25
- (style/*: any*/)[rule] = nextRuleValue;
26
- else
27
- if (nextRuleValue === null)
28
- style.removeProperty(rule);
29
- else
30
- style.setProperty(rule, nextRuleValue.toString());
31
- }
32
- };
33
-
34
- export const setEventListenerProp = (
35
- element/*: Element*/,
36
- { key, prev, next }/*: PropDiff*/
37
- ) => {
38
- const event = key.slice(2).toLowerCase();
39
-
40
- if (typeof prev === 'function')
41
- element.removeEventListener(event, ((prev/*: any*/)/*: EventListener*/));
42
- if (typeof next === 'function')
43
- element.addEventListener(event, ((next/*: any*/)/*: EventListener*/));
44
- };
45
-
46
- export const setAttributeProp = (
47
- element/*: Element*/,
48
- { key, prev, next }/*: PropDiff*/
49
- ) => {
50
- if (next === null && prev !== null)
51
- element.removeAttribute(key);
52
- else if (next !== null)
53
- switch (typeof next) {
54
- case 'string':
55
- element.setAttribute(key, next);
56
- case 'number':
57
- case 'boolean':
58
- element.setAttribute(key, next.toString());
59
- default:
60
- }
61
- };
62
-
63
- export const setDOMTokenList = (
64
- list/*: DOMTokenList*/,
65
- prop/*: PropDiff*/
66
- )/*: void*/ => {
67
- const next = prop.next;
68
- if (typeof prop.next === 'string')
69
- // $FlowFixMe
70
- return list.value = prop.next;
71
- else if (Array.isArray(next)) {
72
- const removed = [...list].filter(e => !next.includes(e));
73
- for (const item of removed)
74
- list.remove(item);
75
- for (const item of next)
76
- typeof item === 'string' && list.add(item);
77
- }
78
- }
79
-
80
- export const setHTMLProp = (
81
- element/*: HTMLElement | SVGElement*/,
82
- prop/*: PropDiff*/
83
- ) => {
84
- if (prop.key.startsWith('on'))
85
- setEventListenerProp(element, prop);
86
- else if (prop.key === 'style')
87
- setStylesProp(element, prop);
88
- else if (prop.key in element && !propBlacklist.has(prop.key) && element instanceof HTMLElement) {
89
- const htmlElement = (element/*: Object*/);
90
- if (htmlElement[prop.key] instanceof DOMTokenList)
91
- setDOMTokenList(htmlElement[prop.key], prop);
92
- else
93
- htmlElement[prop.key] = prop.next;
94
- }
95
- else
96
- setAttributeProp(element, prop);
97
- }
98
-
99
- export const setHTMLProps = (
100
- element/*: HTMLElement | SVGElement*/,
101
- registry/*: PropDiffRegistry*/
102
- ) => {
103
- for (const [_, propDiff] of registry.map)
104
- setHTMLProp(element, propDiff);
105
- };
106
-
107
- export const setTextProps = (
108
- element/*: Text*/,
109
- registry/*: PropDiffRegistry*/
110
- ) => {
111
- const content = registry.prop('content', '').next;
112
- if (content !== element.textContent)
113
- element.textContent = typeof content === 'string' ? content : '';
114
- };
115
-
116
- export const setProps = (
117
- element/*: ?Node*/,
118
- diff/*: CommitDiff*/
119
- ) => {
120
- const propDiff = calculatePropsDiff(diff.prev.element.props, diff.next.element.props);
121
- if (element instanceof HTMLElement || element instanceof SVGElement)
122
- setHTMLProps(element, propDiff);
123
- if (element instanceof Text)
124
- setTextProps(element, propDiff);
125
- };
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
-
140
- export const setRef = (
141
- node/*: ?Node*/,
142
- diff/*: CommitDiff*/
143
- ) => {;
144
- const ref/*: any*/ = diff.next.element.props['ref'];
145
- if (typeof ref === 'function') {
146
- if (diff.prev.pruned)
147
- (ref/*: Function*/)(node);
148
- else if (diff.next.pruned)
149
- (ref/*: Function*/)(null);
150
- } else if (ref && typeof ref === 'object') {
151
- if (diff.prev.pruned)
152
- ref['current'] = node;
153
- else if (diff.next.pruned)
154
- ref['current'] = null;
155
- }
156
- };
package/props.d.ts DELETED
@@ -1,7 +0,0 @@
1
- import { Diff3, DiffSet } from "@lukekaalim/act-reconciler";
2
-
3
- export declare function setWebProps2(
4
- element: Node,
5
- set: DiffSet,
6
- diff: Diff3,
7
- ): void;
package/reconciler.js DELETED
@@ -1,27 +0,0 @@
1
- // @flow strict
2
- /*:: import type { Element } from '@lukekaalim/act'; */
3
- import { createBoundaryService, createEffectService, createReconciler, createSchedule2, createTree, createTreeService2 } from '@lukekaalim/act-reconciler';
4
- import { createWebRenderer } from './renderer.js';
5
- import { setNodeChildren2 } from "./node.js";
6
-
7
- export const render = (element/*: Element*/, node/*: HTMLElement*/) => {
8
- const web = createWebRenderer();
9
-
10
- const onScheduleRequest = (callback) => {
11
- const id = requestAnimationFrame(() => callback(16));
12
- return () => cancelAnimationFrame(id);
13
- };
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
- setNodeChildren2(node, web.render(set, set.root));
21
- reconciler.tree.live.registry = effect.runEffectRegistry(set.registry);
22
-
23
- const map = boundary.calcBoundaryMap(set);
24
- boundary.getRootBoundaryValue(set.suspensions, set, map);
25
- });
26
- reconciler.tree.mount(element);
27
- };
package/renderer.d.ts DELETED
@@ -1,6 +0,0 @@
1
- import { ElementType } from "@lukekaalim/act";
2
- import { Renderer2 } from "@lukekaalim/act-renderer-core";
3
-
4
- export declare function createWebRenderer(
5
- getNextRenderer?: null | ((element: ElementType) => null | Renderer2<Node>),
6
- ): Renderer2<Node>
package/renderer.js DELETED
@@ -1,85 +0,0 @@
1
- // @flow strict
2
- /*::
3
- import type { ElementType } from '@lukekaalim/act';
4
- import type { CommitDiff, Commit } from '@lukekaalim/act-reconciler';
5
- import type { Renderer2 } from "../core/renderer2";
6
- */
7
- /*:: import type { Renderer, RenderResult } from '@lukekaalim/act-renderer-core'; */
8
- import { setProps, setRef, setWebProps2 } from './prop.js';
9
- import { createNode, removeNode, setNodeChildren, setNodeChildren2 } from './node.js';
10
- import { createRenderer2, setRef2 } from '@lukekaalim/act-renderer-core';
11
-
12
- export const createDOMRenderer = (
13
- namespace/*: string*/,
14
- getNextRenderer/*: null | (ElementType => null | Renderer2<Node>)*/ = null,
15
- )/*: Renderer2<Node>*/ => {
16
- const create = (type) => {
17
- return createNode(type, namespace);
18
- }
19
- const remove = (node, children, diff) => {
20
- setRef2(node, diff.commit, diff.change);
21
- removeNode(node);
22
- };
23
- const update = (node, set, diff) => {
24
- if (diff.change.type === 'create')
25
- setRef2(node, diff.commit, diff.change);
26
-
27
- setWebProps2(node, set, diff);
28
- }
29
- const attach = (node, set, diff, children) => {
30
- if (diff.commit.element.props["ignoreChildren"])
31
- return;
32
- setNodeChildren2(node, children);
33
- }
34
-
35
- const getRenderer = (set, commitId) => {
36
- const commit = set.nexts.map.get(commitId) || set.prevs.get(commitId);
37
- return getNextRenderer && getNextRenderer(commit.element.type) || nodeRenderer;
38
- }
39
-
40
- const getNodes = (set, commitId) => {
41
- const renderer = getRenderer(set, commitId)
42
- return renderer.getNodes(set, commitId);
43
- }
44
-
45
- const render = (set, commitId) => {
46
- const renderer = getRenderer(set, commitId)
47
- return renderer.render(set, commitId);
48
- }
49
-
50
- const nodeRenderer = createRenderer2({
51
- create,
52
- update,
53
- remove,
54
- attach,
55
- }, {
56
- getNodes,
57
- render,
58
- });
59
-
60
- return nodeRenderer;
61
- };
62
-
63
- export const createWebRenderer = (
64
- getNextRenderer/*: null | (ElementType => null | Renderer2<Node>)*/ = null,
65
- )/*: Renderer2<Node>*/ => {
66
- const svgRenderer = createDOMRenderer('http://www.w3.org/2000/svg', type => {
67
- switch (type) {
68
- case 'div':
69
- return htmlRenderer;
70
- default:
71
- return getNextRenderer && getNextRenderer(type);
72
- }
73
- })
74
-
75
- const htmlRenderer = createDOMRenderer('http://www.w3.org/1999/xhtml', type => {
76
- switch (type) {
77
- case 'svg':
78
- return svgRenderer;
79
- default:
80
- return getNextRenderer && getNextRenderer(type);
81
- }
82
- });
83
-
84
- return htmlRenderer;
85
- }