@ryupold/vode 1.1.9 → 1.3.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/README.md +57 -3
- package/dist/vode.js +233 -112
- package/dist/vode.min.js +1 -1
- package/dist/vode.min.mjs +1 -1
- package/dist/vode.mjs +232 -116
- package/index.ts +5 -1
- package/package.json +4 -4
- package/src/merge-class.ts +62 -0
- package/src/state-context.ts +228 -0
- package/src/vode-tags.ts +204 -203
- package/src/vode.ts +154 -164
- package/tsconfig.json +1 -2
package/README.md
CHANGED
|
@@ -6,9 +6,9 @@
|
|
|
6
6
|
[](https://www.npmjs.com/package/@ryupold/vode)
|
|
7
7
|
[](./LICENSE)
|
|
8
8
|
|
|
9
|
-
A
|
|
9
|
+
A compact web framework for minimalist developers. Zero dependencies, no build step except for typescript compilation, and a simple virtual DOM implementation that is easy to understand and use. Autocompletion out of the box thanks to `lib.dom.d.ts`.
|
|
10
10
|
|
|
11
|
-
It
|
|
11
|
+
It brings a primitive building block to the table that gives flexibility in composition and makes refactoring easy. Usecases can be single page applications or isolated components with complex state.
|
|
12
12
|
|
|
13
13
|
## Usage
|
|
14
14
|
|
|
@@ -116,7 +116,7 @@ const state = createState({
|
|
|
116
116
|
|
|
117
117
|
type State = typeof state;
|
|
118
118
|
|
|
119
|
-
const appNode = document.getElementById('app')
|
|
119
|
+
const appNode = document.getElementById('app')!;
|
|
120
120
|
|
|
121
121
|
app<State>(appNode, state,
|
|
122
122
|
(s: State) => [DIV,
|
|
@@ -399,6 +399,17 @@ const ComponentEwww = (s) => {
|
|
|
399
399
|
|
|
400
400
|
return [DIV, s.loading ? [PROGRESS] : s.title];
|
|
401
401
|
}
|
|
402
|
+
|
|
403
|
+
// ✨ experimental view transitions support ✨
|
|
404
|
+
// patch with a render via view transition
|
|
405
|
+
s.patch([{}, (s) => {/*...*/}]); //all given patches will be part of a view transition
|
|
406
|
+
|
|
407
|
+
// empty array patches command to skip the current view transition
|
|
408
|
+
// and set the queued animated patches until now as current state with a sync patch
|
|
409
|
+
s.patch([]);
|
|
410
|
+
|
|
411
|
+
// skip current view transition and start this view transition instead
|
|
412
|
+
s.patch([[], { loading: true }]);
|
|
402
413
|
```
|
|
403
414
|
|
|
404
415
|
### memoization
|
|
@@ -452,6 +463,7 @@ import { tag, props, children, mergeClass, hydrate } from '@ryupold/vode';
|
|
|
452
463
|
// Merge class props intelligently
|
|
453
464
|
mergeClass('foo', ['baz', 'bar']); // -> 'foo bar baz'
|
|
454
465
|
mergeClass(['foo'], { bar: true, baz: false }); // -> 'foo bar'
|
|
466
|
+
mergeClass({zig: true, zag: false}, 'foo', ['baz', 'bar']); // -> 'zig foo bar baz'
|
|
455
467
|
|
|
456
468
|
const myVode = [DIV, { class: 'foo' }, [SPAN, 'hello'], [STRONG, 'world']];
|
|
457
469
|
|
|
@@ -473,6 +485,30 @@ Like the other events they can be patches too.
|
|
|
473
485
|
> is actually created/removed which might not always be the case during
|
|
474
486
|
> rendering, as only a diff of the virtual DOM is applied.
|
|
475
487
|
|
|
488
|
+
### SVG & MathML
|
|
489
|
+
SVG and MathML elements are supported but need the namespace defined in properties.
|
|
490
|
+
|
|
491
|
+
```typescript
|
|
492
|
+
import { SVG, CIRCLE } from '@ryupold/vode';
|
|
493
|
+
|
|
494
|
+
const CompSVG = (s) =>
|
|
495
|
+
[SVG, { xmlns: 'http://www.w3.org/2000/svg', width: 100, height: 100 },
|
|
496
|
+
[CIRCLE, { cx: 50, cy: 50, r: 40, stroke: 'green', 'stroke-width': 4, fill: 'yellow' }]
|
|
497
|
+
];
|
|
498
|
+
```
|
|
499
|
+
|
|
500
|
+
```typescript
|
|
501
|
+
import { MATH, MSUP, MI, MN } from '@ryupold/vode';
|
|
502
|
+
|
|
503
|
+
const CompMathML = (s) =>
|
|
504
|
+
[MATH, { xmlns: 'http://www.w3.org/1998/Math/MathML' },
|
|
505
|
+
[MSUP,
|
|
506
|
+
[MI, 'x'],
|
|
507
|
+
[MN, '2']
|
|
508
|
+
]
|
|
509
|
+
];
|
|
510
|
+
```
|
|
511
|
+
|
|
476
512
|
### advanced usage
|
|
477
513
|
|
|
478
514
|
#### isolated state
|
|
@@ -504,6 +540,24 @@ The memo with empty dependency array prevents further render calls from the oute
|
|
|
504
540
|
so rendering of the subtree inside is controlled by the inner app.
|
|
505
541
|
Take note of the fact that the top-level element of the inner app refers to the surrounding element and will change its state accordingly.
|
|
506
542
|
|
|
543
|
+
#### view transitions
|
|
544
|
+
The library has experimental support for [View Transitions API](https://developer.mozilla.org/en-US/docs/Web/API/View_Transition_API).
|
|
545
|
+
You can pass an array of patches to the `patch` function where each patch will be applied with the next available view transition.
|
|
546
|
+
|
|
547
|
+
Patching an empty array `[]` will skip the current view transition and set the queued animated patches until now as current state with a sync patch.
|
|
548
|
+
> Keep in mind that view transitions are not supported in all browsers yet and only one active transition can happen at a time. This feature may change significantly in the future, so do not rely on it heavily.
|
|
549
|
+
|
|
550
|
+
Scheduling behaviour can in theory be overridden with `containerNode._vode.asyncRenderer`.
|
|
551
|
+
|
|
552
|
+
```js
|
|
553
|
+
// or globally disable view transitions for the vode framework
|
|
554
|
+
import { globals } from '@ryupold/vode';
|
|
555
|
+
globals.startViewTransition = null;
|
|
556
|
+
|
|
557
|
+
// set to disable view transitions for specific vode-app
|
|
558
|
+
containerNode._vode.asyncRenderer = null;
|
|
559
|
+
```
|
|
560
|
+
|
|
507
561
|
### performance
|
|
508
562
|
|
|
509
563
|
There are some metrics available on the appNode.
|
package/dist/vode.js
CHANGED
|
@@ -61,6 +61,7 @@ var V = (() => {
|
|
|
61
61
|
DIV: () => DIV,
|
|
62
62
|
DL: () => DL,
|
|
63
63
|
DT: () => DT,
|
|
64
|
+
DelegateStateContext: () => DelegateStateContext,
|
|
64
65
|
ELLIPSE: () => ELLIPSE,
|
|
65
66
|
EM: () => EM,
|
|
66
67
|
EMBED: () => EMBED,
|
|
@@ -115,6 +116,7 @@ var V = (() => {
|
|
|
115
116
|
INPUT: () => INPUT,
|
|
116
117
|
INS: () => INS,
|
|
117
118
|
KBD: () => KBD,
|
|
119
|
+
KeyStateContext: () => KeyStateContext,
|
|
118
120
|
LABEL: () => LABEL,
|
|
119
121
|
LEGEND: () => LEGEND,
|
|
120
122
|
LI: () => LI,
|
|
@@ -182,6 +184,7 @@ var V = (() => {
|
|
|
182
184
|
S: () => S,
|
|
183
185
|
SAMP: () => SAMP,
|
|
184
186
|
SCRIPT: () => SCRIPT,
|
|
187
|
+
SEARCH: () => SEARCH,
|
|
185
188
|
SECTION: () => SECTION,
|
|
186
189
|
SELECT: () => SELECT,
|
|
187
190
|
SEMANTICS: () => SEMANTICS,
|
|
@@ -217,6 +220,7 @@ var V = (() => {
|
|
|
217
220
|
U: () => U,
|
|
218
221
|
UL: () => UL,
|
|
219
222
|
USE: () => USE,
|
|
223
|
+
VAR: () => VAR,
|
|
220
224
|
VIDEO: () => VIDEO,
|
|
221
225
|
VIEW: () => VIEW,
|
|
222
226
|
WBR: () => WBR,
|
|
@@ -227,6 +231,7 @@ var V = (() => {
|
|
|
227
231
|
childrenStart: () => childrenStart,
|
|
228
232
|
createPatch: () => createPatch,
|
|
229
233
|
createState: () => createState,
|
|
234
|
+
globals: () => globals,
|
|
230
235
|
hydrate: () => hydrate,
|
|
231
236
|
memo: () => memo,
|
|
232
237
|
mergeClass: () => mergeClass,
|
|
@@ -236,6 +241,11 @@ var V = (() => {
|
|
|
236
241
|
});
|
|
237
242
|
|
|
238
243
|
// src/vode.ts
|
|
244
|
+
var globals = {
|
|
245
|
+
currentViewTransition: void 0,
|
|
246
|
+
requestAnimationFrame: !!window.requestAnimationFrame ? window.requestAnimationFrame.bind(window) : ((cb) => cb()),
|
|
247
|
+
startViewTransition: !!document.startViewTransition ? document.startViewTransition.bind(document) : null
|
|
248
|
+
};
|
|
239
249
|
function vode(tag2, props2, ...children2) {
|
|
240
250
|
if (!tag2) throw new Error("first argument to vode() must be a tag name or a vode");
|
|
241
251
|
if (Array.isArray(tag2)) return tag2;
|
|
@@ -247,12 +257,16 @@ var V = (() => {
|
|
|
247
257
|
if (!state || typeof state !== "object") throw new Error("second argument to app() must be a state object");
|
|
248
258
|
if (typeof dom !== "function") throw new Error("third argument to app() must be a function that returns a vode");
|
|
249
259
|
const _vode = {};
|
|
250
|
-
_vode.
|
|
260
|
+
_vode.syncRenderer = globals.requestAnimationFrame;
|
|
261
|
+
_vode.asyncRenderer = globals.startViewTransition;
|
|
262
|
+
_vode.qSync = null;
|
|
263
|
+
_vode.qAsync = null;
|
|
264
|
+
_vode.stats = { lastSyncRenderTime: 0, lastAsyncRenderTime: 0, syncRenderCount: 0, asyncRenderCount: 0, liveEffectCount: 0, patchCount: 0, syncRenderPatchCount: 0, asyncRenderPatchCount: 0 };
|
|
251
265
|
Object.defineProperty(state, "patch", {
|
|
252
266
|
enumerable: false,
|
|
253
267
|
configurable: true,
|
|
254
268
|
writable: false,
|
|
255
|
-
value: async (action) => {
|
|
269
|
+
value: async (action, isAsync) => {
|
|
256
270
|
if (!action || typeof action !== "function" && typeof action !== "object") return;
|
|
257
271
|
_vode.stats.patchCount++;
|
|
258
272
|
if (action?.next) {
|
|
@@ -263,13 +277,13 @@ var V = (() => {
|
|
|
263
277
|
while (v.done === false) {
|
|
264
278
|
_vode.stats.liveEffectCount++;
|
|
265
279
|
try {
|
|
266
|
-
_vode.patch(v.value);
|
|
280
|
+
_vode.patch(v.value, isAsync);
|
|
267
281
|
v = await generator.next();
|
|
268
282
|
} finally {
|
|
269
283
|
_vode.stats.liveEffectCount--;
|
|
270
284
|
}
|
|
271
285
|
}
|
|
272
|
-
_vode.patch(v.value);
|
|
286
|
+
_vode.patch(v.value, isAsync);
|
|
273
287
|
} finally {
|
|
274
288
|
_vode.stats.liveEffectCount--;
|
|
275
289
|
}
|
|
@@ -277,57 +291,91 @@ var V = (() => {
|
|
|
277
291
|
_vode.stats.liveEffectCount++;
|
|
278
292
|
try {
|
|
279
293
|
const nextState = await action;
|
|
280
|
-
_vode.patch(nextState);
|
|
294
|
+
_vode.patch(nextState, isAsync);
|
|
281
295
|
} finally {
|
|
282
296
|
_vode.stats.liveEffectCount--;
|
|
283
297
|
}
|
|
284
298
|
} else if (Array.isArray(action)) {
|
|
285
|
-
if (
|
|
286
|
-
|
|
287
|
-
_vode.patch(
|
|
288
|
-
|
|
299
|
+
if (action.length > 0) {
|
|
300
|
+
for (const p of action) {
|
|
301
|
+
_vode.patch(p, !document.hidden && !!_vode.asyncRenderer);
|
|
302
|
+
}
|
|
289
303
|
} else {
|
|
290
|
-
_vode.
|
|
304
|
+
_vode.qSync = mergeState(_vode.qSync || {}, _vode.qAsync, false);
|
|
305
|
+
_vode.qAsync = null;
|
|
306
|
+
globals.currentViewTransition?.skipTransition();
|
|
307
|
+
_vode.stats.syncRenderPatchCount++;
|
|
308
|
+
_vode.renderSync();
|
|
291
309
|
}
|
|
292
310
|
} else if (typeof action === "function") {
|
|
293
|
-
_vode.patch(action(_vode.state));
|
|
311
|
+
_vode.patch(action(_vode.state), isAsync);
|
|
294
312
|
} else {
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
313
|
+
if (isAsync) {
|
|
314
|
+
_vode.stats.asyncRenderPatchCount++;
|
|
315
|
+
_vode.qAsync = mergeState(_vode.qAsync || {}, action, false);
|
|
316
|
+
await _vode.renderAsync();
|
|
317
|
+
} else {
|
|
318
|
+
_vode.stats.syncRenderPatchCount++;
|
|
319
|
+
_vode.qSync = mergeState(_vode.qSync || {}, action, false);
|
|
320
|
+
_vode.renderSync();
|
|
321
|
+
}
|
|
298
322
|
}
|
|
299
323
|
}
|
|
300
324
|
});
|
|
301
|
-
|
|
325
|
+
function renderDom(isAsync) {
|
|
326
|
+
const sw = Date.now();
|
|
327
|
+
const vom = dom(_vode.state);
|
|
328
|
+
_vode.vode = render(_vode.state, _vode.patch, container.parentElement, 0, _vode.vode, vom);
|
|
329
|
+
if (container.tagName.toUpperCase() !== vom[0].toUpperCase()) {
|
|
330
|
+
container = _vode.vode.node;
|
|
331
|
+
container._vode = _vode;
|
|
332
|
+
}
|
|
333
|
+
if (!isAsync) {
|
|
334
|
+
_vode.stats.lastSyncRenderTime = Date.now() - sw;
|
|
335
|
+
_vode.stats.syncRenderCount++;
|
|
336
|
+
_vode.isRendering = false;
|
|
337
|
+
if (_vode.qSync) _vode.renderSync();
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
const sr = renderDom.bind(null, false);
|
|
341
|
+
const ar = renderDom.bind(null, true);
|
|
342
|
+
Object.defineProperty(_vode, "renderSync", {
|
|
302
343
|
enumerable: false,
|
|
303
344
|
configurable: true,
|
|
304
345
|
writable: false,
|
|
305
|
-
value: () =>
|
|
306
|
-
if (_vode.isRendering || !_vode.
|
|
346
|
+
value: () => {
|
|
347
|
+
if (_vode.isRendering || !_vode.qSync) return;
|
|
307
348
|
_vode.isRendering = true;
|
|
349
|
+
_vode.state = mergeState(_vode.state, _vode.qSync, true);
|
|
350
|
+
_vode.qSync = null;
|
|
351
|
+
_vode.syncRenderer(sr);
|
|
352
|
+
}
|
|
353
|
+
});
|
|
354
|
+
Object.defineProperty(_vode, "renderAsync", {
|
|
355
|
+
enumerable: false,
|
|
356
|
+
configurable: true,
|
|
357
|
+
writable: false,
|
|
358
|
+
value: async () => {
|
|
359
|
+
if (_vode.isAnimating || !_vode.qAsync) return;
|
|
360
|
+
await globals.currentViewTransition?.updateCallbackDone;
|
|
361
|
+
if (_vode.isAnimating || !_vode.qAsync || document.hidden) return;
|
|
362
|
+
_vode.isAnimating = true;
|
|
308
363
|
const sw = Date.now();
|
|
309
364
|
try {
|
|
310
|
-
_vode.state = mergeState(_vode.state, _vode.
|
|
311
|
-
_vode.
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
if (container.tagName.toUpperCase() !== vom[0].toUpperCase()) {
|
|
315
|
-
container = _vode.vode.node;
|
|
316
|
-
container._vode = _vode;
|
|
317
|
-
}
|
|
365
|
+
_vode.state = mergeState(_vode.state, _vode.qAsync, true);
|
|
366
|
+
_vode.qAsync = null;
|
|
367
|
+
globals.currentViewTransition = _vode.asyncRenderer(ar);
|
|
368
|
+
await globals.currentViewTransition?.updateCallbackDone;
|
|
318
369
|
} finally {
|
|
319
|
-
_vode.
|
|
320
|
-
_vode.stats.
|
|
321
|
-
_vode.
|
|
322
|
-
if (_vode.q) {
|
|
323
|
-
_vode.render();
|
|
324
|
-
}
|
|
370
|
+
_vode.stats.lastAsyncRenderTime = Date.now() - sw;
|
|
371
|
+
_vode.stats.asyncRenderCount++;
|
|
372
|
+
_vode.isAnimating = false;
|
|
325
373
|
}
|
|
326
|
-
|
|
374
|
+
if (_vode.qAsync) _vode.renderAsync();
|
|
375
|
+
}
|
|
327
376
|
});
|
|
328
377
|
_vode.patch = state.patch;
|
|
329
378
|
_vode.state = state;
|
|
330
|
-
_vode.q = null;
|
|
331
379
|
const root = container;
|
|
332
380
|
root._vode = _vode;
|
|
333
381
|
_vode.vode = render(
|
|
@@ -402,47 +450,6 @@ var V = (() => {
|
|
|
402
450
|
}
|
|
403
451
|
return void 0;
|
|
404
452
|
}
|
|
405
|
-
function mergeClass(a, b) {
|
|
406
|
-
if (!a) return b;
|
|
407
|
-
if (!b) return a;
|
|
408
|
-
if (typeof a === "string" && typeof b === "string") {
|
|
409
|
-
const aSplit = a.split(" ");
|
|
410
|
-
const bSplit = b.split(" ");
|
|
411
|
-
const classSet = /* @__PURE__ */ new Set([...aSplit, ...bSplit]);
|
|
412
|
-
return Array.from(classSet).join(" ").trim();
|
|
413
|
-
} else if (typeof a === "string" && Array.isArray(b)) {
|
|
414
|
-
const classSet = /* @__PURE__ */ new Set([...b, ...a.split(" ")]);
|
|
415
|
-
return Array.from(classSet).join(" ").trim();
|
|
416
|
-
} else if (Array.isArray(a) && typeof b === "string") {
|
|
417
|
-
const classSet = /* @__PURE__ */ new Set([...a, ...b.split(" ")]);
|
|
418
|
-
return Array.from(classSet).join(" ").trim();
|
|
419
|
-
} else if (Array.isArray(a) && Array.isArray(b)) {
|
|
420
|
-
const classSet = /* @__PURE__ */ new Set([...a, ...b]);
|
|
421
|
-
return Array.from(classSet).join(" ").trim();
|
|
422
|
-
} else if (typeof a === "string" && typeof b === "object") {
|
|
423
|
-
return { [a]: true, ...b };
|
|
424
|
-
} else if (typeof a === "object" && typeof b === "string") {
|
|
425
|
-
return { ...a, [b]: true };
|
|
426
|
-
} else if (typeof a === "object" && typeof b === "object") {
|
|
427
|
-
return { ...a, ...b };
|
|
428
|
-
} else if (typeof a === "object" && Array.isArray(b)) {
|
|
429
|
-
const aa = { ...a };
|
|
430
|
-
for (const item of b) {
|
|
431
|
-
aa[item] = true;
|
|
432
|
-
}
|
|
433
|
-
return aa;
|
|
434
|
-
} else if (Array.isArray(a) && typeof b === "object") {
|
|
435
|
-
const aa = {};
|
|
436
|
-
for (const item of a) {
|
|
437
|
-
aa[item] = true;
|
|
438
|
-
}
|
|
439
|
-
for (const bKey of Object.keys(b)) {
|
|
440
|
-
aa[bKey] = b[bKey];
|
|
441
|
-
}
|
|
442
|
-
return aa;
|
|
443
|
-
}
|
|
444
|
-
throw new Error(`cannot merge classes of ${a} (${typeof a}) and ${b} (${typeof b})`);
|
|
445
|
-
}
|
|
446
453
|
function children(vode2) {
|
|
447
454
|
const start = childrenStart(vode2);
|
|
448
455
|
if (start > 0) {
|
|
@@ -490,7 +497,7 @@ var V = (() => {
|
|
|
490
497
|
}
|
|
491
498
|
return target;
|
|
492
499
|
}
|
|
493
|
-
function render(state, patch, parent, childIndex, oldVode, newVode,
|
|
500
|
+
function render(state, patch, parent, childIndex, oldVode, newVode, xmlns) {
|
|
494
501
|
newVode = remember(state, newVode, oldVode);
|
|
495
502
|
const isNoVode = !newVode || typeof newVode === "number" || typeof newVode === "boolean";
|
|
496
503
|
if (newVode === oldVode || !oldVode && isNoVode) {
|
|
@@ -534,15 +541,15 @@ var V = (() => {
|
|
|
534
541
|
return text;
|
|
535
542
|
}
|
|
536
543
|
if (isNode && (!oldNode || oldIsText || oldVode[0] !== newVode[0])) {
|
|
537
|
-
svg = svg || newVode[0] === "svg";
|
|
538
|
-
const newNode = svg ? document.createElementNS("http://www.w3.org/2000/svg", newVode[0]) : document.createElement(newVode[0]);
|
|
539
|
-
newVode.node = newNode;
|
|
540
544
|
const newvode = newVode;
|
|
541
545
|
if (1 in newvode) {
|
|
542
546
|
newvode[1] = remember(state, newvode[1], void 0);
|
|
543
547
|
}
|
|
544
548
|
const properties = props(newVode);
|
|
545
|
-
|
|
549
|
+
xmlns = properties?.xmlns || xmlns;
|
|
550
|
+
const newNode = xmlns ? document.createElementNS(xmlns, newVode[0]) : document.createElement(newVode[0]);
|
|
551
|
+
newVode.node = newNode;
|
|
552
|
+
patchProperties(state, patch, newNode, void 0, properties);
|
|
546
553
|
if (oldNode) {
|
|
547
554
|
oldNode.onUnmount && patch(oldNode.onUnmount(oldNode));
|
|
548
555
|
oldNode.replaceWith(newNode);
|
|
@@ -557,7 +564,7 @@ var V = (() => {
|
|
|
557
564
|
if (newChildren) {
|
|
558
565
|
for (let i = 0; i < newChildren.length; i++) {
|
|
559
566
|
const child2 = newChildren[i];
|
|
560
|
-
const attached = render(state, patch, newNode, i, void 0, child2,
|
|
567
|
+
const attached = render(state, patch, newNode, i, void 0, child2, xmlns);
|
|
561
568
|
newVode[properties ? i + 2 : i + 1] = attached;
|
|
562
569
|
}
|
|
563
570
|
}
|
|
@@ -565,7 +572,6 @@ var V = (() => {
|
|
|
565
572
|
return newVode;
|
|
566
573
|
}
|
|
567
574
|
if (!oldIsText && isNode && oldVode[0] === newVode[0]) {
|
|
568
|
-
svg = svg || newVode[0] === "svg";
|
|
569
575
|
newVode.node = oldNode;
|
|
570
576
|
const newvode = newVode;
|
|
571
577
|
const oldvode = oldVode;
|
|
@@ -575,12 +581,12 @@ var V = (() => {
|
|
|
575
581
|
newvode[1] = remember(state, newvode[1], oldvode[1]);
|
|
576
582
|
if (prev !== newvode[1]) {
|
|
577
583
|
const properties = props(newVode);
|
|
578
|
-
patchProperties(patch, oldNode, props(oldVode), properties
|
|
584
|
+
patchProperties(state, patch, oldNode, props(oldVode), properties);
|
|
579
585
|
hasProps = !!properties;
|
|
580
586
|
}
|
|
581
587
|
} else {
|
|
582
588
|
const properties = props(newVode);
|
|
583
|
-
patchProperties(patch, oldNode, props(oldVode), properties
|
|
589
|
+
patchProperties(state, patch, oldNode, props(oldVode), properties);
|
|
584
590
|
hasProps = !!properties;
|
|
585
591
|
}
|
|
586
592
|
const newKids = children(newVode);
|
|
@@ -589,7 +595,7 @@ var V = (() => {
|
|
|
589
595
|
for (let i = 0; i < newKids.length; i++) {
|
|
590
596
|
const child2 = newKids[i];
|
|
591
597
|
const oldChild = oldKids && oldKids[i];
|
|
592
|
-
const attached = render(state, patch, oldNode, i, oldChild, child2,
|
|
598
|
+
const attached = render(state, patch, oldNode, i, oldChild, child2, xmlns);
|
|
593
599
|
if (attached) {
|
|
594
600
|
newVode[hasProps ? i + 2 : i + 1] = attached;
|
|
595
601
|
}
|
|
@@ -645,15 +651,15 @@ var V = (() => {
|
|
|
645
651
|
return c;
|
|
646
652
|
}
|
|
647
653
|
}
|
|
648
|
-
function patchProperties(patch, node, oldProps, newProps
|
|
654
|
+
function patchProperties(s, patch, node, oldProps, newProps) {
|
|
649
655
|
if (!newProps && !oldProps) return;
|
|
650
656
|
if (oldProps) {
|
|
651
657
|
for (const key in oldProps) {
|
|
652
658
|
const oldValue = oldProps[key];
|
|
653
659
|
const newValue = newProps?.[key];
|
|
654
660
|
if (oldValue !== newValue) {
|
|
655
|
-
if (newProps) newProps[key] = patchProperty(patch, node, key, oldValue, newValue
|
|
656
|
-
else patchProperty(patch, node, key, oldValue, void 0
|
|
661
|
+
if (newProps) newProps[key] = patchProperty(s, patch, node, key, oldValue, newValue);
|
|
662
|
+
else patchProperty(s, patch, node, key, oldValue, void 0);
|
|
657
663
|
}
|
|
658
664
|
}
|
|
659
665
|
}
|
|
@@ -661,17 +667,17 @@ var V = (() => {
|
|
|
661
667
|
for (const key in newProps) {
|
|
662
668
|
if (!(key in oldProps)) {
|
|
663
669
|
const newValue = newProps[key];
|
|
664
|
-
newProps[key] = patchProperty(patch, node, key, void 0, newValue
|
|
670
|
+
newProps[key] = patchProperty(s, patch, node, key, void 0, newValue);
|
|
665
671
|
}
|
|
666
672
|
}
|
|
667
673
|
} else if (newProps) {
|
|
668
674
|
for (const key in newProps) {
|
|
669
675
|
const newValue = newProps[key];
|
|
670
|
-
newProps[key] = patchProperty(patch, node, key, void 0, newValue
|
|
676
|
+
newProps[key] = patchProperty(s, patch, node, key, void 0, newValue);
|
|
671
677
|
}
|
|
672
678
|
}
|
|
673
679
|
}
|
|
674
|
-
function patchProperty(patch, node, key, oldValue, newValue
|
|
680
|
+
function patchProperty(s, patch, node, key, oldValue, newValue) {
|
|
675
681
|
if (key === "style") {
|
|
676
682
|
if (!newValue) {
|
|
677
683
|
node.style.cssText = "";
|
|
@@ -691,35 +697,17 @@ var V = (() => {
|
|
|
691
697
|
}
|
|
692
698
|
}
|
|
693
699
|
} else if (key === "class") {
|
|
694
|
-
if (
|
|
695
|
-
|
|
696
|
-
const newClass = classString(newValue);
|
|
697
|
-
node.classList.value = newClass;
|
|
698
|
-
} else {
|
|
699
|
-
node.classList.value = "";
|
|
700
|
-
}
|
|
700
|
+
if (newValue) {
|
|
701
|
+
node.setAttribute("class", classString(newValue));
|
|
701
702
|
} else {
|
|
702
|
-
|
|
703
|
-
const newClass = classString(newValue);
|
|
704
|
-
node.className = newClass;
|
|
705
|
-
} else {
|
|
706
|
-
node.className = "";
|
|
707
|
-
}
|
|
703
|
+
node.removeAttribute("class");
|
|
708
704
|
}
|
|
709
705
|
} else if (key[0] === "o" && key[1] === "n") {
|
|
710
706
|
if (newValue) {
|
|
711
707
|
let eventHandler = null;
|
|
712
708
|
if (typeof newValue === "function") {
|
|
713
709
|
const action = newValue;
|
|
714
|
-
eventHandler = (evt) => patch(
|
|
715
|
-
} else if (Array.isArray(newValue)) {
|
|
716
|
-
const arr = newValue;
|
|
717
|
-
const action = newValue[0];
|
|
718
|
-
if (arr.length > 1) {
|
|
719
|
-
eventHandler = () => patch([action, ...arr.slice(1)]);
|
|
720
|
-
} else {
|
|
721
|
-
eventHandler = (evt) => patch([action, evt]);
|
|
722
|
-
}
|
|
710
|
+
eventHandler = (evt) => patch(action(s, evt));
|
|
723
711
|
} else if (typeof newValue === "object") {
|
|
724
712
|
eventHandler = () => patch(newValue);
|
|
725
713
|
}
|
|
@@ -829,6 +817,7 @@ var V = (() => {
|
|
|
829
817
|
var S = "s";
|
|
830
818
|
var SAMP = "samp";
|
|
831
819
|
var SCRIPT = "script";
|
|
820
|
+
var SEARCH = "search";
|
|
832
821
|
var SECTION = "section";
|
|
833
822
|
var SELECT = "select";
|
|
834
823
|
var SLOT = "slot";
|
|
@@ -854,6 +843,7 @@ var V = (() => {
|
|
|
854
843
|
var TRACK = "track";
|
|
855
844
|
var U = "u";
|
|
856
845
|
var UL = "ul";
|
|
846
|
+
var VAR = "var";
|
|
857
847
|
var VIDEO = "video";
|
|
858
848
|
var WBR = "wbr";
|
|
859
849
|
var ANIMATE = "animate";
|
|
@@ -945,5 +935,136 @@ var V = (() => {
|
|
|
945
935
|
var MUNDER = "munder";
|
|
946
936
|
var MUNDEROVER = "munderover";
|
|
947
937
|
var SEMANTICS = "semantics";
|
|
938
|
+
|
|
939
|
+
// src/merge-class.ts
|
|
940
|
+
function mergeClass(...classes) {
|
|
941
|
+
if (!classes || classes.length === 0) return null;
|
|
942
|
+
if (classes.length === 1) return classes[0];
|
|
943
|
+
let finalClass = classes[0];
|
|
944
|
+
for (let index = 1; index < classes.length; index++) {
|
|
945
|
+
const a = finalClass, b = classes[index];
|
|
946
|
+
if (!a) {
|
|
947
|
+
finalClass = b;
|
|
948
|
+
} else if (!b) {
|
|
949
|
+
continue;
|
|
950
|
+
} else if (typeof a === "string" && typeof b === "string") {
|
|
951
|
+
const aSplit = a.split(" ");
|
|
952
|
+
const bSplit = b.split(" ");
|
|
953
|
+
const classSet = /* @__PURE__ */ new Set([...aSplit, ...bSplit]);
|
|
954
|
+
finalClass = Array.from(classSet).join(" ").trim();
|
|
955
|
+
} else if (typeof a === "string" && Array.isArray(b)) {
|
|
956
|
+
const classSet = /* @__PURE__ */ new Set([...b, ...a.split(" ")]);
|
|
957
|
+
finalClass = Array.from(classSet).join(" ").trim();
|
|
958
|
+
} else if (Array.isArray(a) && typeof b === "string") {
|
|
959
|
+
const classSet = /* @__PURE__ */ new Set([...a, ...b.split(" ")]);
|
|
960
|
+
finalClass = Array.from(classSet).join(" ").trim();
|
|
961
|
+
} else if (Array.isArray(a) && Array.isArray(b)) {
|
|
962
|
+
const classSet = /* @__PURE__ */ new Set([...a, ...b]);
|
|
963
|
+
finalClass = Array.from(classSet).join(" ").trim();
|
|
964
|
+
} else if (typeof a === "string" && typeof b === "object") {
|
|
965
|
+
finalClass = { [a]: true, ...b };
|
|
966
|
+
} else if (typeof a === "object" && typeof b === "string") {
|
|
967
|
+
finalClass = { ...a, [b]: true };
|
|
968
|
+
} else if (typeof a === "object" && typeof b === "object") {
|
|
969
|
+
finalClass = { ...a, ...b };
|
|
970
|
+
} else if (typeof a === "object" && Array.isArray(b)) {
|
|
971
|
+
const aa = { ...a };
|
|
972
|
+
for (const item of b) {
|
|
973
|
+
aa[item] = true;
|
|
974
|
+
}
|
|
975
|
+
finalClass = aa;
|
|
976
|
+
} else if (Array.isArray(a) && typeof b === "object") {
|
|
977
|
+
const aa = {};
|
|
978
|
+
for (const item of a) {
|
|
979
|
+
aa[item] = true;
|
|
980
|
+
}
|
|
981
|
+
for (const bKey of Object.keys(b)) {
|
|
982
|
+
aa[bKey] = b[bKey];
|
|
983
|
+
}
|
|
984
|
+
finalClass = aa;
|
|
985
|
+
} else throw new Error(`cannot merge classes of ${a} (${typeof a}) and ${b} (${typeof b})`);
|
|
986
|
+
}
|
|
987
|
+
return finalClass;
|
|
988
|
+
}
|
|
989
|
+
|
|
990
|
+
// src/state-context.ts
|
|
991
|
+
var KeyStateContext = class {
|
|
992
|
+
constructor(state, path) {
|
|
993
|
+
this.state = state;
|
|
994
|
+
this.path = path;
|
|
995
|
+
this.keys = path.split(".");
|
|
996
|
+
}
|
|
997
|
+
keys;
|
|
998
|
+
get() {
|
|
999
|
+
const keys = this.keys;
|
|
1000
|
+
let raw = this.state ? this.state[keys[0]] : void 0;
|
|
1001
|
+
for (let i = 1; i < keys.length && !!raw; i++) {
|
|
1002
|
+
raw = raw[keys[i]];
|
|
1003
|
+
}
|
|
1004
|
+
return raw;
|
|
1005
|
+
}
|
|
1006
|
+
put(value) {
|
|
1007
|
+
this.putDeep(value, this.state);
|
|
1008
|
+
}
|
|
1009
|
+
patch(value) {
|
|
1010
|
+
if (Array.isArray(value)) {
|
|
1011
|
+
const animation = [];
|
|
1012
|
+
for (const v of value) {
|
|
1013
|
+
animation.push(this.createPatch(v));
|
|
1014
|
+
}
|
|
1015
|
+
this.state.patch(animation);
|
|
1016
|
+
}
|
|
1017
|
+
this.state.patch(this.createPatch(value));
|
|
1018
|
+
}
|
|
1019
|
+
/**
|
|
1020
|
+
* Creates a render-patch for the parent state by setting a nested sub-state value while creating necessary structure.
|
|
1021
|
+
*
|
|
1022
|
+
* @example
|
|
1023
|
+
* ```typescript
|
|
1024
|
+
* const ctx = new StateContext(state, 'user.profile.settings');
|
|
1025
|
+
* const patch = ctx.createPatch({ theme: 'light' });
|
|
1026
|
+
* // patch is { user: { profile: { settings: { theme: 'light' } } } }
|
|
1027
|
+
* ```
|
|
1028
|
+
*
|
|
1029
|
+
* @param value
|
|
1030
|
+
* @returns {{key-path}:{...: value}} render-patch for the parent state
|
|
1031
|
+
*/
|
|
1032
|
+
createPatch(value) {
|
|
1033
|
+
const renderPatch = {};
|
|
1034
|
+
this.putDeep(value, renderPatch);
|
|
1035
|
+
return renderPatch;
|
|
1036
|
+
}
|
|
1037
|
+
putDeep(value, target) {
|
|
1038
|
+
const keys = this.keys;
|
|
1039
|
+
if (keys.length > 1) {
|
|
1040
|
+
let i = 0;
|
|
1041
|
+
let raw = target[keys[i]];
|
|
1042
|
+
if (typeof raw !== "object" || raw === null) {
|
|
1043
|
+
target[keys[i]] = raw = {};
|
|
1044
|
+
}
|
|
1045
|
+
for (i = 1; i < keys.length - 1; i++) {
|
|
1046
|
+
const p = raw;
|
|
1047
|
+
raw = raw[keys[i]];
|
|
1048
|
+
if (typeof raw !== "object" || raw === null) {
|
|
1049
|
+
p[keys[i]] = raw = {};
|
|
1050
|
+
}
|
|
1051
|
+
}
|
|
1052
|
+
raw[keys[i]] = value;
|
|
1053
|
+
} else {
|
|
1054
|
+
if (typeof target[keys[0]] === "object" && typeof value === "object")
|
|
1055
|
+
Object.assign(target[keys[0]], value);
|
|
1056
|
+
else
|
|
1057
|
+
target[keys[0]] = value;
|
|
1058
|
+
}
|
|
1059
|
+
}
|
|
1060
|
+
};
|
|
1061
|
+
var DelegateStateContext = class {
|
|
1062
|
+
constructor(state, get, put, patch) {
|
|
1063
|
+
this.state = state;
|
|
1064
|
+
this.get = get;
|
|
1065
|
+
this.put = put;
|
|
1066
|
+
this.patch = patch;
|
|
1067
|
+
}
|
|
1068
|
+
};
|
|
948
1069
|
return __toCommonJS(index_exports);
|
|
949
1070
|
})();
|