closures 0.7.1 → 0.7.3
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/README.md +51 -1
- package/dist/closures.cjs +428 -618
- package/dist/closures.js +426 -614
- package/dist/closures.min.js +1 -1
- package/package.json +1 -1
package/dist/closures.js
CHANGED
@@ -1,759 +1,571 @@
|
|
1
|
-
let
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
1
|
+
let NIL = void 0,
|
2
|
+
noop = _ => {},
|
3
|
+
propDirective = prop => ({
|
4
|
+
mount(el, value) {
|
5
|
+
el[prop] = value;
|
6
|
+
},
|
7
|
+
patch(el, newValue, oldValue) {
|
8
|
+
if (newValue !== oldValue) el[prop] = newValue;
|
9
|
+
},
|
10
|
+
unmount(el) {
|
11
|
+
el[prop] = NIL;
|
12
|
+
}
|
13
|
+
}),
|
12
14
|
DEFAULT_ENV = {
|
13
|
-
|
14
|
-
|
15
|
+
isSVG: false,
|
16
|
+
redraw: noop,
|
17
|
+
directives: {
|
18
|
+
selected: propDirective('selected'),
|
19
|
+
checked: propDirective('checked'),
|
20
|
+
value: propDirective('value'),
|
21
|
+
innerHTML: propDirective('innerHTML')
|
22
|
+
}
|
15
23
|
},
|
16
24
|
ON_REMOVES = [],
|
17
|
-
|
18
|
-
|
19
|
-
NS_ATTRS = { show: XLINK_NS, actuate: XLINK_NS, href: XLINK_NS },
|
25
|
+
CLOSURE_TO_FN = new WeakMap(),
|
26
|
+
ON_CREATE_KEY = 'oncreate',
|
20
27
|
NUM = 1,
|
28
|
+
PARENT_DOM_KEY = '$_REF',
|
29
|
+
EMPTY_OBJECT = {},
|
30
|
+
SVG_NS = 'http://www.w3.org/2000/svg',
|
31
|
+
XLINK_NS = 'http://www.w3.org/1999/xlink',
|
32
|
+
NS_ATTRS = { show: XLINK_NS, actuate: XLINK_NS, href: XLINK_NS },
|
33
|
+
REF_SINGLE = 1, // ref with single dom node
|
21
34
|
VTYPE_ELEMENT = 1,
|
35
|
+
REF_ARRAY = 4, // ref with array of nodes
|
36
|
+
REF_PARENT = 8, // ref with a child ref
|
22
37
|
VTYPE_FUNCTION = 2,
|
23
|
-
|
24
|
-
|
25
|
-
CMP_TO_CLOSURE = new WeakMap(),
|
26
|
-
CHILDS = new WeakMap(),
|
27
|
-
ID = _ => (NUM++).toString(),
|
28
|
-
noop = _ => {},
|
38
|
+
RETAIN_KEY = '=',
|
39
|
+
generateClosureId = _ => NUM++,
|
29
40
|
isFn = x => typeof x === 'function',
|
30
41
|
isStr = x => typeof x === 'string',
|
31
42
|
isObj = x => x !== null && typeof x === 'object',
|
32
43
|
isArr = x => Array.isArray(x),
|
33
|
-
|
44
|
+
toJson = v => JSON.stringify(v),
|
45
|
+
isEmpty = c => c === null || c === false || c === NIL || (isArr(c) && c.length === 0) || (c && c._t === RETAIN_KEY),
|
34
46
|
isNonEmptyArray = c => isArr(c) && c.length > 0,
|
35
|
-
isLeaf = c => isStr(c) || typeof c ===
|
47
|
+
isLeaf = c => isStr(c) || typeof c === 'number',
|
36
48
|
isElement = c => c && c.vtype === VTYPE_ELEMENT,
|
37
|
-
isRenderFunction = c => c && c.vtype === VTYPE_FUNCTION
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
49
|
+
isRenderFunction = c => c && c.vtype === VTYPE_FUNCTION;
|
50
|
+
|
51
|
+
let getDomNode = (ref) => {
|
52
|
+
let type = ref.type;
|
53
|
+
if (type === REF_SINGLE) return ref.node;
|
54
|
+
if (type === REF_PARENT) return getDomNode(ref.childRef);
|
55
|
+
if (type === REF_ARRAY) return getDomNode(ref.children[0]);
|
56
|
+
throw Error('Unknown ref type ' + toJson(ref));
|
57
|
+
};
|
58
|
+
|
59
|
+
let getNextSibling = ref => {
|
60
|
+
let type = ref.type;
|
61
|
+
if (type === REF_SINGLE) return ref.node.nextSibling;
|
62
|
+
if (type === REF_PARENT) return getNextSibling(ref.childRef);
|
63
|
+
if (type === REF_ARRAY) return getNextSibling(ref.children[ref.children.length - 1]);
|
64
|
+
throw Error('Unknown ref type ' + toJson(ref));
|
65
|
+
};
|
66
|
+
|
67
|
+
let insertDom = (parent, ref, nextSibling) => {
|
68
|
+
let type = ref.type;
|
69
|
+
if (type === REF_SINGLE) parent.insertBefore(ref.node, nextSibling);
|
70
|
+
else if (type === REF_PARENT) insertDom(parent, ref.childRef, nextSibling);
|
71
|
+
else if (type === REF_ARRAY)
|
72
|
+
for (let i = 0; i < ref.children.length; i++)
|
73
|
+
insertDom(parent, ref.children[i], nextSibling);
|
74
|
+
else throw Error('Unknown ref type ' + toJson(ref));
|
75
|
+
};
|
76
|
+
|
77
|
+
let removeDom = (parent, ref) => {
|
78
|
+
let type = ref.type;
|
79
|
+
if (type === REF_SINGLE) parent.removeChild(ref.node);
|
80
|
+
else if (type === REF_PARENT) removeDom(parent, ref.childRef);
|
81
|
+
else if (type === REF_ARRAY)
|
82
|
+
for (let i = 0; i < ref.children.length; i++)
|
83
|
+
removeDom(parent, ref.children[i]);
|
84
|
+
else throw Error('Unknown ref type ' + toJson(ref));
|
85
|
+
};
|
86
|
+
|
87
|
+
let replaceDom = (parent, newRef, oldRef) => {
|
88
|
+
insertDom(parent, newRef, getDomNode(oldRef));
|
89
|
+
removeDom(parent, oldRef);
|
90
|
+
};
|
91
|
+
|
92
|
+
let setDomAttribute = (el, attr, value, isSVG) => {
|
93
|
+
if (attr === 'className') attr = 'class';
|
94
|
+
if (value === true) el.setAttribute(attr, '');
|
95
|
+
else if (value === false) el.removeAttribute(attr);
|
96
|
+
else (isSVG && NS_ATTRS[attr])
|
97
|
+
? el.setAttributeNS(NS_ATTRS[attr], attr, value)
|
98
|
+
: el.setAttribute(attr, value);
|
99
|
+
};
|
100
|
+
|
101
|
+
let mountAttributes = (el, props, env) => {
|
102
|
+
for (let key in props) {
|
103
|
+
if (key === 'key' || key === 'children' || key === ON_CREATE_KEY || key in env.directives) continue;
|
104
|
+
else if (key.startsWith('on'))
|
105
|
+
el[key.toLowerCase()] = ev => { props[key](ev); !env.manualRedraw && env.redraw(); };
|
106
|
+
else setDomAttribute(el, key, props[key], env.isSVG);
|
107
|
+
}
|
108
|
+
};
|
42
109
|
|
43
|
-
|
110
|
+
let patchAttributes = (el, newProps, oldProps, env) => {
|
111
|
+
let key;
|
112
|
+
for (key in newProps) {
|
113
|
+
if (key === 'key' || key === 'children' || key === ON_CREATE_KEY || key in env.directives)
|
114
|
+
continue;
|
44
115
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
116
|
+
let oldValue = oldProps[key],
|
117
|
+
newValue = newProps[key];
|
118
|
+
|
119
|
+
if (oldValue !== newValue)
|
120
|
+
key.startsWith('on')
|
121
|
+
? el[key.toLowerCase()] = ev => { newValue(ev); !env.manualRedraw && env.redraw(); }
|
122
|
+
: setDomAttribute(el, key, newValue, env.isSVG);
|
123
|
+
}
|
50
124
|
|
51
|
-
|
52
|
-
children
|
53
|
-
|
54
|
-
: children.length === 1
|
55
|
-
? Object.assign({}, props, { children: children[0] })
|
56
|
-
: props;
|
125
|
+
for (key in oldProps) {
|
126
|
+
if (key === 'key' || key === 'children' || key in newProps || key in env.directives)
|
127
|
+
continue;
|
57
128
|
|
58
|
-
|
59
|
-
|
60
|
-
let idx = __tag.indexOf('.');
|
61
|
-
if (~idx) {
|
62
|
-
let className = __tag.slice(idx + 1).replace(/\./g, ' ')
|
63
|
-
props.class = props.class ? className + ' ' + String(props.class) : className;
|
64
|
-
__tag = __tag.slice(0, idx);
|
65
|
-
}
|
66
|
-
__tag = __tag ?? 'div';
|
129
|
+
if (key.startsWith('on')) el[key.toLowerCase()] = NIL;
|
130
|
+
else el.removeAttribute(key);
|
67
131
|
}
|
132
|
+
};
|
133
|
+
|
134
|
+
let mountDirectives = (el, props, env) => {
|
135
|
+
for (let key in props)
|
136
|
+
if (key in env.directives)
|
137
|
+
env.directives[key].mount(el, props[key]);
|
138
|
+
};
|
139
|
+
|
140
|
+
let patchDirectives = (el, newProps, oldProps, env) => {
|
141
|
+
let key;
|
142
|
+
for (key in newProps)
|
143
|
+
if (key in env.directives)
|
144
|
+
env.directives[key].patch(el, newProps[key], oldProps[key]);
|
145
|
+
|
146
|
+
for (key in oldProps)
|
147
|
+
if (key in env.directives && !(key in newProps))
|
148
|
+
env.directives[key].unmount(el, oldProps[key]);
|
149
|
+
};
|
68
150
|
|
69
|
-
|
70
|
-
|
151
|
+
let unmountDirectives = (el, props, env) => {
|
152
|
+
for (let key in props)
|
153
|
+
if (key in env.directives)
|
154
|
+
env.directives[key].unmount(el, props[key]);
|
155
|
+
};
|
71
156
|
|
72
|
-
|
73
|
-
|
74
|
-
let vtype =
|
75
|
-
isStr(__tag)
|
76
|
-
? VTYPE_ELEMENT
|
77
|
-
: isValidComponentType(__tag)
|
78
|
-
? VTYPE_COMPONENT
|
79
|
-
: isFn(__tag)
|
80
|
-
? VTYPE_FUNCTION
|
81
|
-
: undefined;
|
82
|
-
if (vtype === undefined) throw new Error("Invalid VNode type");
|
83
|
-
return {
|
84
|
-
vtype,
|
85
|
-
__tag,
|
86
|
-
key,
|
87
|
-
props,
|
88
|
-
};
|
89
|
-
}
|
157
|
+
let mount = (vnode, env, closureId, closure, onRemove = noop) => {
|
158
|
+
let baseRef = { closureId, closure, onRemove };
|
90
159
|
|
91
|
-
|
160
|
+
if (isEmpty(vnode))
|
161
|
+
return { ...baseRef, type: REF_SINGLE, node: document.createComment('NULL') };
|
92
162
|
|
93
|
-
|
94
|
-
|
95
|
-
let env = Object.assign({}, DEFAULT_ENV);
|
96
|
-
Object.assign(env.directives, options.directives);
|
97
|
-
if (rootRef == null) {
|
98
|
-
let ref = mount(vnode, env);
|
99
|
-
parentDomNode.$$PETIT_DOM_REF = { ref, vnode };
|
100
|
-
parentDomNode.textContent = "";
|
101
|
-
insertDom(parentDomNode, ref, null);
|
102
|
-
} else {
|
103
|
-
rootRef.ref = patchInPlace(
|
104
|
-
parentDomNode,
|
105
|
-
vnode,
|
106
|
-
rootRef.vnode,
|
107
|
-
rootRef.ref,
|
108
|
-
env
|
109
|
-
);
|
110
|
-
rootRef.vnode = vnode;
|
111
|
-
}
|
112
|
-
}
|
163
|
+
if (isLeaf(vnode))
|
164
|
+
return { ...baseRef, type: REF_SINGLE, node: document.createTextNode(vnode) };
|
113
165
|
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
this.props = props;
|
118
|
-
this._STATE_ = {
|
119
|
-
env,
|
120
|
-
vnode: null,
|
121
|
-
parentDomNode: null,
|
122
|
-
ref: mount(null)
|
123
|
-
};
|
124
|
-
this.render = this.render.bind(this);
|
125
|
-
}
|
166
|
+
if (isElement(vnode)) {
|
167
|
+
let node,
|
168
|
+
{ _t, props } = vnode;
|
126
169
|
|
127
|
-
|
128
|
-
|
129
|
-
this.props = props;
|
130
|
-
}
|
170
|
+
if (_t === 'svg' && !env.isSVG)
|
171
|
+
env = { ...env, isSVG: true };
|
131
172
|
|
132
|
-
|
133
|
-
|
134
|
-
let oldVNode = state.vnode;
|
135
|
-
state.vnode = vnode;
|
136
|
-
if (state.parentDomNode === null) {
|
137
|
-
let parentNode = getParentNode(state.ref);
|
138
|
-
if (parentNode === null) {
|
139
|
-
state.ref = mount(vnode, state.env);
|
140
|
-
return;
|
141
|
-
} else {
|
142
|
-
state.parentDomNode = parentNode;
|
143
|
-
}
|
144
|
-
}
|
145
|
-
// here we are sure state.parentDOMNode is defined
|
146
|
-
state.ref = patchInPlace(
|
147
|
-
state.parentDomNode,
|
148
|
-
vnode,
|
149
|
-
oldVNode,
|
150
|
-
state.ref,
|
151
|
-
state.env
|
152
|
-
);
|
153
|
-
}
|
154
|
-
}
|
155
|
-
|
156
|
-
function mount(vnode, env = DEFAULT_ENV) {
|
157
|
-
if (isEmpty(vnode)) {
|
158
|
-
return {
|
159
|
-
type: REF_SINGLE,
|
160
|
-
node: document.createComment("NULL"),
|
161
|
-
};
|
162
|
-
} else if (isLeaf(vnode)) {
|
163
|
-
return {
|
164
|
-
type: REF_SINGLE,
|
165
|
-
node: document.createTextNode(vnode),
|
166
|
-
};
|
167
|
-
} else if (isElement(vnode)) {
|
168
|
-
let node;
|
169
|
-
let { __tag, props } = vnode;
|
170
|
-
if (__tag === "svg" && !env.isSvg) {
|
171
|
-
env = Object.assign({}, env, { isSVG: true });
|
172
|
-
}
|
173
|
-
// TODO : {is} for custom elements
|
174
|
-
if (!env.isSVG) {
|
175
|
-
node = document.createElement(__tag);
|
176
|
-
} else {
|
177
|
-
node = document.createElementNS(SVG_NS, __tag);
|
178
|
-
}
|
173
|
+
if (!env.isSVG) node = document.createElement(_t);
|
174
|
+
else node = document.createElementNS(SVG_NS, _t);
|
179
175
|
|
180
|
-
|
181
|
-
if (isFn(props.oncreate)) props.oncreate(node);
|
176
|
+
isFn(props[ON_CREATE_KEY]) && props[ON_CREATE_KEY](node);
|
182
177
|
|
183
178
|
mountAttributes(node, props, env);
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
if (childrenRef != null) insertDom(node, childrenRef);
|
179
|
+
|
180
|
+
let children = props.children === NIL
|
181
|
+
? props.children
|
182
|
+
: mount(props.children, env);
|
183
|
+
|
184
|
+
if (children !== NIL) insertDom(node, children);
|
191
185
|
mountDirectives(node, props, env);
|
186
|
+
|
192
187
|
return {
|
188
|
+
...baseRef,
|
193
189
|
type: REF_SINGLE,
|
194
190
|
node,
|
195
|
-
children
|
196
|
-
}
|
197
|
-
}
|
191
|
+
children
|
192
|
+
}
|
193
|
+
}
|
194
|
+
|
195
|
+
if (isNonEmptyArray(vnode)) {
|
196
|
+
let i = 0, children = [];
|
197
|
+
for (; i < vnode.length; i++)
|
198
|
+
children.push(mount(vnode[i], env));
|
199
|
+
|
198
200
|
return {
|
201
|
+
...baseRef,
|
199
202
|
type: REF_ARRAY,
|
200
|
-
children
|
203
|
+
children
|
201
204
|
};
|
202
|
-
}
|
203
|
-
let childVNode = vnode.__tag(vnode.props);
|
205
|
+
}
|
204
206
|
|
205
|
-
|
206
|
-
|
207
|
-
view = childVNode,
|
208
|
-
id = ID(),
|
209
|
-
cmps = CLOSURE_TO_CMP.get(vnode.__tag) ?? {};
|
210
|
-
|
211
|
-
vnode.id = id;
|
212
|
-
cmp = toClosureCmp(vnode, view)
|
213
|
-
|
214
|
-
cmps[id] = cmp;
|
215
|
-
CLOSURE_TO_CMP.set(vnode.__tag, cmps);
|
216
|
-
CMP_TO_CLOSURE.set(cmp, vnode.__tag);
|
217
|
-
return mount(cmp);
|
218
|
-
}
|
207
|
+
if (isRenderFunction(vnode)) {
|
208
|
+
let childVnode = vnode._t(vnode.props); // if this is a closure component, this will be "oninit"
|
219
209
|
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
childs = CHILDS.get(parentCmp) || [],
|
233
|
-
idx = childs.length;
|
234
|
-
|
235
|
-
// attach method to remove self from parent
|
236
|
-
vnode.__tag.removeFromParent = _ => childs.splice(idx, 1);
|
237
|
-
|
238
|
-
childs.push({
|
239
|
-
id: vnode.id,
|
240
|
-
vtype: VTYPE_FUNCTION,
|
241
|
-
__tag: child_closure
|
242
|
-
});
|
243
|
-
|
244
|
-
CHILDS.set(parentCmp, childs);
|
210
|
+
if (isFn(childVnode)) {
|
211
|
+
// closure component
|
212
|
+
let id = generateClosureId(),
|
213
|
+
fnMap = CLOSURE_TO_FN.get(vnode._t) || new Map(),
|
214
|
+
onRemove = ON_REMOVES.pop() || noop;
|
215
|
+
|
216
|
+
fnMap.set(id, childVnode); // save renderFn
|
217
|
+
CLOSURE_TO_FN.set(vnode._t, fnMap); // closure -> Map(id -> renderFn)
|
218
|
+
|
219
|
+
let closure = vnode._t;
|
220
|
+
vnode._t = childVnode;
|
221
|
+
return mount(vnode, env, id, closure, onRemove);
|
245
222
|
}
|
246
223
|
|
247
|
-
vnode.__tag.mount(renderer);
|
248
224
|
return {
|
225
|
+
...baseRef,
|
249
226
|
type: REF_PARENT,
|
250
|
-
childRef:
|
251
|
-
childState:
|
227
|
+
childRef: mount(childVnode, env),
|
228
|
+
childState: childVnode
|
252
229
|
};
|
253
|
-
} else if (vnode instanceof Node) {
|
254
|
-
return {
|
255
|
-
type: REF_SINGLE,
|
256
|
-
node: vnode,
|
257
|
-
};
|
258
|
-
}
|
259
|
-
if (vnode === undefined) {
|
260
|
-
throw new Error("mount: vnode is undefined!");
|
261
230
|
}
|
262
231
|
|
263
|
-
|
264
|
-
}
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
newVNode,
|
269
|
-
oldVNode,
|
270
|
-
ref,
|
271
|
-
env = DEFAULT_ENV
|
272
|
-
) {
|
273
|
-
if (isObj(oldVNode) && isObj(newVNode))
|
274
|
-
newVNode.id = oldVNode.id;
|
275
|
-
|
276
|
-
if (oldVNode === newVNode) {
|
277
|
-
return ref;
|
278
|
-
} else if (isEmpty(newVNode) && isEmpty(oldVNode)) {
|
279
|
-
return ref;
|
280
|
-
} else if (isLeaf(newVNode) && isLeaf(oldVNode)) {
|
281
|
-
ref.node.nodeValue = newVNode;
|
282
|
-
return ref;
|
283
|
-
} else if (
|
284
|
-
isElement(newVNode) &&
|
285
|
-
isElement(oldVNode) &&
|
286
|
-
newVNode.__tag === oldVNode.__tag
|
287
|
-
) {
|
288
|
-
if (newVNode.__tag === "svg" && !env.isSvg) {
|
289
|
-
env = Object.assign({}, env, { isSVG: true });
|
290
|
-
}
|
291
|
-
patchAttributes(ref.node, newVNode.props, oldVNode.props, env);
|
292
|
-
let oldChildren = oldVNode.props.children;
|
293
|
-
let newChildren = newVNode.props.children;
|
294
|
-
if (oldChildren == null) {
|
295
|
-
if (newChildren != null) {
|
296
|
-
ref.children = mount(newChildren, env);
|
297
|
-
insertDom(ref.node, ref.children);
|
298
|
-
}
|
299
|
-
} else {
|
300
|
-
if (newChildren == null) {
|
301
|
-
ref.node.textContent = "";
|
302
|
-
unmount(oldChildren, ref.children, env);
|
303
|
-
ref.children = null;
|
304
|
-
} else {
|
305
|
-
ref.children = patchInPlace(
|
306
|
-
ref.node,
|
307
|
-
newChildren,
|
308
|
-
oldChildren,
|
309
|
-
ref.children,
|
310
|
-
env
|
311
|
-
);
|
312
|
-
}
|
313
|
-
}
|
314
|
-
patchDirectives(ref.node, newVNode.props, oldVNode.props, env);
|
315
|
-
return ref;
|
316
|
-
} else if (isNonEmptyArray(newVNode) && isNonEmptyArray(oldVNode)) {
|
317
|
-
patchChildren(parentDomNode, newVNode, oldVNode, ref, env);
|
318
|
-
return ref;
|
319
|
-
} else if (
|
320
|
-
isRenderFunction(newVNode) &&
|
321
|
-
isRenderFunction(oldVNode) &&
|
322
|
-
newVNode.__tag === oldVNode.__tag
|
323
|
-
) {
|
324
|
-
let renderFn = newVNode.__tag;
|
325
|
-
let shouldUpdate =
|
326
|
-
renderFn.shouldUpdate != null
|
327
|
-
? renderFn.shouldUpdate(oldVNode.props, newVNode.props)
|
328
|
-
: defaultShouldUpdate(oldVNode.props, newVNode.props);
|
329
|
-
if (shouldUpdate) {
|
330
|
-
let cmp,
|
331
|
-
id = oldVNode.id,
|
332
|
-
cmps = CLOSURE_TO_CMP.get(renderFn);
|
333
|
-
|
334
|
-
if (cmps && id && (cmp = cmps[id])) {
|
335
|
-
return patch(
|
336
|
-
parentDomNode,
|
337
|
-
{ ...cmp, props: newVNode.props },
|
338
|
-
cmp,
|
339
|
-
ref
|
340
|
-
);
|
341
|
-
}
|
232
|
+
if (vnode instanceof Node)
|
233
|
+
return { ...baseRef, type: REF_SINGLE, node: vnode };
|
234
|
+
|
235
|
+
if (vnode === NIL)
|
236
|
+
throw Error('mount: vnode is undefined');
|
342
237
|
|
343
|
-
|
344
|
-
|
345
|
-
parentDomNode,
|
346
|
-
childVNode,
|
347
|
-
ref.childState,
|
348
|
-
ref.childRef,
|
349
|
-
env
|
350
|
-
);
|
351
|
-
// We need to return a new ref in order for parent patches to
|
352
|
-
// properly replace changing DOM nodes
|
353
|
-
if (childRef !== ref.childRef) {
|
354
|
-
return {
|
355
|
-
type: REF_PARENT,
|
356
|
-
childRef,
|
357
|
-
childState: childVNode,
|
358
|
-
};
|
359
|
-
} else {
|
360
|
-
ref.childState = childVNode;
|
361
|
-
return ref;
|
362
|
-
}
|
363
|
-
} else {
|
364
|
-
return ref;
|
365
|
-
}
|
366
|
-
} else if (
|
367
|
-
isComponent(newVNode) &&
|
368
|
-
isComponent(oldVNode) &&
|
369
|
-
newVNode.__tag === oldVNode.__tag
|
370
|
-
) {
|
371
|
-
let renderer = ref.childState;
|
372
|
-
let state = renderer._STATE_;
|
373
|
-
state.env = env;
|
374
|
-
state.parentNode = parentDomNode;
|
375
|
-
renderer.setProps(newVNode.props);
|
376
|
-
newVNode.__tag.patch(renderer);
|
377
|
-
if (ref.childRef !== state.ref) {
|
378
|
-
return {
|
379
|
-
type: REF_PARENT,
|
380
|
-
childRef: state.ref,
|
381
|
-
childState: renderer,
|
382
|
-
};
|
383
|
-
} else {
|
384
|
-
return ref;
|
385
|
-
}
|
386
|
-
} else if (newVNode instanceof Node && oldVNode instanceof Node) {
|
387
|
-
ref.node = newVNode;
|
388
|
-
return ref;
|
389
|
-
} else {
|
390
|
-
return mount(newVNode, env);
|
391
|
-
}
|
392
|
-
}
|
238
|
+
throw Error('mount: Invalid vnode');
|
239
|
+
};
|
393
240
|
|
394
|
-
|
395
|
-
* Execute any compoenent specific unmount code
|
396
|
-
*/
|
397
|
-
function unmount(vnode, ref, env) {
|
398
|
-
// if (vnode instanceof Node || isEmpty(vnode) || isLeaf(vnode)) return;
|
241
|
+
let unmount = (vnode, ref, env) => {
|
399
242
|
if (isElement(vnode)) {
|
400
243
|
unmountDirectives(ref.node, vnode.props, env);
|
401
|
-
if (vnode.props.children
|
244
|
+
if (vnode.props.children !== NIL)
|
402
245
|
unmount(vnode.props.children, ref.children, env);
|
403
246
|
} else if (isNonEmptyArray(vnode)) {
|
404
|
-
vnode.
|
405
|
-
unmount(
|
406
|
-
);
|
247
|
+
for (let i = 0; i < vnode.length; i++)
|
248
|
+
unmount(vnode[i], ref.children[i], env);
|
407
249
|
} else if (isRenderFunction(vnode)) {
|
408
|
-
let
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
250
|
+
let closure = ref.closure,
|
251
|
+
closureId = ref.closureId,
|
252
|
+
onRemove = ref.onRemove,
|
253
|
+
fns = CLOSURE_TO_FN.get(closure);
|
254
|
+
|
255
|
+
if (fns && closureId && fns.get(closureId)) {
|
256
|
+
fns.delete(closureId);
|
257
|
+
!fns.size && CLOSURE_TO_FN.delete(closure);
|
258
|
+
onRemove();
|
413
259
|
}
|
414
260
|
|
415
261
|
unmount(ref.childState, ref.childRef, env);
|
416
|
-
} else if (isComponent(vnode)) {
|
417
|
-
vnode.__tag.unmount(ref.childState);
|
418
262
|
}
|
419
|
-
}
|
263
|
+
};
|
264
|
+
|
265
|
+
let patchInPlace = (parentDomNode, newVnode, oldVnode, ref, env) => {
|
266
|
+
let newRef = patch(parentDomNode, newVnode, oldVnode, ref, env);
|
420
267
|
|
421
|
-
function patchInPlace(parentDomNode, newVNode, oldVNode, ref, env) {
|
422
|
-
let newRef = patch(parentDomNode, newVNode, oldVNode, ref, env);
|
423
268
|
if (newRef !== ref) {
|
424
269
|
replaceDom(parentDomNode, newRef, ref);
|
425
|
-
unmount(
|
270
|
+
unmount(oldVnode, ref, env);
|
426
271
|
}
|
272
|
+
|
427
273
|
return newRef;
|
428
|
-
}
|
429
|
-
|
430
|
-
|
431
|
-
//
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
274
|
+
};
|
275
|
+
|
276
|
+
let patchChildren = (parentDomNode, newChildren, oldChildren, ref, env) => {
|
277
|
+
// we need to retrieve the next sibling before the old children get removed from the DOM
|
278
|
+
let i, idx, oldVnode, newVnode, oldRef, newRef, refMap, beforeNode,
|
279
|
+
nextNode = getNextSibling(ref),
|
280
|
+
children = Array(newChildren.length),
|
281
|
+
refChildren = ref.children,
|
282
|
+
newStart = 0,
|
437
283
|
oldStart = 0,
|
438
284
|
newEnd = newChildren.length - 1,
|
439
|
-
oldEnd =
|
440
|
-
|
441
|
-
|
285
|
+
oldEnd = oldChildren.length - 1;
|
286
|
+
|
442
287
|
while (newStart <= newEnd && oldStart <= oldEnd) {
|
443
|
-
if (refChildren[oldStart] ===
|
288
|
+
if (refChildren[oldStart] === NIL) {
|
444
289
|
oldStart++;
|
445
290
|
continue;
|
446
291
|
}
|
447
|
-
|
292
|
+
|
293
|
+
if (refChildren[oldEnd] === NIL) {
|
448
294
|
oldEnd--;
|
449
295
|
continue;
|
450
296
|
}
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
297
|
+
|
298
|
+
oldVnode = oldChildren[oldStart];
|
299
|
+
newVnode = newChildren[newStart];
|
300
|
+
|
301
|
+
if (oldVnode && newVnode && newVnode.key === oldVnode.key) {
|
455
302
|
oldRef = refChildren[oldStart];
|
456
303
|
newRef = children[newStart] = patchInPlace(
|
457
304
|
parentDomNode,
|
458
|
-
|
459
|
-
|
305
|
+
newVnode,
|
306
|
+
oldVnode,
|
460
307
|
oldRef,
|
461
308
|
env
|
462
309
|
);
|
310
|
+
|
463
311
|
newStart++;
|
464
312
|
oldStart++;
|
465
313
|
continue;
|
466
314
|
}
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
315
|
+
|
316
|
+
oldVnode = oldChildren[oldEnd];
|
317
|
+
newVnode = newChildren[newEnd];
|
318
|
+
|
319
|
+
if (oldVnode && newVnode && newVnode.key === oldVnode.key) {
|
471
320
|
oldRef = refChildren[oldEnd];
|
472
321
|
newRef = children[newEnd] = patchInPlace(
|
473
322
|
parentDomNode,
|
474
|
-
|
475
|
-
|
323
|
+
newVnode,
|
324
|
+
oldVnode,
|
476
325
|
oldRef,
|
477
326
|
env
|
478
327
|
);
|
328
|
+
|
479
329
|
newEnd--;
|
480
330
|
oldEnd--;
|
481
331
|
continue;
|
482
332
|
}
|
483
|
-
|
484
|
-
if (refMap
|
485
|
-
refMap = {};
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
refMap[oldVNode.key] = i;
|
490
|
-
}
|
333
|
+
|
334
|
+
if (refMap === NIL)
|
335
|
+
for (i = oldStart, refMap = {}; i <= oldEnd; i++) {
|
336
|
+
oldVnode = oldChildren[i];
|
337
|
+
if (oldVnode && oldVnode.key !== NIL)
|
338
|
+
refMap[oldVnode.key] = i;
|
491
339
|
}
|
492
|
-
|
340
|
+
|
341
|
+
newVnode = newChildren[newStart];
|
342
|
+
idx = newVnode && newVnode.key !== NIL ? refMap[newVnode.key] : NIL;
|
493
343
|
|
494
|
-
|
495
|
-
|
496
|
-
if (idx != null) {
|
497
|
-
oldVNode = oldchildren[idx];
|
344
|
+
if (idx !== NIL) {
|
345
|
+
oldVnode = oldChildren[idx];
|
498
346
|
oldRef = refChildren[idx];
|
499
347
|
newRef = children[newStart] = patch(
|
500
348
|
parentDomNode,
|
501
|
-
|
502
|
-
|
349
|
+
newVnode,
|
350
|
+
oldVnode,
|
503
351
|
oldRef,
|
504
352
|
env
|
505
353
|
);
|
354
|
+
|
506
355
|
insertDom(parentDomNode, newRef, getDomNode(refChildren[oldStart]));
|
356
|
+
|
507
357
|
if (newRef !== oldRef) {
|
508
358
|
removeDom(parentDomNode, oldRef);
|
509
|
-
unmount(
|
359
|
+
unmount(oldVnode, oldRef, env);
|
510
360
|
}
|
511
|
-
|
361
|
+
|
362
|
+
refChildren[idx] = NIL;
|
512
363
|
} else {
|
513
|
-
newRef = children[newStart] = mount(
|
364
|
+
newRef = children[newStart] = mount(newVnode, env);
|
514
365
|
insertDom(parentDomNode, newRef, getDomNode(refChildren[oldStart]));
|
515
366
|
}
|
367
|
+
|
516
368
|
newStart++;
|
517
369
|
}
|
518
|
-
|
519
|
-
|
520
|
-
newEnd
|
521
|
-
|
522
|
-
|
370
|
+
|
371
|
+
beforeNode = newEnd < newChildren.length - 1
|
372
|
+
? getDomNode(children[newEnd + 1])
|
373
|
+
: nextNode;
|
374
|
+
|
523
375
|
while (newStart <= newEnd) {
|
524
|
-
|
376
|
+
newRef = mount(newChildren[newStart], env);
|
525
377
|
children[newStart] = newRef;
|
526
378
|
insertDom(parentDomNode, newRef, beforeNode);
|
527
379
|
newStart++;
|
528
380
|
}
|
381
|
+
|
529
382
|
while (oldStart <= oldEnd) {
|
530
383
|
oldRef = refChildren[oldStart];
|
531
|
-
|
384
|
+
|
385
|
+
if (oldRef !== NIL) {
|
532
386
|
removeDom(parentDomNode, oldRef);
|
533
|
-
unmount(
|
387
|
+
unmount(oldChildren[oldStart], oldRef, env);
|
534
388
|
}
|
389
|
+
|
535
390
|
oldStart++;
|
536
391
|
}
|
392
|
+
|
537
393
|
ref.children = children;
|
538
|
-
}
|
394
|
+
};
|
539
395
|
|
540
|
-
|
541
|
-
if (
|
542
|
-
for (let key in p2) {
|
543
|
-
if (p1[key] !== p2[key]) return true;
|
544
|
-
}
|
545
|
-
return false;
|
546
|
-
}
|
396
|
+
let patch = (parentDomNode, newVnode, oldVnode, ref, env = { ...DEFAULT_ENV }) => {
|
397
|
+
if (newVnode && newVnode._t === RETAIN_KEY) return ref;
|
547
398
|
|
548
|
-
|
549
|
-
return {
|
550
|
-
mount(element, value) {``
|
551
|
-
element[prop] = value;
|
552
|
-
},
|
553
|
-
patch(element, newValue, oldValue) {
|
554
|
-
if (newValue !== oldValue) {
|
555
|
-
element[prop] = newValue;
|
556
|
-
}
|
557
|
-
},
|
558
|
-
unmount(element, _) {
|
559
|
-
element[prop] = null;
|
560
|
-
},
|
561
|
-
};
|
562
|
-
}
|
399
|
+
let closure, closureId;
|
563
400
|
|
564
|
-
|
565
|
-
|
566
|
-
|
567
|
-
} else if (ref.type === REF_ARRAY) {
|
568
|
-
return getDomNode(ref.children[0]);
|
569
|
-
} else if (ref.type === REF_PARENT) {
|
570
|
-
return getDomNode(ref.childRef);
|
401
|
+
if (isObj(ref)) {
|
402
|
+
closure = ref.closure;
|
403
|
+
closureId = ref.closureId;
|
571
404
|
}
|
572
|
-
throw new Error("Unkown ref type " + JSON.stringify(ref));
|
573
|
-
}
|
574
405
|
|
575
|
-
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
} else if (ref.type === REF_PARENT) {
|
581
|
-
return getParentNode(ref.childRef);
|
582
|
-
}
|
583
|
-
throw new Error("Unkown ref type " + ref);
|
584
|
-
}
|
406
|
+
if (isRenderFunction(newVnode) && isRenderFunction(oldVnode) && (newVnode._t === oldVnode._t || (closure && closureId))) {
|
407
|
+
// x is either a renderFn or a closure
|
408
|
+
let x = newVnode._t,
|
409
|
+
fn,
|
410
|
+
fns = CLOSURE_TO_FN.get(closure);
|
585
411
|
|
586
|
-
|
587
|
-
|
588
|
-
return ref.node.nextSibling;
|
589
|
-
} else if (ref.type === REF_ARRAY) {
|
590
|
-
return getNextSibling(ref.children[ref.children.length - 1]);
|
591
|
-
} else if (ref.type === REF_PARENT) {
|
592
|
-
return getNextSibling(ref.childRef);
|
593
|
-
}
|
594
|
-
throw new Error("Unkown ref type " + JSON.stringify(ref));
|
595
|
-
}
|
412
|
+
if (fns && closureId && (fn = fns.get(closureId)))
|
413
|
+
x = fn;
|
596
414
|
|
597
|
-
|
598
|
-
|
599
|
-
|
600
|
-
|
601
|
-
|
602
|
-
|
603
|
-
|
604
|
-
|
605
|
-
insertDom(parent, ref.childRef, nextSibling);
|
606
|
-
} else {
|
607
|
-
throw new Error("Unkown ref type " + JSON.stringify(ref));
|
608
|
-
}
|
609
|
-
}
|
415
|
+
let childVnode = x(newVnode.props),
|
416
|
+
childRef = patch(
|
417
|
+
parentDomNode,
|
418
|
+
childVnode,
|
419
|
+
ref.childState,
|
420
|
+
ref.childRef,
|
421
|
+
env
|
422
|
+
);
|
610
423
|
|
611
|
-
|
612
|
-
|
613
|
-
|
614
|
-
|
615
|
-
|
616
|
-
|
617
|
-
|
618
|
-
|
619
|
-
|
620
|
-
|
621
|
-
|
424
|
+
// we need to return a new ref in order for parent patches to properly replace changing DOM nodes
|
425
|
+
if (childRef !== ref.childRef)
|
426
|
+
return {
|
427
|
+
type: REF_PARENT,
|
428
|
+
childRef,
|
429
|
+
childState: childVnode
|
430
|
+
};
|
431
|
+
else {
|
432
|
+
ref.childState = childVnode;
|
433
|
+
return ref;
|
434
|
+
}
|
622
435
|
}
|
623
|
-
}
|
624
436
|
|
625
|
-
|
626
|
-
|
627
|
-
removeDom(parent, oldRef);
|
628
|
-
}
|
437
|
+
if (oldVnode === newVnode || (isEmpty(newVnode) && isEmpty(oldVnode)))
|
438
|
+
return ref;
|
629
439
|
|
630
|
-
|
631
|
-
|
632
|
-
|
633
|
-
|
634
|
-
}
|
440
|
+
if (isLeaf(newVnode) && isLeaf(oldVnode)) {
|
441
|
+
// leafs just need to have node value updated
|
442
|
+
ref.node.nodeValue = newVnode;
|
443
|
+
return ref;
|
635
444
|
}
|
636
|
-
}
|
637
445
|
|
638
|
-
|
639
|
-
|
640
|
-
if (
|
641
|
-
env
|
642
|
-
}
|
643
|
-
}
|
644
|
-
for (let key in oldProps) {
|
645
|
-
if (key in env.directives && !(key in newProps)) {
|
646
|
-
env.directives[key].unmount(domElement, oldProps[key]);
|
647
|
-
}
|
648
|
-
}
|
649
|
-
}
|
446
|
+
if (isElement(newVnode) && isElement(oldVnode) && newVnode._t === oldVnode._t) {
|
447
|
+
// make sure env has isSVG flag set to true
|
448
|
+
if (newVnode._t === 'svg' && !env.isSVG)
|
449
|
+
env = { ...env, isSVG: true };
|
650
450
|
|
651
|
-
|
652
|
-
|
653
|
-
if (key in env.directives) {
|
654
|
-
env.directives[key].unmount(domElement, props[key]);
|
655
|
-
}
|
656
|
-
}
|
657
|
-
}
|
451
|
+
// update the node DOM attributes with the new props
|
452
|
+
patchAttributes(ref.node, newVnode.props, oldVnode.props, env);
|
658
453
|
|
659
|
-
|
660
|
-
|
661
|
-
if (key === "key" || key === "children" || key in env.directives) continue;
|
662
|
-
if (key.startsWith("on")) {
|
663
|
-
let cmp = MOUNTING[MOUNTING.length - 1];
|
664
|
-
domElement[key.toLowerCase()] = cmp ? cmp.__tag.event(props[key]) : props[key];
|
665
|
-
} else {
|
666
|
-
setDOMAttribute(domElement, key, props[key], env.isSVG);
|
667
|
-
}
|
668
|
-
}
|
669
|
-
}
|
454
|
+
let oldChildren = oldVnode.props.children,
|
455
|
+
newChildren = newVnode.props.children;
|
670
456
|
|
671
|
-
|
672
|
-
|
673
|
-
|
674
|
-
|
675
|
-
|
676
|
-
|
677
|
-
if (
|
678
|
-
|
679
|
-
|
457
|
+
if (oldChildren === NIL) {
|
458
|
+
if (newChildren !== NIL) {
|
459
|
+
ref.children = mount(newChildren, env);
|
460
|
+
insertDom(ref.node, ref.children);
|
461
|
+
}
|
462
|
+
} else {
|
463
|
+
if (newChildren === NIL) {
|
464
|
+
ref.node.textContent = '';
|
465
|
+
unmount(oldChildren, ref.children, env);
|
466
|
+
ref.children = NIL;
|
680
467
|
} else {
|
681
|
-
|
468
|
+
ref.children = patchInPlace(
|
469
|
+
ref.node,
|
470
|
+
newChildren,
|
471
|
+
oldChildren,
|
472
|
+
ref.children,
|
473
|
+
env
|
474
|
+
);
|
682
475
|
}
|
683
476
|
}
|
477
|
+
|
478
|
+
patchDirectives(ref.node, newVnode.props, oldVnode.props, env);
|
479
|
+
return ref;
|
684
480
|
}
|
685
|
-
|
686
|
-
|
687
|
-
|
688
|
-
|
689
|
-
key in env.directives ||
|
690
|
-
key in newProps
|
691
|
-
)
|
692
|
-
continue;
|
693
|
-
if (key.startsWith("on")) {
|
694
|
-
domElement[key.toLowerCase()] = null;
|
695
|
-
} else {
|
696
|
-
domElement.removeAttribute(key);
|
697
|
-
}
|
481
|
+
|
482
|
+
if (isNonEmptyArray(newVnode) && isNonEmptyArray(oldVnode)) {
|
483
|
+
patchChildren(parentDomNode, newVnode, oldVnode, ref, env);
|
484
|
+
return ref;
|
698
485
|
}
|
699
|
-
}
|
700
486
|
|
701
|
-
|
702
|
-
|
703
|
-
|
704
|
-
} else if (value === false) {
|
705
|
-
el.removeAttribute(attr);
|
706
|
-
} else {
|
707
|
-
var namespace = isSVG ? NS_ATTRS[attr] : undefined;
|
708
|
-
if (namespace !== undefined) {
|
709
|
-
el.setAttributeNS(namespace, attr, value);
|
710
|
-
} else {
|
711
|
-
el.setAttribute(attr, value);
|
712
|
-
}
|
487
|
+
if (newVnode instanceof Node && oldVnode instanceof Node) {
|
488
|
+
ref.node = newVnode;
|
489
|
+
return ref;
|
713
490
|
}
|
714
|
-
}
|
715
491
|
|
716
|
-
|
717
|
-
|
718
|
-
|
719
|
-
|
720
|
-
|
721
|
-
|
722
|
-
|
723
|
-
|
724
|
-
view,
|
725
|
-
removeFromParent: noop,
|
726
|
-
event: noop,
|
727
|
-
mount: render,
|
728
|
-
patch: render,
|
729
|
-
unmount: _ => {
|
730
|
-
onRemove();
|
731
|
-
let childs;
|
732
|
-
if (childs = CHILDS.get(cmp)) {
|
733
|
-
for (let i = 0; i < childs.length; i++) {
|
734
|
-
unmount(childs[i], EMPTY_OBJECT);
|
735
|
-
}
|
736
|
-
|
737
|
-
CHILDS.delete(cmp);
|
738
|
-
}
|
739
|
-
|
740
|
-
cmp.__tag.removeFromParent();
|
741
|
-
}
|
742
|
-
}
|
743
|
-
};
|
744
|
-
|
745
|
-
function render(ctx) {
|
746
|
-
cmp.__tag.event = fn => ev => {
|
747
|
-
fn(ev);
|
748
|
-
MOUNTING.push(cmp);
|
749
|
-
ctx.render(view({ ...ctx.props }));
|
750
|
-
MOUNTING.pop();
|
751
|
-
};
|
492
|
+
return mount(newVnode, env);
|
493
|
+
};
|
494
|
+
|
495
|
+
export function h(_t, ...children) {
|
496
|
+
let idx, props = children[0];
|
497
|
+
if (props && isObj(props) && !isArr(props) && !(props._t || props.props))
|
498
|
+
children.shift();
|
499
|
+
else props = EMPTY_OBJECT;
|
752
500
|
|
753
|
-
|
754
|
-
|
755
|
-
|
501
|
+
props =
|
502
|
+
children.length > 1
|
503
|
+
? { ...props, children }
|
504
|
+
: children.length === 1
|
505
|
+
? { ...props, children: children[0] }
|
506
|
+
: props;
|
507
|
+
|
508
|
+
// inline class parsing
|
509
|
+
if (isStr(_t) && ~(idx = _t.indexOf('.'))) {
|
510
|
+
let className = _t.slice(idx + 1).replace(/\./g, ' ')
|
511
|
+
props.class = props.class ? className + ' ' + String(props.class) : className;
|
512
|
+
_t = _t.slice(0, idx);
|
756
513
|
}
|
757
514
|
|
758
|
-
|
515
|
+
if (props.key !== props.key) throw new Error("Invalid NaN key");
|
516
|
+
|
517
|
+
let vtype =
|
518
|
+
isStr(_t)
|
519
|
+
? VTYPE_ELEMENT
|
520
|
+
: _t && isFn(_t.mount)
|
521
|
+
? VTYPE_COMPONENT
|
522
|
+
: isFn(_t)
|
523
|
+
? VTYPE_FUNCTION
|
524
|
+
: NIL;
|
525
|
+
|
526
|
+
if (vtype === NIL) throw new Error("Invalid VNode type");
|
527
|
+
|
528
|
+
// returns a vnode
|
529
|
+
return {
|
530
|
+
vtype, // (number) VTYPE_ELEMENT | VTYPE_COMPONENT | VTYPE_FUNCTION
|
531
|
+
_t, // (string | object | function)
|
532
|
+
key: props.key, // string
|
533
|
+
props // object
|
534
|
+
};
|
759
535
|
}
|
536
|
+
|
537
|
+
h.retain = _ => h(RETAIN_KEY);
|
538
|
+
|
539
|
+
export const m = h;
|
540
|
+
|
541
|
+
export const Fragment = props => props.children;
|
542
|
+
|
543
|
+
export const onRemove = fn => ON_REMOVES.push(fn);
|
544
|
+
|
545
|
+
export function app(vnode, parentDomNode, opts = {}) {
|
546
|
+
let ref,
|
547
|
+
env = { ...DEFAULT_ENV, manualRedraw: opts.manualRedraw },
|
548
|
+
rootRef = parentDomNode[PARENT_DOM_KEY];
|
549
|
+
|
550
|
+
env.directives = { ...env.directives, ...(opts.directives || {}) };
|
551
|
+
|
552
|
+
if (rootRef !== NIL)
|
553
|
+
throw Error('App already mounted on this node');
|
554
|
+
|
555
|
+
ref = mount(vnode, env);
|
556
|
+
rootRef = parentDomNode[PARENT_DOM_KEY] = { ref, vnode };
|
557
|
+
parentDomNode.textContent = '';
|
558
|
+
insertDom(parentDomNode, ref, NIL);
|
559
|
+
|
560
|
+
return env.redraw = (newVnode = vnode) => {
|
561
|
+
rootRef.ref = patchInPlace(
|
562
|
+
parentDomNode,
|
563
|
+
newVnode,
|
564
|
+
rootRef.vnode,
|
565
|
+
rootRef.ref,
|
566
|
+
env
|
567
|
+
);
|
568
|
+
|
569
|
+
rootRef.vnode = newVnode;
|
570
|
+
};
|
571
|
+
}
|