@b9g/crank 0.6.0 → 0.7.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/_utils.d.ts +14 -0
- package/async.cjs +237 -0
- package/async.cjs.map +1 -0
- package/async.d.ts +104 -0
- package/async.js +234 -0
- package/async.js.map +1 -0
- package/crank.cjs +1672 -1313
- package/crank.cjs.map +1 -1
- package/crank.d.ts +230 -247
- package/crank.js +1672 -1314
- package/crank.js.map +1 -1
- package/dom.cjs +356 -212
- package/dom.cjs.map +1 -1
- package/dom.d.ts +5 -5
- package/dom.js +357 -213
- package/dom.js.map +1 -1
- package/event-target.cjs +254 -0
- package/event-target.cjs.map +1 -0
- package/event-target.d.ts +26 -0
- package/event-target.js +249 -0
- package/event-target.js.map +1 -0
- package/html.cjs +32 -43
- package/html.cjs.map +1 -1
- package/html.d.ts +3 -3
- package/html.js +33 -44
- package/html.js.map +1 -1
- package/jsx-runtime.cjs +1 -0
- package/jsx-runtime.cjs.map +1 -1
- package/jsx-runtime.js +1 -0
- package/jsx-runtime.js.map +1 -1
- package/jsx-tag.cjs +6 -2
- package/jsx-tag.cjs.map +1 -1
- package/jsx-tag.d.ts +2 -0
- package/jsx-tag.js +6 -3
- package/jsx-tag.js.map +1 -1
- package/package.json +46 -30
- package/standalone.cjs +3 -0
- package/standalone.cjs.map +1 -1
- package/standalone.d.ts +1 -1
- package/standalone.js +3 -2
- package/standalone.js.map +1 -1
- package/umd.js +2292 -1562
- package/umd.js.map +1 -1
package/dom.cjs
CHANGED
|
@@ -1,12 +1,53 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var crank = require('./crank.cjs');
|
|
4
|
+
require('./event-target.cjs');
|
|
4
5
|
|
|
5
6
|
const SVG_NAMESPACE = "http://www.w3.org/2000/svg";
|
|
6
|
-
|
|
7
|
-
|
|
7
|
+
function isWritableProperty(element, name) {
|
|
8
|
+
// walk up the object's prototype chain to find the owner
|
|
9
|
+
let propOwner = element;
|
|
10
|
+
do {
|
|
11
|
+
if (Object.prototype.hasOwnProperty.call(propOwner, name)) {
|
|
12
|
+
break;
|
|
13
|
+
}
|
|
14
|
+
} while ((propOwner = Object.getPrototypeOf(propOwner)));
|
|
15
|
+
if (propOwner === null) {
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
// get the descriptor for the named property and check whether it implies
|
|
19
|
+
// that the property is writable
|
|
20
|
+
const descriptor = Object.getOwnPropertyDescriptor(propOwner, name);
|
|
21
|
+
if (descriptor != null &&
|
|
22
|
+
(descriptor.writable === true || descriptor.set !== undefined)) {
|
|
23
|
+
return true;
|
|
24
|
+
}
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
function emitHydrationWarning(propName, quietProps, expectedValue, actualValue, element, displayName) {
|
|
28
|
+
const checkName = propName;
|
|
29
|
+
const showName = displayName || propName;
|
|
30
|
+
if (!quietProps || !quietProps.has(checkName)) {
|
|
31
|
+
if (expectedValue === null || expectedValue === false) {
|
|
32
|
+
console.warn(`Expected "${showName}" to be missing but found ${String(actualValue)} while hydrating:`, element);
|
|
33
|
+
}
|
|
34
|
+
else if (expectedValue === true || expectedValue === "") {
|
|
35
|
+
console.warn(`Expected "${showName}" to be ${expectedValue === true ? "present" : '""'} but found ${String(actualValue)} while hydrating:`, element);
|
|
36
|
+
}
|
|
37
|
+
else if (typeof window !== "undefined" &&
|
|
38
|
+
window.location &&
|
|
39
|
+
new URL(expectedValue, window.location.origin).href ===
|
|
40
|
+
new URL(actualValue, window.location.origin).href) ;
|
|
41
|
+
else {
|
|
42
|
+
console.warn(`Expected "${showName}" to be "${String(expectedValue)}" but found ${String(actualValue)} while hydrating:`, element);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
const adapter = {
|
|
47
|
+
scope({ scope: xmlns, tag, props, }) {
|
|
8
48
|
switch (tag) {
|
|
9
49
|
case crank.Portal:
|
|
50
|
+
// TODO: read the namespace from the portal root element
|
|
10
51
|
xmlns = undefined;
|
|
11
52
|
break;
|
|
12
53
|
case "svg":
|
|
@@ -15,9 +56,9 @@ const impl = {
|
|
|
15
56
|
}
|
|
16
57
|
return props.xmlns || xmlns;
|
|
17
58
|
},
|
|
18
|
-
create(tag,
|
|
59
|
+
create({ tag, tagName, scope: xmlns, }) {
|
|
19
60
|
if (typeof tag !== "string") {
|
|
20
|
-
throw new Error(`Unknown tag: ${
|
|
61
|
+
throw new Error(`Unknown tag: ${tagName}`);
|
|
21
62
|
}
|
|
22
63
|
else if (tag.toLowerCase() === "svg") {
|
|
23
64
|
xmlns = SVG_NAMESPACE;
|
|
@@ -26,262 +67,362 @@ const impl = {
|
|
|
26
67
|
? document.createElementNS(xmlns, tag)
|
|
27
68
|
: document.createElement(tag);
|
|
28
69
|
},
|
|
29
|
-
|
|
70
|
+
adopt({ tag, tagName, node, }) {
|
|
30
71
|
if (typeof tag !== "string" && tag !== crank.Portal) {
|
|
31
|
-
throw new Error(`Unknown tag: ${
|
|
72
|
+
throw new Error(`Unknown tag: ${tagName}`);
|
|
32
73
|
}
|
|
33
|
-
if (
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
74
|
+
if (node === document.body ||
|
|
75
|
+
node === document.head ||
|
|
76
|
+
node === document.documentElement ||
|
|
77
|
+
node === document) {
|
|
78
|
+
console.warn(`Hydrating ${node.nodeName.toLowerCase()} is discouraged as it is destructive and may remove unknown nodes.`);
|
|
38
79
|
}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
else if (child.nodeType === Node.ELEMENT_NODE) {
|
|
46
|
-
children.push(child);
|
|
47
|
-
}
|
|
80
|
+
if (node == null ||
|
|
81
|
+
(typeof tag === "string" &&
|
|
82
|
+
(node.nodeType !== Node.ELEMENT_NODE ||
|
|
83
|
+
tag.toLowerCase() !== node.tagName.toLowerCase()))) {
|
|
84
|
+
console.warn(`Expected <${tagName}> while hydrating but found: `, node);
|
|
85
|
+
return;
|
|
48
86
|
}
|
|
49
|
-
|
|
50
|
-
return { props, children };
|
|
87
|
+
return Array.from(node.childNodes);
|
|
51
88
|
},
|
|
52
|
-
patch(
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
89
|
+
patch({ tagName, node, props, oldProps, scope: xmlns, copyProps, quietProps, isHydrating, }) {
|
|
90
|
+
if (node.nodeType !== Node.ELEMENT_NODE) {
|
|
91
|
+
throw new TypeError(`Cannot patch node: ${String(node)}`);
|
|
92
|
+
}
|
|
93
|
+
else if (props.class && props.className) {
|
|
94
|
+
console.error(`Both "class" and "className" set in props for <${tagName}>. Use one or the other.`);
|
|
95
|
+
}
|
|
96
|
+
const element = node;
|
|
57
97
|
const isSVG = xmlns === SVG_NAMESPACE;
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
else if (value == null || value === false) {
|
|
65
|
-
node.removeAttribute("style");
|
|
98
|
+
for (let name in { ...oldProps, ...props }) {
|
|
99
|
+
let value = props[name];
|
|
100
|
+
const oldValue = oldProps ? oldProps[name] : undefined;
|
|
101
|
+
{
|
|
102
|
+
if (copyProps != null && copyProps.has(name)) {
|
|
103
|
+
continue;
|
|
66
104
|
}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
105
|
+
// handle prop:name or attr:name properties
|
|
106
|
+
const colonIndex = name.indexOf(":");
|
|
107
|
+
if (colonIndex !== -1) {
|
|
108
|
+
const [ns, name1] = [
|
|
109
|
+
name.slice(0, colonIndex),
|
|
110
|
+
name.slice(colonIndex + 1),
|
|
111
|
+
];
|
|
112
|
+
switch (ns) {
|
|
113
|
+
case "prop":
|
|
114
|
+
node[name1] = value;
|
|
115
|
+
continue;
|
|
116
|
+
case "attr":
|
|
117
|
+
if (value == null || value === false) {
|
|
118
|
+
if (isHydrating && element.hasAttribute(name1)) {
|
|
119
|
+
emitHydrationWarning(name, quietProps, value, element.getAttribute(name1), element);
|
|
120
|
+
}
|
|
121
|
+
element.removeAttribute(name1);
|
|
122
|
+
}
|
|
123
|
+
else if (value === true) {
|
|
124
|
+
if (isHydrating && !element.hasAttribute(name1)) {
|
|
125
|
+
emitHydrationWarning(name, quietProps, value, null, element);
|
|
126
|
+
}
|
|
127
|
+
element.setAttribute(name1, "");
|
|
128
|
+
}
|
|
129
|
+
else if (typeof value !== "string") {
|
|
130
|
+
value = String(value);
|
|
131
|
+
}
|
|
132
|
+
if (isHydrating && element.getAttribute(name1) !== value) {
|
|
133
|
+
emitHydrationWarning(name, quietProps, value, element.getAttribute(name1), element);
|
|
134
|
+
}
|
|
135
|
+
element.setAttribute(name1, String(value));
|
|
136
|
+
continue;
|
|
73
137
|
}
|
|
74
138
|
}
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
139
|
+
}
|
|
140
|
+
switch (name) {
|
|
141
|
+
// TODO: fix hydration warnings for the style prop
|
|
142
|
+
case "style": {
|
|
143
|
+
const style = element.style;
|
|
144
|
+
if (value == null || value === false) {
|
|
145
|
+
if (isHydrating && style.cssText !== "") {
|
|
146
|
+
emitHydrationWarning(name, quietProps, value, style.cssText, element);
|
|
147
|
+
}
|
|
148
|
+
element.removeAttribute("style");
|
|
78
149
|
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
style.removeProperty(styleName);
|
|
150
|
+
else if (value === true) {
|
|
151
|
+
if (isHydrating && style.cssText !== "") {
|
|
152
|
+
emitHydrationWarning(name, quietProps, "", style.cssText, element);
|
|
83
153
|
}
|
|
84
|
-
|
|
85
|
-
|
|
154
|
+
element.setAttribute("style", "");
|
|
155
|
+
}
|
|
156
|
+
else if (typeof value === "string") {
|
|
157
|
+
if (style.cssText !== value) {
|
|
158
|
+
// TODO: Fix hydration warnings for styles
|
|
159
|
+
//if (isHydrating) {
|
|
160
|
+
// emitHydrationWarning(
|
|
161
|
+
// name,
|
|
162
|
+
// quietProps,
|
|
163
|
+
// value,
|
|
164
|
+
// style.cssText,
|
|
165
|
+
// element,
|
|
166
|
+
// );
|
|
167
|
+
//}
|
|
168
|
+
style.cssText = value;
|
|
86
169
|
}
|
|
87
170
|
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
171
|
+
else {
|
|
172
|
+
if (typeof oldValue === "string") {
|
|
173
|
+
// if the old value was a string, we need to clear the style
|
|
174
|
+
// TODO: only clear the styles enumerated in the old value
|
|
175
|
+
style.cssText = "";
|
|
176
|
+
}
|
|
177
|
+
for (const styleName in { ...oldValue, ...value }) {
|
|
178
|
+
const styleValue = value && value[styleName];
|
|
179
|
+
if (styleValue == null) {
|
|
180
|
+
if (isHydrating && style.getPropertyValue(styleName) !== "") {
|
|
181
|
+
emitHydrationWarning(name, quietProps, null, style.getPropertyValue(styleName), element, `style.${styleName}`);
|
|
182
|
+
}
|
|
183
|
+
style.removeProperty(styleName);
|
|
184
|
+
}
|
|
185
|
+
else if (style.getPropertyValue(styleName) !== styleValue) {
|
|
186
|
+
// TODO: hydration warnings for style props
|
|
187
|
+
//if (isHydrating) {
|
|
188
|
+
// emitHydrationWarning(
|
|
189
|
+
// name,
|
|
190
|
+
// quietProps,
|
|
191
|
+
// styleValue,
|
|
192
|
+
// style.getPropertyValue(styleName),
|
|
193
|
+
// element,
|
|
194
|
+
// `style.${styleName}`,
|
|
195
|
+
// );
|
|
196
|
+
//}
|
|
197
|
+
style.setProperty(styleName, styleValue);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
102
200
|
}
|
|
201
|
+
break;
|
|
103
202
|
}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
if (value !== oldValue) {
|
|
110
|
-
node.innerHTML = value;
|
|
111
|
-
}
|
|
112
|
-
break;
|
|
113
|
-
default: {
|
|
114
|
-
if (name[0] === "o" &&
|
|
115
|
-
name[1] === "n" &&
|
|
116
|
-
name[2] === name[2].toUpperCase() &&
|
|
117
|
-
typeof value === "function") {
|
|
118
|
-
// Support React-style event names (onClick, onChange, etc.)
|
|
119
|
-
name = name.toLowerCase();
|
|
120
|
-
}
|
|
121
|
-
if (name in node &&
|
|
122
|
-
// boolean properties will coerce strings, but sometimes they map to
|
|
123
|
-
// enumerated attributes, where truthy strings ("false", "no") map to
|
|
124
|
-
// falsy properties, so we use attributes in this case.
|
|
125
|
-
!(typeof value === "string" &&
|
|
126
|
-
typeof node[name] === "boolean")) {
|
|
127
|
-
// walk up the object's prototype chain to find the owner of the
|
|
128
|
-
// named property
|
|
129
|
-
let obj = node;
|
|
130
|
-
do {
|
|
131
|
-
if (Object.prototype.hasOwnProperty.call(obj, name)) {
|
|
132
|
-
break;
|
|
203
|
+
case "class":
|
|
204
|
+
case "className":
|
|
205
|
+
if (value === true) {
|
|
206
|
+
if (isHydrating && element.getAttribute("class") !== "") {
|
|
207
|
+
emitHydrationWarning(name, quietProps, "", element.getAttribute("class"), element);
|
|
133
208
|
}
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
(descriptor.writable === true || descriptor.set !== undefined)) {
|
|
140
|
-
if (node[name] !== value || oldValue === undefined) {
|
|
141
|
-
node[name] = value;
|
|
209
|
+
element.setAttribute("class", "");
|
|
210
|
+
}
|
|
211
|
+
else if (value == null) {
|
|
212
|
+
if (isHydrating && element.hasAttribute("class")) {
|
|
213
|
+
emitHydrationWarning(name, quietProps, value, element.getAttribute("class"), element);
|
|
142
214
|
}
|
|
143
|
-
|
|
215
|
+
element.removeAttribute("class");
|
|
144
216
|
}
|
|
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
|
-
while (oldChild !== null && i < children.length) {
|
|
180
|
-
const newChild = children[i];
|
|
181
|
-
if (oldChild === newChild) {
|
|
182
|
-
oldChild = oldChild.nextSibling;
|
|
183
|
-
i++;
|
|
217
|
+
else if (typeof value === "object") {
|
|
218
|
+
// class={{"included-class": true, "excluded-class": false}} syntax
|
|
219
|
+
if (typeof oldValue === "string") {
|
|
220
|
+
// if the old value was a string, we need to clear all classes
|
|
221
|
+
element.setAttribute("class", "");
|
|
222
|
+
}
|
|
223
|
+
let shouldIssueWarning = false;
|
|
224
|
+
const hydratingClasses = isHydrating
|
|
225
|
+
? new Set(Array.from(element.classList))
|
|
226
|
+
: undefined;
|
|
227
|
+
const hydratingClassName = isHydrating
|
|
228
|
+
? element.getAttribute("class")
|
|
229
|
+
: undefined;
|
|
230
|
+
for (const className in { ...oldValue, ...value }) {
|
|
231
|
+
const classValue = value && value[className];
|
|
232
|
+
if (classValue) {
|
|
233
|
+
element.classList.add(className);
|
|
234
|
+
if (hydratingClasses && hydratingClasses.has(className)) {
|
|
235
|
+
hydratingClasses.delete(className);
|
|
236
|
+
}
|
|
237
|
+
else if (isHydrating) {
|
|
238
|
+
shouldIssueWarning = true;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
else {
|
|
242
|
+
element.classList.remove(className);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
if (shouldIssueWarning ||
|
|
246
|
+
(hydratingClasses && hydratingClasses.size > 0)) {
|
|
247
|
+
emitHydrationWarning(name, quietProps, Object.keys(value)
|
|
248
|
+
.filter((k) => value[k])
|
|
249
|
+
.join(" "), hydratingClassName || "", element);
|
|
250
|
+
}
|
|
184
251
|
}
|
|
185
|
-
else if (
|
|
186
|
-
if (
|
|
187
|
-
if (
|
|
188
|
-
|
|
252
|
+
else if (!isSVG) {
|
|
253
|
+
if (element.className !== value) {
|
|
254
|
+
if (isHydrating) {
|
|
255
|
+
emitHydrationWarning(name, quietProps, value, element.className, element);
|
|
189
256
|
}
|
|
190
|
-
|
|
257
|
+
element.className = value;
|
|
191
258
|
}
|
|
192
|
-
|
|
193
|
-
|
|
259
|
+
}
|
|
260
|
+
else if (element.getAttribute("class") !== value) {
|
|
261
|
+
if (isHydrating) {
|
|
262
|
+
emitHydrationWarning(name, quietProps, value, element.getAttribute("class"), element);
|
|
194
263
|
}
|
|
195
|
-
|
|
264
|
+
element.setAttribute("class", value);
|
|
196
265
|
}
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
266
|
+
break;
|
|
267
|
+
case "innerHTML":
|
|
268
|
+
if (value !== oldValue) {
|
|
269
|
+
if (isHydrating) {
|
|
270
|
+
emitHydrationWarning(name, quietProps, value, element.innerHTML, element);
|
|
271
|
+
}
|
|
272
|
+
element.innerHTML = value;
|
|
201
273
|
}
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
274
|
+
break;
|
|
275
|
+
default: {
|
|
276
|
+
if (name[0] === "o" &&
|
|
277
|
+
name[1] === "n" &&
|
|
278
|
+
name[2] === name[2].toUpperCase() &&
|
|
279
|
+
typeof value === "function") {
|
|
280
|
+
// Support React-style event names (onClick, onChange, etc.)
|
|
281
|
+
name = name.toLowerCase();
|
|
282
|
+
}
|
|
283
|
+
// try to set the property directly
|
|
284
|
+
if (name in element &&
|
|
285
|
+
// boolean properties will coerce strings, but sometimes they map to
|
|
286
|
+
// enumerated attributes, where truthy strings ("false", "no") map to
|
|
287
|
+
// falsy properties, so we force using setAttribute.
|
|
288
|
+
!(typeof value === "string" &&
|
|
289
|
+
typeof element[name] === "boolean") &&
|
|
290
|
+
isWritableProperty(element, name)) {
|
|
291
|
+
if (element[name] !== value || oldValue === undefined) {
|
|
292
|
+
if (isHydrating &&
|
|
293
|
+
typeof element[name] === "string" &&
|
|
294
|
+
element[name] !== value) {
|
|
295
|
+
emitHydrationWarning(name, quietProps, value, element[name], element);
|
|
296
|
+
}
|
|
297
|
+
// if the property is writable, assign it directly
|
|
298
|
+
element[name] = value;
|
|
299
|
+
}
|
|
300
|
+
continue;
|
|
301
|
+
}
|
|
302
|
+
if (value === true) {
|
|
303
|
+
value = "";
|
|
304
|
+
}
|
|
305
|
+
else if (value == null || value === false) {
|
|
306
|
+
if (isHydrating && element.hasAttribute(name)) {
|
|
307
|
+
emitHydrationWarning(name, quietProps, value, element.getAttribute(name), element);
|
|
210
308
|
}
|
|
309
|
+
element.removeAttribute(name);
|
|
310
|
+
continue;
|
|
311
|
+
}
|
|
312
|
+
else if (typeof value !== "string") {
|
|
313
|
+
value = String(value);
|
|
314
|
+
}
|
|
315
|
+
if (element.getAttribute(name) !== value) {
|
|
316
|
+
if (isHydrating) {
|
|
317
|
+
emitHydrationWarning(name, quietProps, value, element.getAttribute(name), element);
|
|
318
|
+
}
|
|
319
|
+
element.setAttribute(name, value);
|
|
211
320
|
}
|
|
212
321
|
}
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
},
|
|
325
|
+
arrange({ tag, node, props, children, }) {
|
|
326
|
+
if (tag === crank.Portal && (node == null || typeof node.nodeType !== "number")) {
|
|
327
|
+
throw new TypeError(`<Portal> root is not a node. Received: ${String(node)}`);
|
|
328
|
+
}
|
|
329
|
+
if (!("innerHTML" in props)) {
|
|
330
|
+
let oldChild = node.firstChild;
|
|
331
|
+
for (let i = 0; i < children.length; i++) {
|
|
332
|
+
const newChild = children[i];
|
|
333
|
+
if (oldChild === newChild) {
|
|
334
|
+
// the child is already in the right place, so we can skip it
|
|
335
|
+
oldChild = oldChild.nextSibling;
|
|
218
336
|
}
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
337
|
+
else {
|
|
338
|
+
node.insertBefore(newChild, oldChild);
|
|
339
|
+
if (tag !== crank.Portal &&
|
|
340
|
+
oldChild &&
|
|
341
|
+
i + 1 < children.length &&
|
|
342
|
+
oldChild !== children[i + 1]) {
|
|
343
|
+
oldChild = oldChild.nextSibling;
|
|
344
|
+
}
|
|
225
345
|
}
|
|
226
346
|
}
|
|
227
347
|
}
|
|
228
348
|
},
|
|
229
|
-
|
|
230
|
-
if (
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
349
|
+
remove({ node, parentNode, isNested, }) {
|
|
350
|
+
if (!isNested && node.parentNode === parentNode) {
|
|
351
|
+
parentNode.removeChild(node);
|
|
352
|
+
}
|
|
353
|
+
},
|
|
354
|
+
text({ value, oldNode, hydrationNodes, }) {
|
|
355
|
+
if (hydrationNodes != null) {
|
|
356
|
+
let node = hydrationNodes.shift();
|
|
357
|
+
if (!node || node.nodeType !== Node.TEXT_NODE) {
|
|
358
|
+
console.warn(`Expected "${value}" while hydrating but found:`, node);
|
|
236
359
|
}
|
|
360
|
+
else {
|
|
361
|
+
// value is a text node, check if it matches the expected text
|
|
362
|
+
const textData = node.data;
|
|
363
|
+
if (textData.length > value.length) {
|
|
364
|
+
if (textData.startsWith(value)) {
|
|
365
|
+
// the text node is longer than the expected text, so we
|
|
366
|
+
// reuse the existing text node, but truncate it and unshift the rest
|
|
367
|
+
node.data = value;
|
|
368
|
+
hydrationNodes.unshift(document.createTextNode(textData.slice(value.length)));
|
|
369
|
+
return node;
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
else if (textData === value) {
|
|
373
|
+
return node;
|
|
374
|
+
}
|
|
375
|
+
// We log textData and not node because node will be mutated
|
|
376
|
+
console.warn(`Expected "${value}" while hydrating but found:`, textData);
|
|
377
|
+
oldNode = node;
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
if (oldNode != null) {
|
|
381
|
+
if (oldNode.data !== value) {
|
|
382
|
+
oldNode.data = value;
|
|
383
|
+
}
|
|
384
|
+
return oldNode;
|
|
237
385
|
}
|
|
238
|
-
return
|
|
386
|
+
return document.createTextNode(value);
|
|
239
387
|
},
|
|
240
|
-
raw(value, xmlns,
|
|
241
|
-
let
|
|
388
|
+
raw({ value, scope: xmlns, hydrationNodes, }) {
|
|
389
|
+
let nodes;
|
|
242
390
|
if (typeof value === "string") {
|
|
243
391
|
const el = xmlns == null
|
|
244
392
|
? document.createElement("div")
|
|
245
393
|
: document.createElementNS(xmlns, "svg");
|
|
246
394
|
el.innerHTML = value;
|
|
247
|
-
|
|
248
|
-
result = undefined;
|
|
249
|
-
}
|
|
250
|
-
else if (el.childNodes.length === 1) {
|
|
251
|
-
result = el.childNodes[0];
|
|
252
|
-
}
|
|
253
|
-
else {
|
|
254
|
-
result = Array.from(el.childNodes);
|
|
255
|
-
}
|
|
395
|
+
nodes = Array.from(el.childNodes);
|
|
256
396
|
}
|
|
257
397
|
else {
|
|
258
|
-
|
|
398
|
+
nodes = value == null ? [] : Array.isArray(value) ? [...value] : [value];
|
|
259
399
|
}
|
|
260
|
-
if (
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
400
|
+
if (hydrationNodes != null) {
|
|
401
|
+
for (let i = 0; i < nodes.length; i++) {
|
|
402
|
+
const node = nodes[i];
|
|
403
|
+
// check if node is equal to the next node in the hydration array
|
|
404
|
+
const hydrationNode = hydrationNodes.shift();
|
|
405
|
+
if (hydrationNode &&
|
|
406
|
+
typeof hydrationNode === "object" &&
|
|
407
|
+
typeof hydrationNode.nodeType === "number" &&
|
|
408
|
+
node.isEqualNode(hydrationNode)) {
|
|
409
|
+
nodes[i] = hydrationNode;
|
|
270
410
|
}
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
if (result.nodeType === Node.ELEMENT_NODE ||
|
|
274
|
-
result.nodeType === Node.TEXT_NODE) {
|
|
275
|
-
hydrationData.children.shift();
|
|
411
|
+
else {
|
|
412
|
+
console.warn(`Expected <Raw value="${String(value)}"> while hydrating but found:`, hydrationNode);
|
|
276
413
|
}
|
|
277
414
|
}
|
|
278
415
|
}
|
|
279
|
-
return
|
|
416
|
+
return nodes.length === 0
|
|
417
|
+
? undefined
|
|
418
|
+
: nodes.length === 1
|
|
419
|
+
? nodes[0]
|
|
420
|
+
: nodes;
|
|
280
421
|
},
|
|
281
422
|
};
|
|
282
423
|
class DOMRenderer extends crank.Renderer {
|
|
283
424
|
constructor() {
|
|
284
|
-
super(
|
|
425
|
+
super(adapter);
|
|
285
426
|
}
|
|
286
427
|
render(children, root, ctx) {
|
|
287
428
|
validateRoot(root);
|
|
@@ -293,14 +434,17 @@ class DOMRenderer extends crank.Renderer {
|
|
|
293
434
|
}
|
|
294
435
|
}
|
|
295
436
|
function validateRoot(root) {
|
|
296
|
-
if (root
|
|
437
|
+
if (root == null ||
|
|
297
438
|
(typeof root === "object" && typeof root.nodeType !== "number")) {
|
|
298
|
-
throw new TypeError(`Render root is not a node. Received: ${
|
|
439
|
+
throw new TypeError(`Render root is not a node. Received: ${String(root)}`);
|
|
440
|
+
}
|
|
441
|
+
else if (root.nodeType !== Node.ELEMENT_NODE) {
|
|
442
|
+
throw new TypeError(`Render root must be an element node. Received: ${String(root)}`);
|
|
299
443
|
}
|
|
300
444
|
}
|
|
301
445
|
const renderer = new DOMRenderer();
|
|
302
446
|
|
|
303
447
|
exports.DOMRenderer = DOMRenderer;
|
|
304
|
-
exports.
|
|
448
|
+
exports.adapter = adapter;
|
|
305
449
|
exports.renderer = renderer;
|
|
306
450
|
//# sourceMappingURL=dom.cjs.map
|