closures 0.7.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/LICENSE +21 -0
- package/README.md +3 -0
- package/dist/closures.cjs +766 -0
- package/dist/closures.js +759 -0
- package/dist/closures.min.js +1 -0
- package/package.json +32 -0
@@ -0,0 +1,766 @@
|
|
1
|
+
let EMPTY_OBJECT = {},
|
2
|
+
REF_SINGLE = 1, // ref with a single dom node
|
3
|
+
REF_ARRAY = 4, // ref with an array od nodes
|
4
|
+
REF_PARENT = 8, // ref with a child ref
|
5
|
+
SVG_NS = "http://www.w3.org/2000/svg",
|
6
|
+
DOM_PROPS_DIRECTIVES = {
|
7
|
+
selected: propDirective("selected"),
|
8
|
+
checked: propDirective("checked"),
|
9
|
+
value: propDirective("value"),
|
10
|
+
innerHTML: propDirective("innerHTML"),
|
11
|
+
},
|
12
|
+
DEFAULT_ENV = {
|
13
|
+
isSvg: false,
|
14
|
+
directives: DOM_PROPS_DIRECTIVES,
|
15
|
+
},
|
16
|
+
ON_REMOVES = [],
|
17
|
+
MOUNTING = [],
|
18
|
+
XLINK_NS = "http://www.w3.org/1999/xlink",
|
19
|
+
NS_ATTRS = { show: XLINK_NS, actuate: XLINK_NS, href: XLINK_NS },
|
20
|
+
NUM = 1,
|
21
|
+
VTYPE_ELEMENT = 1,
|
22
|
+
VTYPE_FUNCTION = 2,
|
23
|
+
VTYPE_COMPONENT = 4,
|
24
|
+
CLOSURE_TO_CMP = new WeakMap(),
|
25
|
+
CMP_TO_CLOSURE = new WeakMap(),
|
26
|
+
CHILDS = new WeakMap(),
|
27
|
+
ID = _ => (NUM++).toString(),
|
28
|
+
noop = _ => {},
|
29
|
+
isFn = x => typeof x === 'function',
|
30
|
+
isStr = x => typeof x === 'string',
|
31
|
+
isObj = x => x !== null && typeof x === 'object',
|
32
|
+
isArr = x => Array.isArray(x),
|
33
|
+
isEmpty = c => c === null || c === false || c === undefined || (isArr(c) && c.length === 0),
|
34
|
+
isNonEmptyArray = c => isArr(c) && c.length > 0,
|
35
|
+
isLeaf = c => isStr(c) || typeof c === "number",
|
36
|
+
isElement = c => c && c.vtype === VTYPE_ELEMENT,
|
37
|
+
isRenderFunction = c => c && c.vtype === VTYPE_FUNCTION,
|
38
|
+
isComponent = c => c && c.vtype === VTYPE_COMPONENT,
|
39
|
+
isValidComponentType = c => c && isFn(c.mount);
|
40
|
+
|
41
|
+
const m = h;
|
42
|
+
|
43
|
+
const onRemove = f => ON_REMOVES.push(f);
|
44
|
+
|
45
|
+
function h(__tag, ...children) {
|
46
|
+
let props = children[0];
|
47
|
+
if (props && isObj(props) && !isArr(props) && !(props.__tag || props.props))
|
48
|
+
children.shift();
|
49
|
+
else props = EMPTY_OBJECT;
|
50
|
+
|
51
|
+
props =
|
52
|
+
children.length > 1
|
53
|
+
? Object.assign({}, props, { children })
|
54
|
+
: children.length === 1
|
55
|
+
? Object.assign({}, props, { children: children[0] })
|
56
|
+
: props;
|
57
|
+
|
58
|
+
// parse tag
|
59
|
+
if (isStr(__tag)) {
|
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';
|
67
|
+
}
|
68
|
+
|
69
|
+
return jsx(__tag, props, props.key);
|
70
|
+
}
|
71
|
+
|
72
|
+
function jsx(__tag, props, key) {
|
73
|
+
if (key !== key) throw new Error("Invalid NaN key");
|
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
|
+
}
|
90
|
+
|
91
|
+
const Fragment = props => props.children;
|
92
|
+
|
93
|
+
function render(vnode, parentDomNode, options = {}) {
|
94
|
+
let rootRef = parentDomNode.$$PETIT_DOM_REF;
|
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
|
+
}
|
113
|
+
|
114
|
+
// non exports
|
115
|
+
class Renderer {
|
116
|
+
constructor(props, env) {
|
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
|
+
}
|
126
|
+
|
127
|
+
setProps(props) {
|
128
|
+
this.oldProps = this.props;
|
129
|
+
this.props = props;
|
130
|
+
}
|
131
|
+
|
132
|
+
render(vnode) {
|
133
|
+
let state = this._STATE_;
|
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
|
+
}
|
179
|
+
|
180
|
+
// element lifecycle hooks
|
181
|
+
if (isFn(props.oncreate)) props.oncreate(node);
|
182
|
+
|
183
|
+
mountAttributes(node, props, env);
|
184
|
+
let childrenRef =
|
185
|
+
props.children == null ? props.children : mount(props.children, env);
|
186
|
+
/**
|
187
|
+
* We need to insert content before setting interactive props
|
188
|
+
* that rely on children been present (e.g select)
|
189
|
+
*/
|
190
|
+
if (childrenRef != null) insertDom(node, childrenRef);
|
191
|
+
mountDirectives(node, props, env);
|
192
|
+
return {
|
193
|
+
type: REF_SINGLE,
|
194
|
+
node,
|
195
|
+
children: childrenRef,
|
196
|
+
};
|
197
|
+
} else if (isNonEmptyArray(vnode)) {
|
198
|
+
return {
|
199
|
+
type: REF_ARRAY,
|
200
|
+
children: vnode.map((child) => mount(child, env)),
|
201
|
+
};
|
202
|
+
} else if (isRenderFunction(vnode)) {
|
203
|
+
let childVNode = vnode.__tag(vnode.props);
|
204
|
+
|
205
|
+
if (isFn(childVNode)) {
|
206
|
+
let cmp,
|
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
|
+
}
|
219
|
+
|
220
|
+
let childRef = mount(childVNode, env);
|
221
|
+
return {
|
222
|
+
type: REF_PARENT,
|
223
|
+
childRef,
|
224
|
+
childState: childVNode,
|
225
|
+
};
|
226
|
+
} else if (isComponent(vnode)) {
|
227
|
+
let renderer = new Renderer(vnode.props, env);
|
228
|
+
|
229
|
+
let parentCmp;
|
230
|
+
if (parentCmp = MOUNTING[MOUNTING.length - 1]) {
|
231
|
+
let child_closure = CMP_TO_CLOSURE.get(vnode),
|
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);
|
245
|
+
}
|
246
|
+
|
247
|
+
vnode.__tag.mount(renderer);
|
248
|
+
return {
|
249
|
+
type: REF_PARENT,
|
250
|
+
childRef: renderer._STATE_.ref,
|
251
|
+
childState: renderer,
|
252
|
+
};
|
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
|
+
}
|
262
|
+
|
263
|
+
throw new Error("mount: Invalid Vnode!");
|
264
|
+
}
|
265
|
+
|
266
|
+
function patch(
|
267
|
+
parentDomNode,
|
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
|
+
}
|
342
|
+
|
343
|
+
let childVNode = renderFn(newVNode.props);
|
344
|
+
let childRef = patch(
|
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
|
+
}
|
393
|
+
|
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;
|
399
|
+
if (isElement(vnode)) {
|
400
|
+
unmountDirectives(ref.node, vnode.props, env);
|
401
|
+
if (vnode.props.children != null)
|
402
|
+
unmount(vnode.props.children, ref.children, env);
|
403
|
+
} else if (isNonEmptyArray(vnode)) {
|
404
|
+
vnode.forEach((childVNode, index) =>
|
405
|
+
unmount(childVNode, ref.children[index], env)
|
406
|
+
);
|
407
|
+
} else if (isRenderFunction(vnode)) {
|
408
|
+
let cmp, cmps = CLOSURE_TO_CMP.get(vnode.__tag);
|
409
|
+
if (cmps && vnode.id && (cmp = cmps[vnode.id])) {
|
410
|
+
delete cmps[vnode.id];
|
411
|
+
CMP_TO_CLOSURE.delete(cmp);
|
412
|
+
return unmount(cmp, ref, env);
|
413
|
+
}
|
414
|
+
|
415
|
+
unmount(ref.childState, ref.childRef, env);
|
416
|
+
} else if (isComponent(vnode)) {
|
417
|
+
vnode.__tag.unmount(ref.childState);
|
418
|
+
}
|
419
|
+
}
|
420
|
+
|
421
|
+
function patchInPlace(parentDomNode, newVNode, oldVNode, ref, env) {
|
422
|
+
let newRef = patch(parentDomNode, newVNode, oldVNode, ref, env);
|
423
|
+
if (newRef !== ref) {
|
424
|
+
replaceDom(parentDomNode, newRef, ref);
|
425
|
+
unmount(oldVNode, ref, env);
|
426
|
+
}
|
427
|
+
return newRef;
|
428
|
+
}
|
429
|
+
|
430
|
+
function patchChildren(parentDomNode, newChildren, oldchildren, ref, env) {
|
431
|
+
// We need to retreive the next sibling before the old children
|
432
|
+
// get eventually removed from the current DOM document
|
433
|
+
let nextNode = getNextSibling(ref);
|
434
|
+
let children = Array(newChildren.length);
|
435
|
+
let refChildren = ref.children;
|
436
|
+
let newStart = 0,
|
437
|
+
oldStart = 0,
|
438
|
+
newEnd = newChildren.length - 1,
|
439
|
+
oldEnd = oldchildren.length - 1;
|
440
|
+
let oldVNode, newVNode, oldRef, newRef, refMap;
|
441
|
+
|
442
|
+
while (newStart <= newEnd && oldStart <= oldEnd) {
|
443
|
+
if (refChildren[oldStart] === null) {
|
444
|
+
oldStart++;
|
445
|
+
continue;
|
446
|
+
}
|
447
|
+
if (refChildren[oldEnd] === null) {
|
448
|
+
oldEnd--;
|
449
|
+
continue;
|
450
|
+
}
|
451
|
+
|
452
|
+
oldVNode = oldchildren[oldStart];
|
453
|
+
newVNode = newChildren[newStart];
|
454
|
+
if (newVNode.key === oldVNode.key) {
|
455
|
+
oldRef = refChildren[oldStart];
|
456
|
+
newRef = children[newStart] = patchInPlace(
|
457
|
+
parentDomNode,
|
458
|
+
newVNode,
|
459
|
+
oldVNode,
|
460
|
+
oldRef,
|
461
|
+
env
|
462
|
+
);
|
463
|
+
newStart++;
|
464
|
+
oldStart++;
|
465
|
+
continue;
|
466
|
+
}
|
467
|
+
|
468
|
+
oldVNode = oldchildren[oldEnd];
|
469
|
+
newVNode = newChildren[newEnd];
|
470
|
+
if (newVNode.key === oldVNode.key) {
|
471
|
+
oldRef = refChildren[oldEnd];
|
472
|
+
newRef = children[newEnd] = patchInPlace(
|
473
|
+
parentDomNode,
|
474
|
+
newVNode,
|
475
|
+
oldVNode,
|
476
|
+
oldRef,
|
477
|
+
env
|
478
|
+
);
|
479
|
+
newEnd--;
|
480
|
+
oldEnd--;
|
481
|
+
continue;
|
482
|
+
}
|
483
|
+
|
484
|
+
if (refMap == null) {
|
485
|
+
refMap = {};
|
486
|
+
for (let i = oldStart; i <= oldEnd; i++) {
|
487
|
+
oldVNode = oldchildren[i];
|
488
|
+
if (oldVNode.key != null) {
|
489
|
+
refMap[oldVNode.key] = i;
|
490
|
+
}
|
491
|
+
}
|
492
|
+
}
|
493
|
+
|
494
|
+
newVNode = newChildren[newStart];
|
495
|
+
let idx = newVNode.key != null ? refMap[newVNode.key] : null;
|
496
|
+
if (idx != null) {
|
497
|
+
oldVNode = oldchildren[idx];
|
498
|
+
oldRef = refChildren[idx];
|
499
|
+
newRef = children[newStart] = patch(
|
500
|
+
parentDomNode,
|
501
|
+
newVNode,
|
502
|
+
oldVNode,
|
503
|
+
oldRef,
|
504
|
+
env
|
505
|
+
);
|
506
|
+
insertDom(parentDomNode, newRef, getDomNode(refChildren[oldStart]));
|
507
|
+
if (newRef !== oldRef) {
|
508
|
+
removeDom(parentDomNode, oldRef);
|
509
|
+
unmount(oldVNode, oldRef, env);
|
510
|
+
}
|
511
|
+
refChildren[idx] = null;
|
512
|
+
} else {
|
513
|
+
newRef = children[newStart] = mount(newVNode, env);
|
514
|
+
insertDom(parentDomNode, newRef, getDomNode(refChildren[oldStart]));
|
515
|
+
}
|
516
|
+
newStart++;
|
517
|
+
}
|
518
|
+
|
519
|
+
let beforeNode =
|
520
|
+
newEnd < newChildren.length - 1
|
521
|
+
? getDomNode(children[newEnd + 1])
|
522
|
+
: nextNode;
|
523
|
+
while (newStart <= newEnd) {
|
524
|
+
let newRef = mount(newChildren[newStart], env);
|
525
|
+
children[newStart] = newRef;
|
526
|
+
insertDom(parentDomNode, newRef, beforeNode);
|
527
|
+
newStart++;
|
528
|
+
}
|
529
|
+
while (oldStart <= oldEnd) {
|
530
|
+
oldRef = refChildren[oldStart];
|
531
|
+
if (oldRef != null) {
|
532
|
+
removeDom(parentDomNode, oldRef);
|
533
|
+
unmount(oldchildren[oldStart], oldRef, env);
|
534
|
+
}
|
535
|
+
oldStart++;
|
536
|
+
}
|
537
|
+
ref.children = children;
|
538
|
+
}
|
539
|
+
|
540
|
+
function defaultShouldUpdate(p1, p2) {
|
541
|
+
if (p1 === p2) return false;
|
542
|
+
for (let key in p2) {
|
543
|
+
if (p1[key] !== p2[key]) return true;
|
544
|
+
}
|
545
|
+
return false;
|
546
|
+
}
|
547
|
+
|
548
|
+
function propDirective(prop) {
|
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
|
+
}
|
563
|
+
|
564
|
+
function getDomNode(ref) {
|
565
|
+
if (ref.type === REF_SINGLE) {
|
566
|
+
return ref.node;
|
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);
|
571
|
+
}
|
572
|
+
throw new Error("Unkown ref type " + JSON.stringify(ref));
|
573
|
+
}
|
574
|
+
|
575
|
+
function getParentNode(ref) {
|
576
|
+
if (ref.type === REF_SINGLE) {
|
577
|
+
return ref.node.parentNode;
|
578
|
+
} else if (ref.type === REF_ARRAY) {
|
579
|
+
return getParentNode(ref.children[0]);
|
580
|
+
} else if (ref.type === REF_PARENT) {
|
581
|
+
return getParentNode(ref.childRef);
|
582
|
+
}
|
583
|
+
throw new Error("Unkown ref type " + ref);
|
584
|
+
}
|
585
|
+
|
586
|
+
function getNextSibling(ref) {
|
587
|
+
if (ref.type === REF_SINGLE) {
|
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
|
+
}
|
596
|
+
|
597
|
+
function insertDom(parent, ref, nextSibling) {
|
598
|
+
if (ref.type === REF_SINGLE) {
|
599
|
+
parent.insertBefore(ref.node, nextSibling);
|
600
|
+
} else if (ref.type === REF_ARRAY) {
|
601
|
+
ref.children.forEach((ch) => {
|
602
|
+
insertDom(parent, ch, nextSibling);
|
603
|
+
});
|
604
|
+
} else if (ref.type === REF_PARENT) {
|
605
|
+
insertDom(parent, ref.childRef, nextSibling);
|
606
|
+
} else {
|
607
|
+
throw new Error("Unkown ref type " + JSON.stringify(ref));
|
608
|
+
}
|
609
|
+
}
|
610
|
+
|
611
|
+
function removeDom(parent, ref) {
|
612
|
+
if (ref.type === REF_SINGLE) {
|
613
|
+
parent.removeChild(ref.node);
|
614
|
+
} else if (ref.type === REF_ARRAY) {
|
615
|
+
ref.children.forEach((ch) => {
|
616
|
+
removeDom(parent, ch);
|
617
|
+
});
|
618
|
+
} else if (ref.type === REF_PARENT) {
|
619
|
+
removeDom(parent, ref.childRef);
|
620
|
+
} else {
|
621
|
+
throw new Error("Unkown ref type " + ref);
|
622
|
+
}
|
623
|
+
}
|
624
|
+
|
625
|
+
function replaceDom(parent, newRef, oldRef) {
|
626
|
+
insertDom(parent, newRef, getDomNode(oldRef));
|
627
|
+
removeDom(parent, oldRef);
|
628
|
+
}
|
629
|
+
|
630
|
+
function mountDirectives(domElement, props, env) {
|
631
|
+
for (let key in props) {
|
632
|
+
if (key in env.directives) {
|
633
|
+
env.directives[key].mount(domElement, props[key]);
|
634
|
+
}
|
635
|
+
}
|
636
|
+
}
|
637
|
+
|
638
|
+
function patchDirectives(domElement, newProps, oldProps, env) {
|
639
|
+
for (let key in newProps) {
|
640
|
+
if (key in env.directives) {
|
641
|
+
env.directives[key].patch(domElement, newProps[key], oldProps[key]);
|
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
|
+
}
|
650
|
+
|
651
|
+
function unmountDirectives(domElement, props, env) {
|
652
|
+
for (let key in props) {
|
653
|
+
if (key in env.directives) {
|
654
|
+
env.directives[key].unmount(domElement, props[key]);
|
655
|
+
}
|
656
|
+
}
|
657
|
+
}
|
658
|
+
|
659
|
+
function mountAttributes(domElement, props, env) {
|
660
|
+
for (var key in props) {
|
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
|
+
}
|
670
|
+
|
671
|
+
function patchAttributes(domElement, newProps, oldProps, env) {
|
672
|
+
for (var key in newProps) {
|
673
|
+
if (key === "key" || key === "children" || key in env.directives) continue;
|
674
|
+
var oldValue = oldProps[key];
|
675
|
+
var newValue = newProps[key];
|
676
|
+
if (oldValue !== newValue) {
|
677
|
+
if (key.startsWith("on")) {
|
678
|
+
let cmp = MOUNTING[MOUNTING.length - 1];
|
679
|
+
domElement[key.toLowerCase()] = cmp ? cmp.__tag.event(newValue) : newValue;
|
680
|
+
} else {
|
681
|
+
setDOMAttribute(domElement, key, newValue, env.isSVG);
|
682
|
+
}
|
683
|
+
}
|
684
|
+
}
|
685
|
+
for (key in oldProps) {
|
686
|
+
if (
|
687
|
+
key === "key" ||
|
688
|
+
key === "children" ||
|
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
|
+
}
|
698
|
+
}
|
699
|
+
}
|
700
|
+
|
701
|
+
function setDOMAttribute(el, attr, value, isSVG) {
|
702
|
+
if (value === true) {
|
703
|
+
el.setAttribute(attr, "");
|
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
|
+
}
|
713
|
+
}
|
714
|
+
}
|
715
|
+
|
716
|
+
function toClosureCmp(vnode, view) {
|
717
|
+
let onRemove = ON_REMOVES.pop() ?? noop,
|
718
|
+
cmp = {
|
719
|
+
key: vnode.key,
|
720
|
+
id: vnode.id,
|
721
|
+
vtype: VTYPE_COMPONENT,
|
722
|
+
props: vnode.props || {},
|
723
|
+
__tag: {
|
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
|
+
};
|
752
|
+
|
753
|
+
MOUNTING.push(cmp);
|
754
|
+
ctx.render(view({ ...ctx.props }));
|
755
|
+
MOUNTING.pop();
|
756
|
+
}
|
757
|
+
|
758
|
+
return cmp;
|
759
|
+
}
|
760
|
+
|
761
|
+
exports.Fragment = Fragment;
|
762
|
+
exports.h = h;
|
763
|
+
exports.jsx = jsx;
|
764
|
+
exports.m = m;
|
765
|
+
exports.onRemove = onRemove;
|
766
|
+
exports.render = render;
|