-
Notifications
You must be signed in to change notification settings - Fork 96
/
van-0.10.1.nomodule.debug.js
216 lines (212 loc) · 8.02 KB
/
van-0.10.1.nomodule.debug.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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
(() => {
var __defProp = Object.defineProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
// van.debug.js
var van_debug_exports = {};
__export(van_debug_exports, {
add: () => add2,
bind: () => bind2,
capturedErrors: () => capturedErrors,
empty: () => empty2,
startCapturingErrors: () => startCapturingErrors,
state: () => state2,
stopCapturingErrors: () => stopCapturingErrors,
tags: () => tags2
});
// van.js
var doc = document;
var Obj = Object;
var Null = null;
var _empty = {};
var empty = _empty;
var changedStates;
var enqueueState = (s) => changedStates = (changedStates ?? (setTimeout(updateDoms), /* @__PURE__ */ new Set())).add(s);
var State = class {
constructor(v) {
this._val = v;
this.bindings = [];
this.derivedStateSetters = [];
}
get "val"() {
return this._val;
}
set "val"(v) {
let s = this;
if (v !== s._val) {
if (!s.oldVal) {
enqueueState(s);
s.oldVal = s._val;
} else if (v === s.oldVal) {
s.oldVal = Null;
changedStates.delete(s);
}
s._val = v;
s.derivedStateSetters.forEach((d) => d());
}
}
};
var state = (initVal) => new State(initVal);
var toDom = (input) => input.nodeType ? input : input instanceof State ? bind(input, (v) => doc.createTextNode(v)) : doc.createTextNode(input);
var add = (dom, ...children) => children.flat(Infinity).forEach((child) => dom.appendChild(toDom(child)));
var tags = new Proxy((name, ...args) => {
let [props, ...children] = args[0]?.constructor === Obj ? args : [{}, ...args];
let dom = doc.createElement(name);
Obj.entries(props).forEach(([k, v]) => {
if (k.startsWith("on"))
dom[k] = v;
else if (v instanceof State)
bind(v, (v2) => (dom[k] = v2, dom));
else
dom.setAttribute(k, v);
});
add(dom, ...children);
return dom;
}, { get: (tag, name) => tag.bind(Null, name) });
var updateDoms = () => {
let changedStatesArray = [...changedStates];
changedStates = Null;
new Set(changedStatesArray.flatMap(
(s) => s.bindings = s.bindings.filter((b) => b.dom.isConnected)
)).forEach((b) => {
let { dom, deps, func } = b;
let newDom = func(...deps.map((d) => d._val), dom, ...deps.map((d) => d.oldVal));
if (newDom !== dom) {
if (newDom !== _empty)
dom.replaceWith(newDom);
else
dom.remove();
b.dom = newDom;
}
});
changedStatesArray.forEach((s) => s.oldVal = Null);
};
var bind = (...args) => {
let deps = args.slice(0, -1), func = args[args.length - 1];
let result = func(...deps.map((d) => d._val));
if (result === _empty)
return [];
if (result.nodeType) {
let binding = { deps, dom: result, func };
deps.forEach((d) => d.bindings.push(binding));
return result;
}
let resultState = state(result);
let setter = () => resultState.val = func(
...deps.map((d) => d._val),
resultState._val,
...deps.map((d) => d.oldVal)
);
deps.forEach((d) => d.derivedStateSetters.push(setter));
return resultState;
};
// van.debug.js
var capturedErrors;
var startCapturingErrors = () => capturedErrors = [];
var stopCapturingErrors = () => capturedErrors = null;
var expect = (cond, msg) => {
if (!cond) {
if (capturedErrors)
capturedErrors.push(msg);
else
throw new Error(msg);
return false;
}
return true;
};
var State2 = state().constructor;
var checkStateValValid = (v) => {
expect(!(v instanceof Node), "DOM Node is not valid value for state");
expect(!(v instanceof State2), "State couldn't have value to other state");
};
var state2 = (initVal) => {
checkStateValValid(initVal);
return new Proxy(state(initVal), {
set: (s, name, val) => {
if (name === "val") {
checkStateValValid(val);
s.val = val;
} else
s[name] = val;
return true;
}
});
};
var isValidPrimitive = (v) => typeof v === "string" || typeof v === "number" || typeof v === "boolean" || typeof v === "bigint";
var checkChildValid = (child) => {
expect(
child instanceof Node || isValidPrimitive(child) || child instanceof State2 && isValidPrimitive(child.val),
"Only DOM Node, string, number, boolean, bigint, and state of string, number, boolean or bigint are valid child of a DOM Node"
);
expect(!child.isConnected, "You can't add a DOM Node that is already connected to a DOM document");
};
var add2 = (dom, ...children) => {
expect(dom instanceof Node, "1st argument of `add` function must be a DOM Node object");
children.flat(Infinity).forEach((child) => checkChildValid(child));
add(dom, ...children);
};
var tags2 = new Proxy(tags, {
get: (vanTags, name) => {
const vanTag = vanTags[name];
return (...args) => {
let [props, ...children] = args[0]?.constructor === Object ? args : [{}, ...args];
for (const [k, v] of Object.entries(props)) {
if (k.startsWith("on"))
expect(typeof v === "function", "Value for on... handler must be of function type");
else {
expect(
isValidPrimitive(v) || v instanceof State2 && isValidPrimitive(v.val),
"Only string, number, boolean, bigint, and state of string, number, boolean or bigint are valid prop value types"
);
if (v instanceof State2)
expect(k !== "class", "When prop value is a state, we set the value on DOM Node properties directly. Thus you probably want to use `classList` instead of `class` here");
else
expect(k !== "classList", "When prop value is a primitive type, we set the value via setAttribute instead of setting via DOM Node properties. Thus you probably want to use `class` instead of `classList` here");
}
}
children.flat(Infinity).forEach((child) => checkChildValid(child));
return vanTag(...args);
};
}
});
var empty2 = empty;
var bind2 = (...args) => {
const deps = args.slice(0, -1), func = args[args.length - 1];
expect(deps.length > 0, "`bind` must be called with 1 or more states as dependencies");
deps.forEach((d) => expect(d instanceof State2, "Dependencies in `bind` must be states"));
expect(typeof func === "function", "The last argument of `bind` must be the generation function");
const result = func(...deps.map((d) => d.val));
expect(!(result instanceof State2), "The result of `bind` generation function can't be a state object");
return bind(...deps, (...genArgs) => {
const result2 = func(...genArgs);
expect(!(result2 instanceof State2), "The result of `bind` generation function can't be a state object");
if (genArgs.length > deps.length) {
const prevResult = genArgs[deps.length];
if (prevResult instanceof Node) {
expect(prevResult.isConnected, "For binding to DOM Node, the previous result of generation function must be connected to a DOM document");
if (!expect(
result2 instanceof Node || result2 === empty2,
"For binding to DOM Node, the result of generation function must be also a DOM object, or `van.empty`"
))
return empty2;
if (result2 && result2 !== prevResult) {
if (!expect(
!result2.isConnected,
"For binding to DOM Node, if the result of generation function is not the same as previous one, it shouldn't be already connected to a DOM document"
))
return empty2;
}
} else
expect(
!(result2 instanceof Node) && result2 !== empty2,
"For binding to derived state, the result of generation function can't be a DOM object, or van.empty"
);
}
return result2;
});
};
// van.forbundle.debug.js
window.van = van_debug_exports;
})();