/
index.js
121 lines (100 loc) · 3.33 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
let NIL = void 0,
REDRAWS = [],
isArray = Array.isArray,
isStr = x => typeof x === 'string',
isFn = x => typeof x === 'function',
isObj = x => x !== null && typeof x === 'object';
let createNode = v => document[v._cmp ? 'createElement' : 'createTextNode'](v.tag || v);
let addChildren = (x, children) => {
if (isArray(x)) for (let i = 0; i < x.length; i++) addChildren(x[i], children);
else if (x != null && x !== false) children.push(x);
};
let styles = (obj) => {
let str = '';
for (let k in obj) str += k.replace(/[A-Z]/g, m => '-' + m.toLowerCase()) + ':' + obj[k] + ';';
return str;
};
let update = (node, v, redraw) => {
if (!v._cmp)
// add '' to convert to str; if the nodeValue has changed, update
return node.nodeValue === v + '' || (node.nodeValue = v);
for (let i in v.props) {
let newProp = v.props[i];
if (i in node) {
if (redraw && i[0] === 'o' && i[1] === 'n' && isFn(newProp)) {
let res, fn = newProp;
node[i] = ev =>
(res = fn(ev)) instanceof Promise
? res.finally(_ => (redraw(), res = NIL))
: (redraw(), res = NIL);
} else {
if (i === 'style' && isObj(newProp))
newProp = styles(newProp);
node[i] = newProp;
}
} else if (!isFn(newProp) && node.getAttribute(i) != newProp) {
if (newProp == null || newProp === false) node.removeAttribute(i);
else node.setAttribute(i, newProp);
}
}
for (let i = 0, names = [...node.getAttributeNames(), ...Object.keys(node)]; i < names.length; i++)
if (!(names[i] in v.props))
(i in node)
? (node[names[i]] = NIL)
: (node.removeAttribute(names[i]));
}
export function render(parent, cmp, redraw) {
let i, tmp,
olds = parent.childNodes || [],
children = cmp.children || [],
news = isArray(children) ? children : [children];
for (i = 0, tmp = Array(Math.max(0, olds.length - news.length)); i < tmp.length; i++)
parent.removeChild(parent.lastChild);
for (i = 0; i < news.length; i++) {
let node, vnode = news[i];
node = olds[i] || createNode(vnode);
if (!olds[i]) parent.appendChild(node);
else if ((node.tagName || '') !== (vnode.tag || '').toUpperCase()) {
node = createNode(vnode);
parent.replaceChild(node, olds[i]);
}
update(node, vnode, redraw);
render(node, vnode, redraw);
}
}
export function mount(el, cmp) {
let redraw;
el.innerHTML = '';
REDRAWS.push(
redraw = _ => requestAnimationFrame(
_ => render(el, { children: cmp() }, redraw)
)
);
return redraw() && redraw;
}
export const redraw = _ =>
REDRAWS.map(r => r());
export function m(tag, ...tail) {
let k, tmp, classes,
first = tail[0],
props = {},
children = [];
if (isObj(first) && !isArray(first) && first.tag === NIL)
[props, ...tail] = tail;
if (isStr(tag)) {
[tag, ...classes] = tag.split('.');
classes = classes.join(' ');
if (isObj(tmp = props.class)) {
for (k in tmp) {
if (tmp[k]) {
if (classes) classes += ' ';
classes += k;
}
}
}
if (isStr(tmp)) classes += !classes ? tmp : tmp ? ' ' + tmp : '';
if (classes) props.class = classes;
}
addChildren(tail, children); // will recurse through tail and push valid childs to `children`
return { _cmp: 1, tag, props: { ...props }, children };
}