defuss-morph 0.1.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/LICENSE +21 -0
- package/README.md +369 -0
- package/dist/all.js +1312 -0
- package/dist/all.js.map +17 -0
- package/dist/all.min.js +2 -0
- package/dist/all.min.js.map +1 -0
- package/dist/index.cjs +1242 -0
- package/dist/index.d.ts +233 -0
- package/dist/index.mjs +1204 -0
- package/dist/stats.json +22 -0
- package/package.json +89 -0
package/dist/all.js
ADDED
|
@@ -0,0 +1,1312 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __returnValue = (v) => v;
|
|
3
|
+
function __exportSetter(name, newValue) {
|
|
4
|
+
this[name] = __returnValue.bind(null, newValue);
|
|
5
|
+
}
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, {
|
|
9
|
+
get: all[name],
|
|
10
|
+
enumerable: true,
|
|
11
|
+
configurable: true,
|
|
12
|
+
set: __exportSetter.bind(all, name)
|
|
13
|
+
});
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
// src/index.ts
|
|
17
|
+
var exports_src = {};
|
|
18
|
+
__export(exports_src, {
|
|
19
|
+
updateDomWithVdom: () => updateDomWithVdom,
|
|
20
|
+
resolveGlobals: () => resolveGlobals,
|
|
21
|
+
replaceDomWithVdom: () => replaceDomWithVdom,
|
|
22
|
+
renderMarkup: () => renderMarkup,
|
|
23
|
+
removeDelegatedEventByKey: () => removeDelegatedEventByKey,
|
|
24
|
+
removeDelegatedEvent: () => removeDelegatedEvent,
|
|
25
|
+
registerDelegatedEvent: () => registerDelegatedEvent,
|
|
26
|
+
queueCallback: () => queueCallback,
|
|
27
|
+
performTransition: () => performTransition,
|
|
28
|
+
parseEventPropName: () => parseEventPropName,
|
|
29
|
+
parseDOM: () => parseDOM,
|
|
30
|
+
observeUnmount: () => observeUnmount,
|
|
31
|
+
nsMap: () => nsMap,
|
|
32
|
+
morph: () => morph2,
|
|
33
|
+
isSVG: () => isSVG,
|
|
34
|
+
isMarkup: () => isMarkup,
|
|
35
|
+
isHTML: () => isHTML,
|
|
36
|
+
htmlStringToVNodes: () => htmlStringToVNodes,
|
|
37
|
+
handleLifecycleEventsForOnMount: () => handleLifecycleEventsForOnMount,
|
|
38
|
+
getTransitionStyles: () => getTransitionStyles,
|
|
39
|
+
getRenderer: () => getRenderer,
|
|
40
|
+
getRegisteredEventTypes: () => getRegisteredEventTypes,
|
|
41
|
+
getRegisteredEventKeys: () => getRegisteredEventKeys,
|
|
42
|
+
getMimeType: () => getMimeType,
|
|
43
|
+
domNodeToVNode: () => domNodeToVNode,
|
|
44
|
+
clearDelegatedEventsDeep: () => clearDelegatedEventsDeep,
|
|
45
|
+
clearDelegatedEvents: () => clearDelegatedEvents,
|
|
46
|
+
areDomNodesEqual: () => areDomNodesEqual,
|
|
47
|
+
applyStyles: () => applyStyles,
|
|
48
|
+
XMLNS_ATTRIBUTE_NAME: () => XMLNS_ATTRIBUTE_NAME,
|
|
49
|
+
XLINK_ATTRIBUTE_NAME: () => XLINK_ATTRIBUTE_NAME,
|
|
50
|
+
REF_ATTRIBUTE_NAME: () => REF_ATTRIBUTE_NAME,
|
|
51
|
+
FROM_DOM_MARKER: () => FROM_DOM_MARKER,
|
|
52
|
+
DEFAULT_TRANSITION_CONFIG: () => DEFAULT_TRANSITION_CONFIG,
|
|
53
|
+
DANGEROUSLY_SET_INNER_HTML_ATTRIBUTE: () => DANGEROUSLY_SET_INNER_HTML_ATTRIBUTE,
|
|
54
|
+
CLASS_ATTRIBUTE_NAME: () => CLASS_ATTRIBUTE_NAME,
|
|
55
|
+
CAPTURE_ONLY_EVENTS: () => CAPTURE_ONLY_EVENTS
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
// src/queue.ts
|
|
59
|
+
var queueCallback = (cb) => (...args) => queueMicrotask(() => cb(...args));
|
|
60
|
+
|
|
61
|
+
// src/delegated-events.ts
|
|
62
|
+
var CAPTURE_ONLY_EVENTS = new Set([
|
|
63
|
+
"focus",
|
|
64
|
+
"blur",
|
|
65
|
+
"scroll",
|
|
66
|
+
"mouseenter",
|
|
67
|
+
"mouseleave"
|
|
68
|
+
]);
|
|
69
|
+
var elementHandlerMap = new WeakMap;
|
|
70
|
+
var bubbleDispatched = new WeakMap;
|
|
71
|
+
var captureDispatched = new WeakMap;
|
|
72
|
+
var activeDispatches = new WeakMap;
|
|
73
|
+
var parseEventPropName = (propName) => {
|
|
74
|
+
if (!propName.startsWith("on"))
|
|
75
|
+
return null;
|
|
76
|
+
const raw = propName.slice(2);
|
|
77
|
+
if (!raw)
|
|
78
|
+
return null;
|
|
79
|
+
const lower = raw.toLowerCase();
|
|
80
|
+
const isCapture = lower.endsWith("capture");
|
|
81
|
+
const eventType = isCapture ? lower.slice(0, -"capture".length) : lower;
|
|
82
|
+
if (!eventType)
|
|
83
|
+
return null;
|
|
84
|
+
return { eventType, capture: isCapture };
|
|
85
|
+
};
|
|
86
|
+
var getOrCreateElementHandlers = (el) => {
|
|
87
|
+
const existing = elementHandlerMap.get(el);
|
|
88
|
+
if (existing)
|
|
89
|
+
return existing;
|
|
90
|
+
const created = new Map;
|
|
91
|
+
elementHandlerMap.set(el, created);
|
|
92
|
+
return created;
|
|
93
|
+
};
|
|
94
|
+
var getEventPath = (event) => {
|
|
95
|
+
const composedPath = event.composedPath?.();
|
|
96
|
+
if (composedPath && composedPath.length > 0)
|
|
97
|
+
return composedPath;
|
|
98
|
+
const path = [];
|
|
99
|
+
let node = event.target;
|
|
100
|
+
while (node) {
|
|
101
|
+
path.push(node);
|
|
102
|
+
const maybeNode = node;
|
|
103
|
+
if (typeof maybeNode === "object" && maybeNode && "parentNode" in maybeNode) {
|
|
104
|
+
node = maybeNode.parentNode;
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
break;
|
|
108
|
+
}
|
|
109
|
+
const doc = event.target?.ownerDocument;
|
|
110
|
+
if (doc && path[path.length - 1] !== doc)
|
|
111
|
+
path.push(doc);
|
|
112
|
+
const win = doc?.defaultView;
|
|
113
|
+
if (win && path[path.length - 1] !== win)
|
|
114
|
+
path.push(win);
|
|
115
|
+
return path;
|
|
116
|
+
};
|
|
117
|
+
var createPhaseHandler = (eventType, phase) => {
|
|
118
|
+
const dispatched = phase === "capture" ? captureDispatched : bubbleDispatched;
|
|
119
|
+
return (event) => {
|
|
120
|
+
const path = getEventPath(event).filter((t) => typeof t === "object" && t !== null && t.nodeType === 1);
|
|
121
|
+
const ordered = phase === "capture" ? [...path].reverse() : path;
|
|
122
|
+
for (const target of ordered) {
|
|
123
|
+
const handlersByEvent = elementHandlerMap.get(target);
|
|
124
|
+
if (!handlersByEvent)
|
|
125
|
+
continue;
|
|
126
|
+
const entry = handlersByEvent.get(eventType);
|
|
127
|
+
if (!entry)
|
|
128
|
+
continue;
|
|
129
|
+
let targets = dispatched.get(event);
|
|
130
|
+
if (targets?.has(target))
|
|
131
|
+
continue;
|
|
132
|
+
if (!targets) {
|
|
133
|
+
targets = new WeakSet;
|
|
134
|
+
dispatched.set(event, targets);
|
|
135
|
+
}
|
|
136
|
+
targets.add(target);
|
|
137
|
+
const dispatchKey = `${eventType}:${phase}`;
|
|
138
|
+
let activeSet = activeDispatches.get(target);
|
|
139
|
+
if (activeSet?.has(dispatchKey))
|
|
140
|
+
continue;
|
|
141
|
+
if (!activeSet) {
|
|
142
|
+
activeSet = new Set;
|
|
143
|
+
activeDispatches.set(target, activeSet);
|
|
144
|
+
}
|
|
145
|
+
activeSet.add(dispatchKey);
|
|
146
|
+
try {
|
|
147
|
+
if (phase === "capture") {
|
|
148
|
+
if (entry.capture) {
|
|
149
|
+
entry.capture.call(target, event);
|
|
150
|
+
if (event.cancelBubble)
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
if (entry.captureSet) {
|
|
154
|
+
for (const handler of entry.captureSet) {
|
|
155
|
+
handler.call(target, event);
|
|
156
|
+
if (event.cancelBubble)
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
} else {
|
|
161
|
+
if (entry.bubble) {
|
|
162
|
+
entry.bubble.call(target, event);
|
|
163
|
+
if (event.cancelBubble)
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
if (entry.bubbleSet) {
|
|
167
|
+
for (const handler of entry.bubbleSet) {
|
|
168
|
+
handler.call(target, event);
|
|
169
|
+
if (event.cancelBubble)
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
} finally {
|
|
175
|
+
activeSet.delete(dispatchKey);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
};
|
|
180
|
+
var installedRootListeners = new WeakMap;
|
|
181
|
+
var ensureRootListener = (root, eventType) => {
|
|
182
|
+
const installed = installedRootListeners.get(root) ?? new Set;
|
|
183
|
+
installedRootListeners.set(root, installed);
|
|
184
|
+
const captureKey = `${eventType}:capture`;
|
|
185
|
+
if (!installed.has(captureKey)) {
|
|
186
|
+
root.addEventListener(eventType, createPhaseHandler(eventType, "capture"), true);
|
|
187
|
+
installed.add(captureKey);
|
|
188
|
+
}
|
|
189
|
+
const bubbleKey = `${eventType}:bubble`;
|
|
190
|
+
if (!installed.has(bubbleKey)) {
|
|
191
|
+
root.addEventListener(eventType, createPhaseHandler(eventType, "bubble"), false);
|
|
192
|
+
installed.add(bubbleKey);
|
|
193
|
+
}
|
|
194
|
+
};
|
|
195
|
+
var getEventRoot = (element) => {
|
|
196
|
+
const root = element.getRootNode();
|
|
197
|
+
if (root && root.nodeType === 9) {
|
|
198
|
+
return root;
|
|
199
|
+
}
|
|
200
|
+
if (root && root.nodeType === 11 && "host" in root) {
|
|
201
|
+
return root;
|
|
202
|
+
}
|
|
203
|
+
return null;
|
|
204
|
+
};
|
|
205
|
+
var registerDelegatedEvent = (element, eventType, handler, options = {}) => {
|
|
206
|
+
const root = getEventRoot(element);
|
|
207
|
+
const capture = options.capture || CAPTURE_ONLY_EVENTS.has(eventType);
|
|
208
|
+
if (root) {
|
|
209
|
+
ensureRootListener(root, eventType);
|
|
210
|
+
} else if (element.ownerDocument) {
|
|
211
|
+
ensureRootListener(element.ownerDocument, eventType);
|
|
212
|
+
} else {
|
|
213
|
+
element.addEventListener(eventType, handler, capture);
|
|
214
|
+
}
|
|
215
|
+
const byEvent = getOrCreateElementHandlers(element);
|
|
216
|
+
const entry = byEvent.get(eventType) ?? {};
|
|
217
|
+
byEvent.set(eventType, entry);
|
|
218
|
+
if (options.multi) {
|
|
219
|
+
if (capture) {
|
|
220
|
+
if (!entry.captureSet)
|
|
221
|
+
entry.captureSet = new Set;
|
|
222
|
+
entry.captureSet.add(handler);
|
|
223
|
+
} else {
|
|
224
|
+
if (!entry.bubbleSet)
|
|
225
|
+
entry.bubbleSet = new Set;
|
|
226
|
+
entry.bubbleSet.add(handler);
|
|
227
|
+
}
|
|
228
|
+
} else {
|
|
229
|
+
if (capture) {
|
|
230
|
+
entry.capture = handler;
|
|
231
|
+
} else {
|
|
232
|
+
entry.bubble = handler;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
};
|
|
236
|
+
var isEntryEmpty = (entry) => !entry.capture && !entry.bubble && (!entry.captureSet || entry.captureSet.size === 0) && (!entry.bubbleSet || entry.bubbleSet.size === 0);
|
|
237
|
+
var removeDelegatedEvent = (target, eventType, handler, _options = {}) => {
|
|
238
|
+
const byEvent = elementHandlerMap.get(target);
|
|
239
|
+
if (!byEvent)
|
|
240
|
+
return;
|
|
241
|
+
const entry = byEvent.get(eventType);
|
|
242
|
+
if (!entry)
|
|
243
|
+
return;
|
|
244
|
+
if (handler) {
|
|
245
|
+
if (entry.captureSet) {
|
|
246
|
+
entry.captureSet.delete(handler);
|
|
247
|
+
}
|
|
248
|
+
if (entry.bubbleSet) {
|
|
249
|
+
entry.bubbleSet.delete(handler);
|
|
250
|
+
}
|
|
251
|
+
if (entry.capture === handler) {
|
|
252
|
+
entry.capture = undefined;
|
|
253
|
+
}
|
|
254
|
+
if (entry.bubble === handler) {
|
|
255
|
+
entry.bubble = undefined;
|
|
256
|
+
}
|
|
257
|
+
target.removeEventListener(eventType, handler, true);
|
|
258
|
+
target.removeEventListener(eventType, handler, false);
|
|
259
|
+
} else {
|
|
260
|
+
entry.capture = undefined;
|
|
261
|
+
entry.bubble = undefined;
|
|
262
|
+
entry.captureSet = undefined;
|
|
263
|
+
entry.bubbleSet = undefined;
|
|
264
|
+
}
|
|
265
|
+
if (isEntryEmpty(entry)) {
|
|
266
|
+
byEvent.delete(eventType);
|
|
267
|
+
}
|
|
268
|
+
};
|
|
269
|
+
var clearDelegatedEvents = (target) => {
|
|
270
|
+
const byEvent = elementHandlerMap.get(target);
|
|
271
|
+
if (!byEvent)
|
|
272
|
+
return;
|
|
273
|
+
byEvent.clear();
|
|
274
|
+
};
|
|
275
|
+
var clearDelegatedEventsDeep = (root) => {
|
|
276
|
+
clearDelegatedEvents(root);
|
|
277
|
+
const doc = root.ownerDocument;
|
|
278
|
+
if (!doc)
|
|
279
|
+
return;
|
|
280
|
+
const walker = doc.createTreeWalker(root, 1);
|
|
281
|
+
let node = walker.nextNode();
|
|
282
|
+
while (node) {
|
|
283
|
+
clearDelegatedEvents(node);
|
|
284
|
+
node = walker.nextNode();
|
|
285
|
+
}
|
|
286
|
+
};
|
|
287
|
+
var getRegisteredEventTypes = (element) => {
|
|
288
|
+
const byEvent = elementHandlerMap.get(element);
|
|
289
|
+
if (!byEvent)
|
|
290
|
+
return new Set;
|
|
291
|
+
return new Set(byEvent.keys());
|
|
292
|
+
};
|
|
293
|
+
var getRegisteredEventKeys = (element) => {
|
|
294
|
+
const byEvent = elementHandlerMap.get(element);
|
|
295
|
+
if (!byEvent)
|
|
296
|
+
return new Set;
|
|
297
|
+
const keys = new Set;
|
|
298
|
+
for (const [eventType, entry] of byEvent) {
|
|
299
|
+
if (entry.bubble || entry.bubbleSet?.size)
|
|
300
|
+
keys.add(`${eventType}:bubble`);
|
|
301
|
+
if (entry.capture || entry.captureSet?.size)
|
|
302
|
+
keys.add(`${eventType}:capture`);
|
|
303
|
+
}
|
|
304
|
+
return keys;
|
|
305
|
+
};
|
|
306
|
+
var removeDelegatedEventByKey = (element, eventType, phase) => {
|
|
307
|
+
const byEvent = elementHandlerMap.get(element);
|
|
308
|
+
if (!byEvent)
|
|
309
|
+
return;
|
|
310
|
+
const entry = byEvent.get(eventType);
|
|
311
|
+
if (!entry)
|
|
312
|
+
return;
|
|
313
|
+
if (phase === "capture") {
|
|
314
|
+
entry.capture = undefined;
|
|
315
|
+
entry.captureSet = undefined;
|
|
316
|
+
} else {
|
|
317
|
+
entry.bubble = undefined;
|
|
318
|
+
entry.bubbleSet = undefined;
|
|
319
|
+
}
|
|
320
|
+
if (isEntryEmpty(entry))
|
|
321
|
+
byEvent.delete(eventType);
|
|
322
|
+
};
|
|
323
|
+
|
|
324
|
+
// src/renderer.ts
|
|
325
|
+
var CLASS_ATTRIBUTE_NAME = "class";
|
|
326
|
+
var XLINK_ATTRIBUTE_NAME = "xlink";
|
|
327
|
+
var XMLNS_ATTRIBUTE_NAME = "xmlns";
|
|
328
|
+
var REF_ATTRIBUTE_NAME = "ref";
|
|
329
|
+
var DANGEROUSLY_SET_INNER_HTML_ATTRIBUTE = "dangerouslySetInnerHTML";
|
|
330
|
+
var nsMap = {
|
|
331
|
+
[XMLNS_ATTRIBUTE_NAME]: "http://www.w3.org/2000/xmlns/",
|
|
332
|
+
[XLINK_ATTRIBUTE_NAME]: "http://www.w3.org/1999/xlink",
|
|
333
|
+
svg: "http://www.w3.org/2000/svg"
|
|
334
|
+
};
|
|
335
|
+
var observeUnmount = (domNode, onUnmount) => {
|
|
336
|
+
if (!domNode || typeof onUnmount !== "function") {
|
|
337
|
+
throw new Error("Invalid arguments. Ensure domNode and onUnmount are valid.");
|
|
338
|
+
}
|
|
339
|
+
if (typeof MutationObserver === "undefined") {
|
|
340
|
+
return;
|
|
341
|
+
}
|
|
342
|
+
let parentNode = domNode.parentNode;
|
|
343
|
+
if (!parentNode) {
|
|
344
|
+
throw new Error("The provided domNode does not have a parentNode.");
|
|
345
|
+
}
|
|
346
|
+
const observer = new MutationObserver((mutationsList) => {
|
|
347
|
+
for (const mutation of mutationsList) {
|
|
348
|
+
if (mutation.removedNodes.length > 0) {
|
|
349
|
+
for (const removedNode of mutation.removedNodes) {
|
|
350
|
+
if (removedNode === domNode) {
|
|
351
|
+
queueMicrotask(() => {
|
|
352
|
+
if (!domNode.isConnected) {
|
|
353
|
+
onUnmount();
|
|
354
|
+
observer.disconnect();
|
|
355
|
+
return;
|
|
356
|
+
}
|
|
357
|
+
const newParent = domNode.parentNode;
|
|
358
|
+
if (newParent && newParent !== parentNode) {
|
|
359
|
+
parentNode = newParent;
|
|
360
|
+
observer.disconnect();
|
|
361
|
+
observer.observe(parentNode, { childList: true });
|
|
362
|
+
}
|
|
363
|
+
});
|
|
364
|
+
return;
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
});
|
|
370
|
+
observer.observe(parentNode, { childList: true });
|
|
371
|
+
};
|
|
372
|
+
var handleLifecycleEventsForOnMount = (newEl) => {
|
|
373
|
+
if (typeof newEl?.$onMount === "function") {
|
|
374
|
+
newEl.$onMount(newEl);
|
|
375
|
+
newEl.$onMount = null;
|
|
376
|
+
}
|
|
377
|
+
if (typeof newEl?.$onUnmount === "function") {
|
|
378
|
+
observeUnmount(newEl, newEl.$onUnmount);
|
|
379
|
+
}
|
|
380
|
+
};
|
|
381
|
+
var getRenderer = (document2) => {
|
|
382
|
+
const renderer = {
|
|
383
|
+
hasElNamespace: (domElement) => domElement.namespaceURI === nsMap.svg,
|
|
384
|
+
hasSvgNamespace: (parentElement, type) => renderer.hasElNamespace(parentElement) && type !== "STYLE" && type !== "SCRIPT",
|
|
385
|
+
createElementOrElements: (virtualNode, parentDomElement) => {
|
|
386
|
+
if (Array.isArray(virtualNode)) {
|
|
387
|
+
return renderer.createChildElements(virtualNode, parentDomElement);
|
|
388
|
+
}
|
|
389
|
+
if (typeof virtualNode !== "undefined") {
|
|
390
|
+
return renderer.createElement(virtualNode, parentDomElement);
|
|
391
|
+
}
|
|
392
|
+
return renderer.createTextNode("", parentDomElement);
|
|
393
|
+
},
|
|
394
|
+
createElement: (virtualNode, parentDomElement) => {
|
|
395
|
+
let newEl;
|
|
396
|
+
try {
|
|
397
|
+
if (typeof virtualNode === "function" && virtualNode.constructor.name === "AsyncFunction") {
|
|
398
|
+
newEl = document2.createElement("div");
|
|
399
|
+
} else if (typeof virtualNode === "object" && virtualNode !== null && "type" in virtualNode) {
|
|
400
|
+
const vNode = virtualNode;
|
|
401
|
+
if (typeof vNode.type === "function") {
|
|
402
|
+
newEl = document2.createElement("div");
|
|
403
|
+
newEl.innerText = `FATAL ERROR: ${vNode.type._error}`;
|
|
404
|
+
} else if (typeof vNode.type === "string" && vNode.type.toUpperCase() === "SVG" || parentDomElement && renderer.hasSvgNamespace(parentDomElement, typeof vNode.type === "string" ? vNode.type.toUpperCase() : "")) {
|
|
405
|
+
newEl = document2.createElementNS(nsMap.svg, vNode.type);
|
|
406
|
+
} else {
|
|
407
|
+
newEl = document2.createElement(vNode.type);
|
|
408
|
+
}
|
|
409
|
+
if (vNode.attributes) {
|
|
410
|
+
renderer.setAttributes(vNode, newEl);
|
|
411
|
+
if (vNode.attributes.dangerouslySetInnerHTML) {
|
|
412
|
+
newEl.innerHTML = vNode.attributes.dangerouslySetInnerHTML.__html;
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
if (vNode.children && !vNode.attributes?.dangerouslySetInnerHTML) {
|
|
416
|
+
renderer.createChildElements(vNode.children, newEl);
|
|
417
|
+
}
|
|
418
|
+
} else {
|
|
419
|
+
if (typeof virtualNode === "string" || typeof virtualNode === "number") {
|
|
420
|
+
newEl = document2.createElement(String(virtualNode));
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
if (newEl && parentDomElement) {
|
|
424
|
+
parentDomElement.appendChild(newEl);
|
|
425
|
+
handleLifecycleEventsForOnMount(newEl);
|
|
426
|
+
}
|
|
427
|
+
} catch (e) {
|
|
428
|
+
console.error("Fatal error! Error happend while rendering the VDOM!", e, virtualNode);
|
|
429
|
+
throw e;
|
|
430
|
+
}
|
|
431
|
+
return newEl;
|
|
432
|
+
},
|
|
433
|
+
createTextNode: (text, domElement) => {
|
|
434
|
+
const node = document2.createTextNode(text.toString());
|
|
435
|
+
if (domElement) {
|
|
436
|
+
domElement.appendChild(node);
|
|
437
|
+
}
|
|
438
|
+
return node;
|
|
439
|
+
},
|
|
440
|
+
createChildElements: (virtualChildren, domElement) => {
|
|
441
|
+
const children = [];
|
|
442
|
+
for (let i = 0;i < virtualChildren.length; i++) {
|
|
443
|
+
const virtualChild = virtualChildren[i];
|
|
444
|
+
if (typeof virtualChild === "boolean") {
|
|
445
|
+
continue;
|
|
446
|
+
}
|
|
447
|
+
if (virtualChild === null || typeof virtualChild !== "object" && typeof virtualChild !== "function") {
|
|
448
|
+
children.push(renderer.createTextNode((typeof virtualChild === "undefined" || virtualChild === null ? "" : virtualChild).toString(), domElement));
|
|
449
|
+
} else {
|
|
450
|
+
children.push(renderer.createElement(virtualChild, domElement));
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
return children;
|
|
454
|
+
},
|
|
455
|
+
setAttribute: (name, value, domElement) => {
|
|
456
|
+
if (typeof value === "undefined")
|
|
457
|
+
return;
|
|
458
|
+
if (name === DANGEROUSLY_SET_INNER_HTML_ATTRIBUTE)
|
|
459
|
+
return;
|
|
460
|
+
if (name === "key") {
|
|
461
|
+
domElement._defussKey = String(value);
|
|
462
|
+
return;
|
|
463
|
+
}
|
|
464
|
+
if (name === REF_ATTRIBUTE_NAME && typeof value !== "function") {
|
|
465
|
+
const ref = value;
|
|
466
|
+
ref.current = domElement;
|
|
467
|
+
domElement._defussRef = value;
|
|
468
|
+
domElement.$onUnmount = queueCallback(() => {});
|
|
469
|
+
if (domElement.parentNode) {
|
|
470
|
+
observeUnmount(domElement, domElement.$onUnmount);
|
|
471
|
+
} else {
|
|
472
|
+
queueMicrotask(() => {
|
|
473
|
+
if (domElement.parentNode) {
|
|
474
|
+
observeUnmount(domElement, domElement.$onUnmount);
|
|
475
|
+
}
|
|
476
|
+
});
|
|
477
|
+
}
|
|
478
|
+
return;
|
|
479
|
+
}
|
|
480
|
+
const parsed = parseEventPropName(name);
|
|
481
|
+
if (parsed && typeof value === "function") {
|
|
482
|
+
const { eventType, capture } = parsed;
|
|
483
|
+
if (eventType === "mount") {
|
|
484
|
+
domElement.$onMount = queueCallback(value);
|
|
485
|
+
return;
|
|
486
|
+
}
|
|
487
|
+
if (eventType === "unmount") {
|
|
488
|
+
if (domElement.$onUnmount) {
|
|
489
|
+
const existingUnmount = domElement.$onUnmount;
|
|
490
|
+
domElement.$onUnmount = () => {
|
|
491
|
+
existingUnmount();
|
|
492
|
+
value();
|
|
493
|
+
};
|
|
494
|
+
} else {
|
|
495
|
+
domElement.$onUnmount = queueCallback(value);
|
|
496
|
+
}
|
|
497
|
+
return;
|
|
498
|
+
}
|
|
499
|
+
registerDelegatedEvent(domElement, eventType, value, { capture });
|
|
500
|
+
return;
|
|
501
|
+
}
|
|
502
|
+
if (name === "className") {
|
|
503
|
+
name = CLASS_ATTRIBUTE_NAME;
|
|
504
|
+
}
|
|
505
|
+
if (name === CLASS_ATTRIBUTE_NAME && Array.isArray(value)) {
|
|
506
|
+
value = value.filter((val) => !!val).join(" ");
|
|
507
|
+
}
|
|
508
|
+
const nsEndIndex = name.match(/[A-Z]/)?.index;
|
|
509
|
+
if (renderer.hasElNamespace(domElement) && nsEndIndex) {
|
|
510
|
+
const ns = name.substring(0, nsEndIndex).toLowerCase();
|
|
511
|
+
const attrName = name.substring(nsEndIndex, name.length).toLowerCase();
|
|
512
|
+
const namespace = nsMap[ns] || null;
|
|
513
|
+
domElement.setAttributeNS(namespace, ns === XLINK_ATTRIBUTE_NAME || ns === XMLNS_ATTRIBUTE_NAME ? `${ns}:${attrName}` : name, String(value));
|
|
514
|
+
} else if (name === "style" && typeof value !== "string") {
|
|
515
|
+
const styleObj = value;
|
|
516
|
+
for (const prop of Object.keys(styleObj)) {
|
|
517
|
+
domElement.style[prop] = String(styleObj[prop]);
|
|
518
|
+
}
|
|
519
|
+
} else if (typeof value === "boolean") {
|
|
520
|
+
domElement[name] = value;
|
|
521
|
+
if (value) {
|
|
522
|
+
domElement.setAttribute(name, "");
|
|
523
|
+
} else {
|
|
524
|
+
domElement.removeAttribute(name);
|
|
525
|
+
}
|
|
526
|
+
} else if ((name === "value" || name === "checked" || name === "selectedIndex") && (domElement.nodeName === "INPUT" || domElement.nodeName === "TEXTAREA" || domElement.nodeName === "SELECT")) {
|
|
527
|
+
domElement[name] = value;
|
|
528
|
+
if (name === "checked") {
|
|
529
|
+
if (value) {
|
|
530
|
+
domElement.setAttribute("checked", "");
|
|
531
|
+
} else {
|
|
532
|
+
domElement.removeAttribute("checked");
|
|
533
|
+
}
|
|
534
|
+
} else if (name === "value") {
|
|
535
|
+
domElement.setAttribute("value", String(value));
|
|
536
|
+
}
|
|
537
|
+
} else {
|
|
538
|
+
domElement.setAttribute(name, String(value));
|
|
539
|
+
}
|
|
540
|
+
},
|
|
541
|
+
setAttributes: (virtualNode, domElement) => {
|
|
542
|
+
const attrNames = Object.keys(virtualNode.attributes ?? {});
|
|
543
|
+
for (let i = 0;i < attrNames.length; i++) {
|
|
544
|
+
renderer.setAttribute(attrNames[i], virtualNode.attributes[attrNames[i]], domElement);
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
};
|
|
548
|
+
return renderer;
|
|
549
|
+
};
|
|
550
|
+
|
|
551
|
+
// src/html.ts
|
|
552
|
+
var FROM_DOM_MARKER = Symbol("defuss-morph.from-dom");
|
|
553
|
+
var HTML_BOOLEAN_ATTRIBUTES = new Set([
|
|
554
|
+
"allowfullscreen",
|
|
555
|
+
"async",
|
|
556
|
+
"autofocus",
|
|
557
|
+
"autoplay",
|
|
558
|
+
"checked",
|
|
559
|
+
"controls",
|
|
560
|
+
"default",
|
|
561
|
+
"defer",
|
|
562
|
+
"disabled",
|
|
563
|
+
"formnovalidate",
|
|
564
|
+
"hidden",
|
|
565
|
+
"inert",
|
|
566
|
+
"ismap",
|
|
567
|
+
"itemscope",
|
|
568
|
+
"loop",
|
|
569
|
+
"multiple",
|
|
570
|
+
"muted",
|
|
571
|
+
"nomodule",
|
|
572
|
+
"novalidate",
|
|
573
|
+
"open",
|
|
574
|
+
"playsinline",
|
|
575
|
+
"readonly",
|
|
576
|
+
"required",
|
|
577
|
+
"reversed",
|
|
578
|
+
"selected"
|
|
579
|
+
]);
|
|
580
|
+
var domAttributeToVNodeValue = (attr) => HTML_BOOLEAN_ATTRIBUTES.has(attr.name.toLowerCase()) ? true : attr.value;
|
|
581
|
+
function parseDOM(input, type, Parser) {
|
|
582
|
+
return new Parser().parseFromString(input, type);
|
|
583
|
+
}
|
|
584
|
+
function isSVG(input, Parser) {
|
|
585
|
+
const doc = parseDOM(input, "image/svg+xml", Parser);
|
|
586
|
+
if (!doc.documentElement)
|
|
587
|
+
return false;
|
|
588
|
+
return doc.documentElement.nodeName.toLowerCase() === "svg";
|
|
589
|
+
}
|
|
590
|
+
function isHTML(input, Parser) {
|
|
591
|
+
const doc = parseDOM(input, "text/html", Parser);
|
|
592
|
+
return doc.documentElement.querySelectorAll("*").length > 2;
|
|
593
|
+
}
|
|
594
|
+
var isMarkup = (input, Parser) => input.indexOf("<") > -1 && input.indexOf(">") > -1 && (isHTML(input, Parser) || isSVG(input, Parser));
|
|
595
|
+
function renderMarkup(markup, Parser, doc) {
|
|
596
|
+
const parsed = doc ? doc : parseDOM(markup, getMimeType(markup, Parser), Parser);
|
|
597
|
+
if (parsed.body)
|
|
598
|
+
return Array.from(parsed.body.childNodes);
|
|
599
|
+
return parsed.documentElement ? [parsed.documentElement] : [];
|
|
600
|
+
}
|
|
601
|
+
function getMimeType(input, Parser) {
|
|
602
|
+
if (isSVG(input, Parser)) {
|
|
603
|
+
return "image/svg+xml";
|
|
604
|
+
}
|
|
605
|
+
return "text/html";
|
|
606
|
+
}
|
|
607
|
+
function domNodeToVNode(node) {
|
|
608
|
+
if (node.nodeType === 3) {
|
|
609
|
+
return node.textContent || "";
|
|
610
|
+
}
|
|
611
|
+
if (node.nodeType === 1) {
|
|
612
|
+
const element = node;
|
|
613
|
+
const attributes = {};
|
|
614
|
+
for (let i = 0;i < element.attributes.length; i++) {
|
|
615
|
+
const attr = element.attributes[i];
|
|
616
|
+
attributes[attr.name] = domAttributeToVNodeValue(attr);
|
|
617
|
+
}
|
|
618
|
+
const children = [];
|
|
619
|
+
for (let i = 0;i < element.childNodes.length; i++) {
|
|
620
|
+
const childVNode = domNodeToVNode(element.childNodes[i]);
|
|
621
|
+
children.push(childVNode);
|
|
622
|
+
}
|
|
623
|
+
return {
|
|
624
|
+
type: element.tagName.toLowerCase(),
|
|
625
|
+
attributes: { ...attributes, [FROM_DOM_MARKER]: true },
|
|
626
|
+
children
|
|
627
|
+
};
|
|
628
|
+
}
|
|
629
|
+
return "";
|
|
630
|
+
}
|
|
631
|
+
function htmlStringToVNodes(html, Parser) {
|
|
632
|
+
const parser = new Parser;
|
|
633
|
+
const doc = parser.parseFromString(html, "text/html");
|
|
634
|
+
const vNodes = [];
|
|
635
|
+
for (let i = 0;i < doc.body.childNodes.length; i++) {
|
|
636
|
+
const vnode = domNodeToVNode(doc.body.childNodes[i]);
|
|
637
|
+
if (vnode !== "") {
|
|
638
|
+
vNodes.push(vnode);
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
return vNodes;
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
// src/morph.ts
|
|
645
|
+
var areDomNodesEqual = (oldNode, newNode) => {
|
|
646
|
+
if (oldNode === newNode)
|
|
647
|
+
return true;
|
|
648
|
+
if (oldNode.nodeType !== newNode.nodeType)
|
|
649
|
+
return false;
|
|
650
|
+
if (oldNode.nodeType === 1) {
|
|
651
|
+
const oldElement = oldNode;
|
|
652
|
+
const newElement = newNode;
|
|
653
|
+
if (oldElement.tagName !== newElement.tagName)
|
|
654
|
+
return false;
|
|
655
|
+
const oldAttrs = oldElement.attributes;
|
|
656
|
+
const newAttrs = newElement.attributes;
|
|
657
|
+
if (oldAttrs.length !== newAttrs.length)
|
|
658
|
+
return false;
|
|
659
|
+
for (let i = 0;i < oldAttrs.length; i++) {
|
|
660
|
+
const oldAttr = oldAttrs[i];
|
|
661
|
+
const newAttrValue = newElement.getAttribute(oldAttr.name);
|
|
662
|
+
if (oldAttr.value !== newAttrValue)
|
|
663
|
+
return false;
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
if (oldNode.nodeType === 3) {
|
|
667
|
+
if (oldNode.textContent !== newNode.textContent)
|
|
668
|
+
return false;
|
|
669
|
+
}
|
|
670
|
+
return true;
|
|
671
|
+
};
|
|
672
|
+
function isTextLike(value) {
|
|
673
|
+
return typeof value === "string" || typeof value === "number" || typeof value === "boolean";
|
|
674
|
+
}
|
|
675
|
+
function isVNode(value) {
|
|
676
|
+
return Boolean(value && typeof value === "object" && "type" in value);
|
|
677
|
+
}
|
|
678
|
+
function toValidChild(child, lenient = false) {
|
|
679
|
+
if (child == null)
|
|
680
|
+
return child;
|
|
681
|
+
if (isTextLike(child))
|
|
682
|
+
return child;
|
|
683
|
+
if (isVNode(child))
|
|
684
|
+
return child;
|
|
685
|
+
if (lenient && child && typeof child === "object" && "attributes" in child)
|
|
686
|
+
return child;
|
|
687
|
+
return;
|
|
688
|
+
}
|
|
689
|
+
function normalizeChildren(input, lenient = false) {
|
|
690
|
+
const raw = [];
|
|
691
|
+
const pushChild = (child) => {
|
|
692
|
+
if (Array.isArray(child)) {
|
|
693
|
+
child.forEach(pushChild);
|
|
694
|
+
return;
|
|
695
|
+
}
|
|
696
|
+
const valid = toValidChild(child, lenient);
|
|
697
|
+
if (typeof valid === "undefined")
|
|
698
|
+
return;
|
|
699
|
+
if (isVNode(valid) && (valid.type === "fragment" || valid.type === "Fragment")) {
|
|
700
|
+
const nested = Array.isArray(valid.children) ? valid.children : [];
|
|
701
|
+
nested.forEach(pushChild);
|
|
702
|
+
return;
|
|
703
|
+
}
|
|
704
|
+
if (valid === null || typeof valid === "undefined" || typeof valid === "boolean")
|
|
705
|
+
return;
|
|
706
|
+
raw.push(valid);
|
|
707
|
+
};
|
|
708
|
+
pushChild(input);
|
|
709
|
+
const fused = [];
|
|
710
|
+
let buffer = null;
|
|
711
|
+
const flush = () => {
|
|
712
|
+
if (buffer !== null && buffer.length > 0)
|
|
713
|
+
fused.push(buffer);
|
|
714
|
+
buffer = null;
|
|
715
|
+
};
|
|
716
|
+
for (const child of raw) {
|
|
717
|
+
if (typeof child === "string" || typeof child === "number" || typeof child === "boolean") {
|
|
718
|
+
buffer = (buffer ?? "") + String(child);
|
|
719
|
+
continue;
|
|
720
|
+
}
|
|
721
|
+
flush();
|
|
722
|
+
fused.push(child);
|
|
723
|
+
}
|
|
724
|
+
flush();
|
|
725
|
+
return fused;
|
|
726
|
+
}
|
|
727
|
+
function getVNodeMatchKey(child) {
|
|
728
|
+
if (!child || typeof child !== "object")
|
|
729
|
+
return null;
|
|
730
|
+
const key = child.attributes?.key;
|
|
731
|
+
if (typeof key === "string" || typeof key === "number")
|
|
732
|
+
return `k:${String(key)}`;
|
|
733
|
+
const id = child.attributes?.id;
|
|
734
|
+
if (typeof id === "string" && id.length > 0)
|
|
735
|
+
return `id:${id}`;
|
|
736
|
+
return null;
|
|
737
|
+
}
|
|
738
|
+
function describePatchItem(child) {
|
|
739
|
+
if (child && typeof child === "object") {
|
|
740
|
+
return `<${typeof child.type === "string" ? child.type : "component"}>`;
|
|
741
|
+
}
|
|
742
|
+
return "plain text";
|
|
743
|
+
}
|
|
744
|
+
function getDomMatchKeys(node) {
|
|
745
|
+
if (node.nodeType !== 1)
|
|
746
|
+
return [];
|
|
747
|
+
const el = node;
|
|
748
|
+
const keys = [];
|
|
749
|
+
const internalKey = el._defussKey;
|
|
750
|
+
if (internalKey)
|
|
751
|
+
keys.push(`k:${internalKey}`);
|
|
752
|
+
const attrKey = el.getAttribute("key");
|
|
753
|
+
if (attrKey)
|
|
754
|
+
keys.push(`k:${attrKey}`);
|
|
755
|
+
const id = el.id;
|
|
756
|
+
if (id)
|
|
757
|
+
keys.push(`id:${id}`);
|
|
758
|
+
return keys;
|
|
759
|
+
}
|
|
760
|
+
function areNodeAndChildMatching(domNode, child) {
|
|
761
|
+
if (typeof child === "string" || typeof child === "number" || typeof child === "boolean") {
|
|
762
|
+
return domNode.nodeType === 3;
|
|
763
|
+
}
|
|
764
|
+
if (child && typeof child === "object") {
|
|
765
|
+
if (domNode.nodeType !== 1)
|
|
766
|
+
return false;
|
|
767
|
+
const el = domNode;
|
|
768
|
+
const oldTag = el.tagName.toLowerCase();
|
|
769
|
+
const newTag = typeof child.type === "string" ? child.type.toLowerCase() : "";
|
|
770
|
+
if (!newTag || oldTag !== newTag)
|
|
771
|
+
return false;
|
|
772
|
+
return true;
|
|
773
|
+
}
|
|
774
|
+
return false;
|
|
775
|
+
}
|
|
776
|
+
function createDomFromChild(child, globals) {
|
|
777
|
+
const renderer = getRenderer(globals.window.document);
|
|
778
|
+
if (child == null)
|
|
779
|
+
return;
|
|
780
|
+
if (typeof child === "string" || typeof child === "number" || typeof child === "boolean") {
|
|
781
|
+
return [globals.window.document.createTextNode(String(child))];
|
|
782
|
+
}
|
|
783
|
+
const created = renderer.createElementOrElements(child);
|
|
784
|
+
if (!created)
|
|
785
|
+
return;
|
|
786
|
+
const nodes = Array.isArray(created) ? created : [created];
|
|
787
|
+
return nodes.filter(Boolean);
|
|
788
|
+
}
|
|
789
|
+
function shouldPreserveFormStateAttribute(el, attrName, vnode) {
|
|
790
|
+
const tag = el.tagName.toLowerCase();
|
|
791
|
+
const hasExplicit = Object.hasOwn(vnode.attributes ?? {}, attrName);
|
|
792
|
+
if (hasExplicit)
|
|
793
|
+
return false;
|
|
794
|
+
if (tag === "input")
|
|
795
|
+
return attrName === "value" || attrName === "checked";
|
|
796
|
+
if (tag === "textarea")
|
|
797
|
+
return attrName === "value";
|
|
798
|
+
if (tag === "select")
|
|
799
|
+
return attrName === "value";
|
|
800
|
+
return false;
|
|
801
|
+
}
|
|
802
|
+
function patchElementInPlace(el, vnode, globals, mergeAttributes = false) {
|
|
803
|
+
const renderer = getRenderer(globals.window.document);
|
|
804
|
+
const existingAttrs = mergeAttributes ? [] : Array.from(el.attributes);
|
|
805
|
+
const nextAttrs = vnode.attributes ?? {};
|
|
806
|
+
for (const attr of existingAttrs) {
|
|
807
|
+
const { name } = attr;
|
|
808
|
+
if (name === "key")
|
|
809
|
+
continue;
|
|
810
|
+
if (name.startsWith("on"))
|
|
811
|
+
continue;
|
|
812
|
+
if (name === "class" && (Object.hasOwn(nextAttrs, "class") || Object.hasOwn(nextAttrs, "className"))) {
|
|
813
|
+
continue;
|
|
814
|
+
}
|
|
815
|
+
if (!Object.hasOwn(nextAttrs, name)) {
|
|
816
|
+
if (shouldPreserveFormStateAttribute(el, name, vnode))
|
|
817
|
+
continue;
|
|
818
|
+
el.removeAttribute(name);
|
|
819
|
+
}
|
|
820
|
+
}
|
|
821
|
+
const preserveDelegatedHandlers = mergeAttributes || Boolean(nextAttrs[FROM_DOM_MARKER]);
|
|
822
|
+
if (!preserveDelegatedHandlers) {
|
|
823
|
+
const registeredKeys = getRegisteredEventKeys(el);
|
|
824
|
+
const nextEventKeys = new Set;
|
|
825
|
+
for (const propName of Object.keys(nextAttrs)) {
|
|
826
|
+
const parsed = parseEventPropName(propName);
|
|
827
|
+
if (parsed) {
|
|
828
|
+
const phase = parsed.capture ? "capture" : "bubble";
|
|
829
|
+
nextEventKeys.add(`${parsed.eventType}:${phase}`);
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
for (const key of registeredKeys) {
|
|
833
|
+
if (!nextEventKeys.has(key)) {
|
|
834
|
+
const [eventType, phase] = key.split(":");
|
|
835
|
+
removeDelegatedEventByKey(el, eventType, phase);
|
|
836
|
+
}
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
renderer.setAttributes(vnode, el);
|
|
840
|
+
handleLifecycleEventsForOnMount(el);
|
|
841
|
+
const d = vnode.attributes?.dangerouslySetInnerHTML;
|
|
842
|
+
if (d && typeof d === "object" && typeof d.__html === "string") {
|
|
843
|
+
el.innerHTML = d.__html;
|
|
844
|
+
return;
|
|
845
|
+
}
|
|
846
|
+
const tag = el.tagName.toLowerCase();
|
|
847
|
+
if (tag === "textarea") {
|
|
848
|
+
const isControlled = Object.hasOwn(nextAttrs, "value");
|
|
849
|
+
const isActive = el.ownerDocument?.activeElement === el;
|
|
850
|
+
if (isActive && !isControlled)
|
|
851
|
+
return;
|
|
852
|
+
}
|
|
853
|
+
if (mergeAttributes && (vnode.children === undefined || vnode.children.length === 0 && nextAttrs[FROM_DOM_MARKER]))
|
|
854
|
+
return;
|
|
855
|
+
morphDomDirect(el, vnode.children ?? [], globals);
|
|
856
|
+
}
|
|
857
|
+
function morphNode(domNode, child, globals, mergeAttributes = false) {
|
|
858
|
+
if (typeof child === "string" || typeof child === "number" || typeof child === "boolean") {
|
|
859
|
+
const text = String(child);
|
|
860
|
+
if (domNode.nodeType === 3) {
|
|
861
|
+
if (domNode.nodeValue !== text)
|
|
862
|
+
domNode.nodeValue = text;
|
|
863
|
+
return domNode;
|
|
864
|
+
}
|
|
865
|
+
const next = globals.window.document.createTextNode(text);
|
|
866
|
+
domNode.parentNode?.replaceChild(next, domNode);
|
|
867
|
+
return next;
|
|
868
|
+
}
|
|
869
|
+
if (child && typeof child === "object") {
|
|
870
|
+
const newType = typeof child.type === "string" ? child.type : null;
|
|
871
|
+
if (!newType)
|
|
872
|
+
return domNode;
|
|
873
|
+
if (domNode.nodeType !== 1) {
|
|
874
|
+
const created = createDomFromChild(child, globals);
|
|
875
|
+
const first = Array.isArray(created) ? created[0] : created;
|
|
876
|
+
if (!first)
|
|
877
|
+
return null;
|
|
878
|
+
domNode.parentNode?.replaceChild(first, domNode);
|
|
879
|
+
handleLifecycleEventsForOnMount(first);
|
|
880
|
+
return first;
|
|
881
|
+
}
|
|
882
|
+
const el = domNode;
|
|
883
|
+
const oldTag = el.tagName.toLowerCase();
|
|
884
|
+
const newTag = newType.toLowerCase();
|
|
885
|
+
if (oldTag !== newTag) {
|
|
886
|
+
const created = createDomFromChild(child, globals);
|
|
887
|
+
const first = Array.isArray(created) ? created[0] : created;
|
|
888
|
+
if (!first)
|
|
889
|
+
return null;
|
|
890
|
+
el.parentNode?.replaceChild(first, el);
|
|
891
|
+
handleLifecycleEventsForOnMount(first);
|
|
892
|
+
return first;
|
|
893
|
+
}
|
|
894
|
+
patchElementInPlace(el, child, globals, mergeAttributes);
|
|
895
|
+
return el;
|
|
896
|
+
}
|
|
897
|
+
domNode.parentNode?.removeChild(domNode);
|
|
898
|
+
return null;
|
|
899
|
+
}
|
|
900
|
+
var renderingNodes = new WeakSet;
|
|
901
|
+
var pendingMorphs = new Map;
|
|
902
|
+
var resolveGlobals = (el, globals) => {
|
|
903
|
+
if (globals)
|
|
904
|
+
return globals;
|
|
905
|
+
const win = el?.ownerDocument?.defaultView ?? globalThis;
|
|
906
|
+
return { window: win };
|
|
907
|
+
};
|
|
908
|
+
function isAncestorRendering(el) {
|
|
909
|
+
let current = el.parentElement;
|
|
910
|
+
while (current) {
|
|
911
|
+
if (renderingNodes.has(current))
|
|
912
|
+
return true;
|
|
913
|
+
current = current.parentElement;
|
|
914
|
+
}
|
|
915
|
+
return false;
|
|
916
|
+
}
|
|
917
|
+
function flushPendingMorphs() {
|
|
918
|
+
if (pendingMorphs.size === 0)
|
|
919
|
+
return;
|
|
920
|
+
const snapshot = [...pendingMorphs.entries()];
|
|
921
|
+
pendingMorphs.clear();
|
|
922
|
+
for (const [el, { vdom, globals, mode }] of snapshot) {
|
|
923
|
+
if (!el.isConnected)
|
|
924
|
+
continue;
|
|
925
|
+
updateDomWithVdom(el, vdom, globals, mode);
|
|
926
|
+
}
|
|
927
|
+
}
|
|
928
|
+
function updateDomWithVdom(parentElement, newVDOM, globals, mode = "replace") {
|
|
929
|
+
const resolvedGlobals = resolveGlobals(parentElement, globals);
|
|
930
|
+
if (renderingNodes.has(parentElement) || isAncestorRendering(parentElement)) {
|
|
931
|
+
pendingMorphs.set(parentElement, {
|
|
932
|
+
vdom: newVDOM,
|
|
933
|
+
globals: resolvedGlobals,
|
|
934
|
+
mode
|
|
935
|
+
});
|
|
936
|
+
return;
|
|
937
|
+
}
|
|
938
|
+
renderingNodes.add(parentElement);
|
|
939
|
+
try {
|
|
940
|
+
morphDomDirect(parentElement, newVDOM, resolvedGlobals, mode);
|
|
941
|
+
} finally {
|
|
942
|
+
renderingNodes.delete(parentElement);
|
|
943
|
+
}
|
|
944
|
+
flushPendingMorphs();
|
|
945
|
+
}
|
|
946
|
+
function morphDiff(targetRoot, patchItems, globals) {
|
|
947
|
+
const keyedPool = new Map;
|
|
948
|
+
for (const node of Array.from(targetRoot.childNodes)) {
|
|
949
|
+
for (const k of getDomMatchKeys(node)) {
|
|
950
|
+
if (!keyedPool.has(k))
|
|
951
|
+
keyedPool.set(k, node);
|
|
952
|
+
}
|
|
953
|
+
}
|
|
954
|
+
for (const item of patchItems) {
|
|
955
|
+
if (typeof item === "string" && item.trim() === "")
|
|
956
|
+
continue;
|
|
957
|
+
const key = getVNodeMatchKey(item);
|
|
958
|
+
if (!key) {
|
|
959
|
+
throw new Error(`morph diff: patch items must be elements with a key or id attribute (got ${describePatchItem(item)})`);
|
|
960
|
+
}
|
|
961
|
+
const match = keyedPool.get(key);
|
|
962
|
+
if (match) {
|
|
963
|
+
const patchItem = item && typeof item === "object" && !item.type ? { ...item, type: match.tagName.toLowerCase() } : item;
|
|
964
|
+
morphNode(match, patchItem, globals, true);
|
|
965
|
+
continue;
|
|
966
|
+
}
|
|
967
|
+
if (!item?.type) {
|
|
968
|
+
throw new Error(`morph diff: new (unmatched) patch items must declare a tag (type), got key/id "${key}"`);
|
|
969
|
+
}
|
|
970
|
+
const created = createDomFromChild(item, globals) ?? [];
|
|
971
|
+
for (const node of created) {
|
|
972
|
+
targetRoot.appendChild(node);
|
|
973
|
+
handleLifecycleEventsForOnMount(node);
|
|
974
|
+
}
|
|
975
|
+
}
|
|
976
|
+
}
|
|
977
|
+
function morphDomDirect(parentElement, newVDOM, globals, mode = "replace") {
|
|
978
|
+
const el = parentElement;
|
|
979
|
+
const isCustomElement = el.tagName.includes("-");
|
|
980
|
+
const targetRoot = el.shadowRoot && !isCustomElement ? el.shadowRoot : parentElement;
|
|
981
|
+
const nextChildren = normalizeChildren(newVDOM, mode === "diff");
|
|
982
|
+
if (mode === "diff") {
|
|
983
|
+
morphDiff(targetRoot, nextChildren, globals);
|
|
984
|
+
return;
|
|
985
|
+
}
|
|
986
|
+
const existing = Array.from(targetRoot.childNodes);
|
|
987
|
+
const keyedPool = new Map;
|
|
988
|
+
const nodeKeys = new WeakMap;
|
|
989
|
+
const unkeyedPool = [];
|
|
990
|
+
for (const node of existing) {
|
|
991
|
+
const keys = getDomMatchKeys(node);
|
|
992
|
+
if (keys.length > 0) {
|
|
993
|
+
nodeKeys.set(node, keys);
|
|
994
|
+
let addedToKeyedPool = false;
|
|
995
|
+
for (const k of keys) {
|
|
996
|
+
if (!keyedPool.has(k)) {
|
|
997
|
+
keyedPool.set(k, node);
|
|
998
|
+
addedToKeyedPool = true;
|
|
999
|
+
}
|
|
1000
|
+
}
|
|
1001
|
+
if (!addedToKeyedPool) {
|
|
1002
|
+
unkeyedPool.push(node);
|
|
1003
|
+
}
|
|
1004
|
+
} else {
|
|
1005
|
+
unkeyedPool.push(node);
|
|
1006
|
+
}
|
|
1007
|
+
}
|
|
1008
|
+
const consumeKeyedNode = (node) => {
|
|
1009
|
+
const keys = nodeKeys.get(node) ?? [];
|
|
1010
|
+
for (const k of keys)
|
|
1011
|
+
keyedPool.delete(k);
|
|
1012
|
+
};
|
|
1013
|
+
const takeUnkeyedMatch = (child) => {
|
|
1014
|
+
for (let i = 0;i < unkeyedPool.length; i++) {
|
|
1015
|
+
const candidate = unkeyedPool[i];
|
|
1016
|
+
if (areNodeAndChildMatching(candidate, child)) {
|
|
1017
|
+
unkeyedPool.splice(i, 1);
|
|
1018
|
+
return candidate;
|
|
1019
|
+
}
|
|
1020
|
+
}
|
|
1021
|
+
return;
|
|
1022
|
+
};
|
|
1023
|
+
let domIndex = 0;
|
|
1024
|
+
for (const child of nextChildren) {
|
|
1025
|
+
const key = getVNodeMatchKey(child);
|
|
1026
|
+
let match;
|
|
1027
|
+
if (key) {
|
|
1028
|
+
match = keyedPool.get(key);
|
|
1029
|
+
if (match)
|
|
1030
|
+
consumeKeyedNode(match);
|
|
1031
|
+
} else {
|
|
1032
|
+
match = takeUnkeyedMatch(child);
|
|
1033
|
+
}
|
|
1034
|
+
const anchor = targetRoot.childNodes[domIndex] ?? null;
|
|
1035
|
+
if (match) {
|
|
1036
|
+
if (match !== anchor) {
|
|
1037
|
+
targetRoot.insertBefore(match, anchor);
|
|
1038
|
+
}
|
|
1039
|
+
const morphed = morphNode(match, child, globals);
|
|
1040
|
+
if (morphed && morphed !== match) {}
|
|
1041
|
+
domIndex++;
|
|
1042
|
+
continue;
|
|
1043
|
+
}
|
|
1044
|
+
const created = createDomFromChild(child, globals);
|
|
1045
|
+
if (!created || Array.isArray(created) && created.length === 0)
|
|
1046
|
+
continue;
|
|
1047
|
+
const nodes = Array.isArray(created) ? created : [created];
|
|
1048
|
+
for (const node of nodes) {
|
|
1049
|
+
targetRoot.insertBefore(node, anchor);
|
|
1050
|
+
handleLifecycleEventsForOnMount(node);
|
|
1051
|
+
domIndex++;
|
|
1052
|
+
}
|
|
1053
|
+
}
|
|
1054
|
+
const remaining = new Set;
|
|
1055
|
+
for (const node of unkeyedPool)
|
|
1056
|
+
remaining.add(node);
|
|
1057
|
+
for (const node of keyedPool.values())
|
|
1058
|
+
remaining.add(node);
|
|
1059
|
+
for (const node of remaining) {
|
|
1060
|
+
if (node.parentNode === targetRoot) {
|
|
1061
|
+
if (node.nodeType === 1) {
|
|
1062
|
+
clearDelegatedEventsDeep(node);
|
|
1063
|
+
}
|
|
1064
|
+
targetRoot.removeChild(node);
|
|
1065
|
+
}
|
|
1066
|
+
}
|
|
1067
|
+
}
|
|
1068
|
+
function replaceDomWithVdom(parentElement, newVDOM, globals) {
|
|
1069
|
+
const resolvedGlobals = resolveGlobals(parentElement, globals);
|
|
1070
|
+
while (parentElement.firstChild) {
|
|
1071
|
+
parentElement.removeChild(parentElement.firstChild);
|
|
1072
|
+
}
|
|
1073
|
+
const renderer = getRenderer(resolvedGlobals.window.document);
|
|
1074
|
+
const newDom = renderer.createElementOrElements(newVDOM);
|
|
1075
|
+
if (Array.isArray(newDom)) {
|
|
1076
|
+
for (const node of newDom) {
|
|
1077
|
+
if (node) {
|
|
1078
|
+
parentElement.appendChild(node);
|
|
1079
|
+
handleLifecycleEventsForOnMount(node);
|
|
1080
|
+
}
|
|
1081
|
+
}
|
|
1082
|
+
} else if (newDom) {
|
|
1083
|
+
parentElement.appendChild(newDom);
|
|
1084
|
+
handleLifecycleEventsForOnMount(newDom);
|
|
1085
|
+
}
|
|
1086
|
+
}
|
|
1087
|
+
|
|
1088
|
+
// src/transitions.ts
|
|
1089
|
+
var injectShakeKeyframes = (doc) => {
|
|
1090
|
+
if (!doc)
|
|
1091
|
+
return;
|
|
1092
|
+
if (!doc.getElementById("defuss-shake")) {
|
|
1093
|
+
const style = doc.createElement("style");
|
|
1094
|
+
style.id = "defuss-shake";
|
|
1095
|
+
style.textContent = "@keyframes shake{0%,100%{transform:translate3d(0,0,0)}10%,30%,50%,70%,90%{transform:translate3d(-10px,0,0)}20%,40%,60%,80%{transform:translate3d(10px,0,0)}}";
|
|
1096
|
+
doc.head.appendChild(style);
|
|
1097
|
+
}
|
|
1098
|
+
};
|
|
1099
|
+
var getTransitionStyles = (type, duration, easing = "ease-in-out") => {
|
|
1100
|
+
const t = `transform ${duration}ms ${easing}, opacity ${duration}ms ${easing}`;
|
|
1101
|
+
const styles = {
|
|
1102
|
+
fade: {
|
|
1103
|
+
enter: { opacity: "0", transition: t, transform: "translate3d(0,0,0)" },
|
|
1104
|
+
enterActive: { opacity: "1" },
|
|
1105
|
+
exit: { opacity: "1", transition: t, transform: "translate3d(0,0,0)" },
|
|
1106
|
+
exitActive: { opacity: "0" }
|
|
1107
|
+
},
|
|
1108
|
+
"slide-left": {
|
|
1109
|
+
enter: {
|
|
1110
|
+
transform: "translate3d(100%,0,0)",
|
|
1111
|
+
opacity: "0.5",
|
|
1112
|
+
transition: t
|
|
1113
|
+
},
|
|
1114
|
+
enterActive: { transform: "translate3d(0,0,0)", opacity: "1" },
|
|
1115
|
+
exit: { transform: "translate3d(0,0,0)", opacity: "1", transition: t },
|
|
1116
|
+
exitActive: { transform: "translate3d(-100%,0,0)", opacity: "0.5" }
|
|
1117
|
+
},
|
|
1118
|
+
"slide-right": {
|
|
1119
|
+
enter: {
|
|
1120
|
+
transform: "translate3d(-100%,0,0)",
|
|
1121
|
+
opacity: "0.5",
|
|
1122
|
+
transition: t
|
|
1123
|
+
},
|
|
1124
|
+
enterActive: { transform: "translate3d(0,0,0)", opacity: "1" },
|
|
1125
|
+
exit: { transform: "translate3d(0,0,0)", opacity: "1", transition: t },
|
|
1126
|
+
exitActive: { transform: "translate3d(100%,0,0)", opacity: "0.5" }
|
|
1127
|
+
},
|
|
1128
|
+
shake: (() => {
|
|
1129
|
+
injectShakeKeyframes(typeof document !== "undefined" ? document : undefined);
|
|
1130
|
+
return {
|
|
1131
|
+
enter: {
|
|
1132
|
+
transform: "translate3d(0,0,0)",
|
|
1133
|
+
opacity: "1",
|
|
1134
|
+
transition: "none"
|
|
1135
|
+
},
|
|
1136
|
+
enterActive: {
|
|
1137
|
+
transform: "translate3d(0,0,0)",
|
|
1138
|
+
opacity: "1",
|
|
1139
|
+
animation: `shake ${duration}ms cubic-bezier(0.36,0.07,0.19,0.97)`
|
|
1140
|
+
},
|
|
1141
|
+
exit: {
|
|
1142
|
+
transform: "translate3d(0,0,0)",
|
|
1143
|
+
opacity: "1",
|
|
1144
|
+
transition: "none"
|
|
1145
|
+
},
|
|
1146
|
+
exitActive: {
|
|
1147
|
+
transform: "translate3d(0,0,0)",
|
|
1148
|
+
opacity: "1",
|
|
1149
|
+
animation: `shake ${duration}ms cubic-bezier(0.36,0.07,0.19,0.97)`
|
|
1150
|
+
}
|
|
1151
|
+
};
|
|
1152
|
+
})()
|
|
1153
|
+
};
|
|
1154
|
+
return styles[type] || { enter: {}, enterActive: {}, exit: {}, exitActive: {} };
|
|
1155
|
+
};
|
|
1156
|
+
var applyStyles = (el, styles) => Object.entries(styles).forEach(([k, v]) => el.style.setProperty(k, String(v)));
|
|
1157
|
+
var DEFAULT_TRANSITION_CONFIG = {
|
|
1158
|
+
type: "fade",
|
|
1159
|
+
duration: 300,
|
|
1160
|
+
easing: "ease-in-out",
|
|
1161
|
+
delay: 0,
|
|
1162
|
+
target: "parent"
|
|
1163
|
+
};
|
|
1164
|
+
var wait = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
1165
|
+
var performCrossfade = async (element, updateCallback, duration, easing) => {
|
|
1166
|
+
const originalStyle = element.style.cssText;
|
|
1167
|
+
const snapshot = element.cloneNode(true);
|
|
1168
|
+
const doc = element.ownerDocument;
|
|
1169
|
+
try {
|
|
1170
|
+
const rect = element.getBoundingClientRect();
|
|
1171
|
+
snapshot.style.cssText = `position:absolute;top:${rect.top}px;left:${rect.left}px;width:${rect.width}px;height:${rect.height}px;opacity:1;transition:opacity ${duration}ms ${easing};z-index:1000;`;
|
|
1172
|
+
element.style.opacity = "0";
|
|
1173
|
+
element.style.transition = `opacity ${duration}ms ${easing}`;
|
|
1174
|
+
doc.body.appendChild(snapshot);
|
|
1175
|
+
await updateCallback();
|
|
1176
|
+
element.offsetHeight;
|
|
1177
|
+
snapshot.style.opacity = "0";
|
|
1178
|
+
element.style.opacity = "1";
|
|
1179
|
+
await wait(duration);
|
|
1180
|
+
doc.body.removeChild(snapshot);
|
|
1181
|
+
} catch (error) {
|
|
1182
|
+
if (snapshot.parentElement)
|
|
1183
|
+
doc.body.removeChild(snapshot);
|
|
1184
|
+
throw error;
|
|
1185
|
+
} finally {
|
|
1186
|
+
element.style.cssText = originalStyle;
|
|
1187
|
+
}
|
|
1188
|
+
};
|
|
1189
|
+
var performTransition = async (element, updateCallback, config = {}) => {
|
|
1190
|
+
const {
|
|
1191
|
+
type = "fade",
|
|
1192
|
+
duration = 300,
|
|
1193
|
+
easing = "ease-in-out",
|
|
1194
|
+
delay = 0
|
|
1195
|
+
} = { ...DEFAULT_TRANSITION_CONFIG, ...config };
|
|
1196
|
+
if (type === "none") {
|
|
1197
|
+
await updateCallback();
|
|
1198
|
+
return;
|
|
1199
|
+
}
|
|
1200
|
+
if (delay > 0)
|
|
1201
|
+
await wait(delay);
|
|
1202
|
+
if (type === "fade") {
|
|
1203
|
+
await performCrossfade(element, updateCallback, duration, easing);
|
|
1204
|
+
return;
|
|
1205
|
+
}
|
|
1206
|
+
const styles = config.styles || getTransitionStyles(type, duration, easing);
|
|
1207
|
+
const originalTransition = element.style.transition;
|
|
1208
|
+
const originalAnimation = element.style.animation;
|
|
1209
|
+
try {
|
|
1210
|
+
if (type === "shake") {
|
|
1211
|
+
element.style.animation = "none";
|
|
1212
|
+
element.offsetHeight;
|
|
1213
|
+
}
|
|
1214
|
+
applyStyles(element, styles.exit);
|
|
1215
|
+
element.offsetHeight;
|
|
1216
|
+
applyStyles(element, styles.exitActive);
|
|
1217
|
+
await wait(duration);
|
|
1218
|
+
await updateCallback();
|
|
1219
|
+
applyStyles(element, styles.enter);
|
|
1220
|
+
element.offsetHeight;
|
|
1221
|
+
applyStyles(element, styles.enterActive);
|
|
1222
|
+
await wait(duration);
|
|
1223
|
+
element.style.transition = originalTransition;
|
|
1224
|
+
element.style.animation = originalAnimation;
|
|
1225
|
+
} catch (error) {
|
|
1226
|
+
element.style.transition = originalTransition;
|
|
1227
|
+
element.style.animation = originalAnimation;
|
|
1228
|
+
throw error;
|
|
1229
|
+
}
|
|
1230
|
+
};
|
|
1231
|
+
|
|
1232
|
+
// src/index.ts
|
|
1233
|
+
var inflightTransitions = new WeakMap;
|
|
1234
|
+
var morph2 = (el, newContent, options = {}) => {
|
|
1235
|
+
const globals = resolveGlobals(el);
|
|
1236
|
+
const win = globals.window;
|
|
1237
|
+
const mode = options.diff ? "diff" : "replace";
|
|
1238
|
+
const apply = (content) => updateDomWithVdom(el, typeof content === "string" ? htmlStringToVNodes(content, win.DOMParser) : content, globals, mode);
|
|
1239
|
+
const transition = options.transition;
|
|
1240
|
+
if (transition && transition.type !== "none") {
|
|
1241
|
+
const config = { ...DEFAULT_TRANSITION_CONFIG, ...transition };
|
|
1242
|
+
const transitionTarget = config.target === "self" ? el : el.parentElement;
|
|
1243
|
+
if (!transitionTarget) {
|
|
1244
|
+
apply(newContent);
|
|
1245
|
+
return;
|
|
1246
|
+
}
|
|
1247
|
+
const slot2 = { content: newContent };
|
|
1248
|
+
inflightTransitions.set(el, slot2);
|
|
1249
|
+
return performTransition(transitionTarget, async () => {
|
|
1250
|
+
if (inflightTransitions.get(el) === slot2)
|
|
1251
|
+
apply(slot2.content);
|
|
1252
|
+
}, config).finally(() => {
|
|
1253
|
+
if (inflightTransitions.get(el) === slot2)
|
|
1254
|
+
inflightTransitions.delete(el);
|
|
1255
|
+
});
|
|
1256
|
+
}
|
|
1257
|
+
const slot = inflightTransitions.get(el);
|
|
1258
|
+
if (slot)
|
|
1259
|
+
slot.content = newContent;
|
|
1260
|
+
apply(newContent);
|
|
1261
|
+
};
|
|
1262
|
+
|
|
1263
|
+
// src/global.ts
|
|
1264
|
+
if (typeof globalThis !== "undefined") {
|
|
1265
|
+
const g = globalThis;
|
|
1266
|
+
if (typeof g.df$ !== "object" || g.df$ === null) {
|
|
1267
|
+
g.df$ = {};
|
|
1268
|
+
}
|
|
1269
|
+
Object.assign(g.df$, exports_src);
|
|
1270
|
+
}
|
|
1271
|
+
export {
|
|
1272
|
+
updateDomWithVdom,
|
|
1273
|
+
resolveGlobals,
|
|
1274
|
+
replaceDomWithVdom,
|
|
1275
|
+
renderMarkup,
|
|
1276
|
+
removeDelegatedEventByKey,
|
|
1277
|
+
removeDelegatedEvent,
|
|
1278
|
+
registerDelegatedEvent,
|
|
1279
|
+
queueCallback,
|
|
1280
|
+
performTransition,
|
|
1281
|
+
parseEventPropName,
|
|
1282
|
+
parseDOM,
|
|
1283
|
+
observeUnmount,
|
|
1284
|
+
nsMap,
|
|
1285
|
+
morph2 as morph,
|
|
1286
|
+
isSVG,
|
|
1287
|
+
isMarkup,
|
|
1288
|
+
isHTML,
|
|
1289
|
+
htmlStringToVNodes,
|
|
1290
|
+
handleLifecycleEventsForOnMount,
|
|
1291
|
+
getTransitionStyles,
|
|
1292
|
+
getRenderer,
|
|
1293
|
+
getRegisteredEventTypes,
|
|
1294
|
+
getRegisteredEventKeys,
|
|
1295
|
+
getMimeType,
|
|
1296
|
+
domNodeToVNode,
|
|
1297
|
+
clearDelegatedEventsDeep,
|
|
1298
|
+
clearDelegatedEvents,
|
|
1299
|
+
areDomNodesEqual,
|
|
1300
|
+
applyStyles,
|
|
1301
|
+
XMLNS_ATTRIBUTE_NAME,
|
|
1302
|
+
XLINK_ATTRIBUTE_NAME,
|
|
1303
|
+
REF_ATTRIBUTE_NAME,
|
|
1304
|
+
FROM_DOM_MARKER,
|
|
1305
|
+
DEFAULT_TRANSITION_CONFIG,
|
|
1306
|
+
DANGEROUSLY_SET_INNER_HTML_ATTRIBUTE,
|
|
1307
|
+
CLASS_ATTRIBUTE_NAME,
|
|
1308
|
+
CAPTURE_ONLY_EVENTS
|
|
1309
|
+
};
|
|
1310
|
+
|
|
1311
|
+
//# debugId=6F130A0428D5249264756E2164756E21
|
|
1312
|
+
//# sourceMappingURL=all.js.map
|