@vertz/ui 0.2.20 → 0.2.22

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.
Files changed (35) hide show
  1. package/dist/shared/{chunk-4fwcwxn6.js → chunk-2qe6aqhb.js} +235 -1
  2. package/dist/shared/{chunk-mtsvrj9e.js → chunk-4cmt1ve8.js} +1 -1
  3. package/dist/shared/chunk-4xkw6h1s.js +73 -0
  4. package/dist/shared/{chunk-j5qtsm0b.js → chunk-67z8b0q8.js} +97 -21
  5. package/dist/shared/{chunk-fkbgbf3n.js → chunk-7g722pdh.js} +70 -12
  6. package/dist/shared/{chunk-6wd36w21.js → chunk-am9zaw4h.js} +3 -1
  7. package/dist/shared/{chunk-14eqne2a.js → chunk-bybgyjye.js} +1 -1
  8. package/dist/shared/{chunk-afawz764.js → chunk-c61572xp.js} +1 -1
  9. package/dist/shared/{chunk-07bh4m1e.js → chunk-kjwp5q5s.js} +10 -5
  10. package/dist/shared/chunk-mwc4v48d.js +36 -0
  11. package/dist/shared/{chunk-yjs76c7v.js → chunk-pdqr78k9.js} +1 -1
  12. package/dist/shared/{chunk-c3r237f0.js → chunk-pq8khh47.js} +32 -11
  13. package/dist/shared/{chunk-fs3eec4b.js → chunk-szk0hyjg.js} +3 -3
  14. package/dist/shared/chunk-vwz86vg9.js +208 -0
  15. package/dist/shared/{chunk-j09yyh34.js → chunk-yb4a0smw.js} +1 -1
  16. package/dist/src/auth/public.d.ts +30 -2
  17. package/dist/src/auth/public.js +95 -136
  18. package/dist/src/components/index.d.ts +70 -0
  19. package/dist/src/components/index.js +213 -0
  20. package/dist/src/css/public.d.ts +48 -14
  21. package/dist/src/css/public.js +4 -4
  22. package/dist/src/form/public.js +2 -2
  23. package/dist/src/index.d.ts +131 -20
  24. package/dist/src/index.js +45 -36
  25. package/dist/src/internals.d.ts +110 -62
  26. package/dist/src/internals.js +18 -14
  27. package/dist/src/jsx-runtime/index.d.ts +20 -0
  28. package/dist/src/jsx-runtime/index.js +13 -3
  29. package/dist/src/query/public.js +4 -4
  30. package/dist/src/router/public.d.ts +47 -1
  31. package/dist/src/router/public.js +10 -9
  32. package/dist/src/test/index.d.ts +33 -0
  33. package/dist/src/test/index.js +4 -4
  34. package/package.json +7 -3
  35. package/dist/shared/chunk-mgfrrrjq.js +0 -384
@@ -285,6 +285,223 @@ function batch(fn) {
285
285
  }
286
286
  }
287
287
 
288
+ // src/hydrate/hydration-context.ts
289
+ var isHydrating = false;
290
+ var currentNode = null;
291
+ var cursorStack = [];
292
+ var deferredEffects = null;
293
+ function queueDeferredEffect(run) {
294
+ if (!isHydrating || deferredEffects === null)
295
+ return false;
296
+ deferredEffects.push(run);
297
+ return true;
298
+ }
299
+ var hydrationRoot = null;
300
+ var claimedNodes = null;
301
+ function isDebug() {
302
+ if (typeof process !== "undefined" && true) {
303
+ return true;
304
+ }
305
+ return typeof globalThis !== "undefined" && globalThis.__VERTZ_HYDRATION_DEBUG__ === true;
306
+ }
307
+ function startHydration(root) {
308
+ if (isHydrating) {
309
+ throw new Error("[hydrate] startHydration() called while hydration is already active. " + "Concurrent hydration is not supported.");
310
+ }
311
+ isHydrating = true;
312
+ currentNode = root.firstChild;
313
+ cursorStack.length = 0;
314
+ deferredEffects = [];
315
+ if (isDebug()) {
316
+ hydrationRoot = root;
317
+ claimedNodes = new WeakSet;
318
+ }
319
+ }
320
+ function endHydration() {
321
+ if (isDebug()) {
322
+ if (currentNode) {
323
+ console.debug("[hydrate] Hydration ended with unclaimed nodes remaining. " + "This may indicate SSR/client tree mismatch or browser extension nodes.");
324
+ }
325
+ if (cursorStack.length > 0) {
326
+ console.debug(`[hydrate] Hydration ended with unbalanced cursor stack (depth: ${cursorStack.length}). ` + "Check that __enterChildren/__exitChildren calls are paired.");
327
+ }
328
+ }
329
+ if (hydrationRoot && claimedNodes) {
330
+ const unclaimed = findUnclaimedNodes(hydrationRoot, claimedNodes);
331
+ if (unclaimed.length > 0) {
332
+ console.warn(`[hydrate] ${unclaimed.length} SSR node(s) not claimed during hydration:
333
+ ` + unclaimed.map((n) => ` - ${describeNode(n)}`).join(`
334
+ `));
335
+ }
336
+ }
337
+ hydrationRoot = null;
338
+ claimedNodes = null;
339
+ isHydrating = false;
340
+ currentNode = null;
341
+ cursorStack.length = 0;
342
+ flushDeferredEffects();
343
+ }
344
+ function discardDeferredEffects() {
345
+ deferredEffects = null;
346
+ }
347
+ function flushDeferredEffects() {
348
+ const effects = deferredEffects;
349
+ deferredEffects = null;
350
+ if (effects) {
351
+ for (const run of effects) {
352
+ try {
353
+ run();
354
+ } catch (e) {
355
+ if (typeof process !== "undefined" && true) {
356
+ console.error("[hydrate] Deferred effect threw during flush:", e);
357
+ }
358
+ }
359
+ }
360
+ }
361
+ }
362
+ function getIsHydrating() {
363
+ return isHydrating;
364
+ }
365
+ function pauseHydration() {
366
+ isHydrating = false;
367
+ }
368
+ function resumeHydration() {
369
+ isHydrating = true;
370
+ }
371
+ function claimElement(tag) {
372
+ const upperTag = tag.toUpperCase();
373
+ const savedNode = currentNode;
374
+ while (currentNode) {
375
+ if (currentNode.nodeType === Node.ELEMENT_NODE) {
376
+ const el = currentNode;
377
+ if (el.tagName === upperTag) {
378
+ if (isDebug()) {
379
+ const id = el.id ? `#${el.id}` : "";
380
+ const cls = el.className ? `.${el.className.split(" ")[0]}` : "";
381
+ console.debug(`[hydrate] claimElement(<${tag}${id}${cls}>) ✓ depth=${cursorStack.length}`);
382
+ }
383
+ if (claimedNodes)
384
+ claimedNodes.add(el);
385
+ currentNode = el.nextSibling;
386
+ return el;
387
+ }
388
+ if (isDebug()) {
389
+ console.debug(`[hydrate] Skipping non-matching node: <${el.tagName.toLowerCase()}> (expected <${tag}>)`);
390
+ }
391
+ }
392
+ currentNode = currentNode.nextSibling;
393
+ }
394
+ currentNode = savedNode;
395
+ if (isDebug()) {
396
+ console.warn(`[hydrate] Expected <${tag}> but no matching SSR node found. Creating new element.`);
397
+ }
398
+ return null;
399
+ }
400
+ function claimText() {
401
+ const savedNode = currentNode;
402
+ while (currentNode) {
403
+ if (currentNode.nodeType === Node.TEXT_NODE) {
404
+ const text = currentNode;
405
+ if (isDebug()) {
406
+ const preview = text.data.length > 30 ? text.data.slice(0, 30) + "..." : text.data;
407
+ console.debug(`[hydrate] claimText("${preview}") ✓ depth=${cursorStack.length}`);
408
+ }
409
+ if (claimedNodes)
410
+ claimedNodes.add(text);
411
+ currentNode = text.nextSibling;
412
+ return text;
413
+ }
414
+ if (currentNode.nodeType === Node.ELEMENT_NODE) {
415
+ break;
416
+ }
417
+ currentNode = currentNode.nextSibling;
418
+ }
419
+ currentNode = savedNode;
420
+ if (isDebug()) {
421
+ console.warn("[hydrate] Expected text node but no matching SSR node found.");
422
+ }
423
+ return null;
424
+ }
425
+ function claimComment() {
426
+ const savedNode = currentNode;
427
+ while (currentNode) {
428
+ if (currentNode.nodeType === Node.COMMENT_NODE) {
429
+ const comment = currentNode;
430
+ if (claimedNodes)
431
+ claimedNodes.add(comment);
432
+ currentNode = comment.nextSibling;
433
+ return comment;
434
+ }
435
+ currentNode = currentNode.nextSibling;
436
+ }
437
+ currentNode = savedNode;
438
+ if (isDebug()) {
439
+ console.warn("[hydrate] Expected comment node but no matching SSR node found.");
440
+ }
441
+ return null;
442
+ }
443
+ function enterChildren(el) {
444
+ cursorStack.push(currentNode);
445
+ currentNode = el.firstChild;
446
+ }
447
+ function exitChildren() {
448
+ if (cursorStack.length === 0) {
449
+ if (isDebug()) {
450
+ console.warn("[hydrate] exitChildren() called with empty stack. " + "This likely means __exitChildren was called without a matching __enterChildren.");
451
+ }
452
+ currentNode = null;
453
+ return;
454
+ }
455
+ currentNode = cursorStack.pop() ?? null;
456
+ }
457
+ function findUnclaimedNodes(root, claimed) {
458
+ const unclaimed = [];
459
+ function walk(node) {
460
+ let child = node.firstChild;
461
+ while (child) {
462
+ if (child.nodeType === Node.ELEMENT_NODE) {
463
+ const el = child;
464
+ if (el.tagName.includes("-")) {
465
+ child = child.nextSibling;
466
+ continue;
467
+ }
468
+ }
469
+ if (child.nodeType === Node.ELEMENT_NODE && claimed.has(child) && child.tagName === "SPAN" && child.style.display === "contents") {
470
+ child = child.nextSibling;
471
+ continue;
472
+ }
473
+ if (!claimed.has(child)) {
474
+ if (child.nodeType === Node.ELEMENT_NODE || child.nodeType === Node.TEXT_NODE || child.nodeType === Node.COMMENT_NODE) {
475
+ unclaimed.push(child);
476
+ }
477
+ }
478
+ if (child.nodeType === Node.ELEMENT_NODE) {
479
+ walk(child);
480
+ }
481
+ child = child.nextSibling;
482
+ }
483
+ }
484
+ walk(root);
485
+ return unclaimed;
486
+ }
487
+ function describeNode(node) {
488
+ if (node.nodeType === Node.ELEMENT_NODE) {
489
+ const el = node;
490
+ const id = el.id ? `#${el.id}` : "";
491
+ const cls = el.className ? `.${String(el.className).split(" ")[0]}` : "";
492
+ return `<${el.tagName.toLowerCase()}${id}${cls}>`;
493
+ }
494
+ if (node.nodeType === Node.TEXT_NODE) {
495
+ const data = node.data;
496
+ const preview = data.length > 20 ? data.slice(0, 20) + "..." : data;
497
+ return `text("${preview}")`;
498
+ }
499
+ if (node.nodeType === Node.COMMENT_NODE) {
500
+ return `<!-- ${node.data} -->`;
501
+ }
502
+ return `[node type=${node.nodeType}]`;
503
+ }
504
+
288
505
  // src/runtime/signal.ts
289
506
  function isSSR() {
290
507
  return getSSRContext() !== undefined;
@@ -471,6 +688,23 @@ function domEffect(fn) {
471
688
  _tryOnCleanup(dispose);
472
689
  return dispose;
473
690
  }
691
+ function deferredDomEffect(fn) {
692
+ if (isSSR()) {
693
+ fn();
694
+ return () => {};
695
+ }
696
+ const eff = new EffectImpl(fn);
697
+ const deferred = queueDeferredEffect(() => {
698
+ if (!eff._disposed)
699
+ eff._run();
700
+ });
701
+ if (!deferred) {
702
+ eff._run();
703
+ }
704
+ const dispose = () => eff._dispose();
705
+ _tryOnCleanup(dispose);
706
+ return dispose;
707
+ }
474
708
  function lifecycleEffect(fn) {
475
709
  if (isSSR()) {
476
710
  return () => {};
@@ -482,4 +716,4 @@ function lifecycleEffect(fn) {
482
716
  return dispose;
483
717
  }
484
718
 
485
- export { registerSSRResolver, getSSRContext, hasSSRResolver, createContext, useContext, getContextScope, setContextScope, DisposalScopeError, onCleanup, _tryOnCleanup, pushScope, popScope, runCleanups, setReadValueCallback, untrack, batch, startSignalCollection, stopSignalCollection, signal, computed, domEffect, lifecycleEffect };
719
+ export { registerSSRResolver, getSSRContext, hasSSRResolver, createContext, useContext, getContextScope, setContextScope, DisposalScopeError, onCleanup, _tryOnCleanup, pushScope, popScope, runCleanups, setReadValueCallback, untrack, startHydration, endHydration, discardDeferredEffects, getIsHydrating, pauseHydration, resumeHydration, claimElement, claimText, claimComment, enterChildren, exitChildren, batch, startSignalCollection, stopSignalCollection, signal, computed, domEffect, deferredDomEffect, lifecycleEffect };
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  createContext,
3
3
  useContext
4
- } from "./chunk-4fwcwxn6.js";
4
+ } from "./chunk-2qe6aqhb.js";
5
5
 
6
6
  // src/router/router-context.ts
7
7
  var RouterContext = createContext(undefined, "@vertz/ui::RouterContext");
@@ -0,0 +1,73 @@
1
+ // src/dom/style.ts
2
+ function camelToKebab(prop) {
3
+ const third = prop[2];
4
+ if (prop.startsWith("ms") && third !== undefined && third >= "A" && third <= "Z") {
5
+ prop = `Ms${prop.slice(2)}`;
6
+ }
7
+ return prop.replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`);
8
+ }
9
+ var UNITLESS = new Set([
10
+ "animationIterationCount",
11
+ "aspectRatio",
12
+ "borderImageOutset",
13
+ "borderImageSlice",
14
+ "borderImageWidth",
15
+ "boxFlex",
16
+ "boxFlexGroup",
17
+ "boxOrdinalGroup",
18
+ "columnCount",
19
+ "columns",
20
+ "flex",
21
+ "flexGrow",
22
+ "flexPositive",
23
+ "flexShrink",
24
+ "flexNegative",
25
+ "flexOrder",
26
+ "gridArea",
27
+ "gridRow",
28
+ "gridRowEnd",
29
+ "gridRowSpan",
30
+ "gridRowStart",
31
+ "gridColumn",
32
+ "gridColumnEnd",
33
+ "gridColumnSpan",
34
+ "gridColumnStart",
35
+ "fontWeight",
36
+ "lineClamp",
37
+ "lineHeight",
38
+ "opacity",
39
+ "order",
40
+ "orphans",
41
+ "tabSize",
42
+ "widows",
43
+ "zIndex",
44
+ "zoom",
45
+ "fillOpacity",
46
+ "floodOpacity",
47
+ "stopOpacity",
48
+ "strokeDasharray",
49
+ "strokeDashoffset",
50
+ "strokeMiterlimit",
51
+ "strokeOpacity",
52
+ "strokeWidth",
53
+ "scale"
54
+ ]);
55
+ function formatValue(key, value) {
56
+ if (typeof value !== "number" || value === 0 || key.startsWith("--") || UNITLESS.has(key)) {
57
+ return String(value);
58
+ }
59
+ return `${value}px`;
60
+ }
61
+ function styleObjectToString(style) {
62
+ const parts = [];
63
+ for (const key of Object.keys(style)) {
64
+ const value = style[key];
65
+ if (value == null)
66
+ continue;
67
+ const cssKey = key.startsWith("--") ? key : camelToKebab(key);
68
+ parts.push(`${cssKey}: ${formatValue(key, value)}`);
69
+ }
70
+ return parts.join("; ");
71
+ }
72
+
73
+ export { styleObjectToString };
@@ -1,33 +1,35 @@
1
1
  import {
2
2
  __classList,
3
3
  __on
4
- } from "./chunk-07bh4m1e.js";
4
+ } from "./chunk-kjwp5q5s.js";
5
5
  import {
6
6
  __append,
7
7
  __element,
8
8
  __enterChildren,
9
9
  __exitChildren,
10
- __staticText,
11
- getIsHydrating
12
- } from "./chunk-mgfrrrjq.js";
10
+ __staticText
11
+ } from "./chunk-vwz86vg9.js";
13
12
  import {
14
13
  RouterContext
15
- } from "./chunk-mtsvrj9e.js";
14
+ } from "./chunk-4cmt1ve8.js";
16
15
  import {
17
16
  isBrowser
18
- } from "./chunk-14eqne2a.js";
17
+ } from "./chunk-bybgyjye.js";
19
18
  import {
20
19
  _tryOnCleanup,
21
20
  createContext,
22
21
  domEffect,
22
+ endHydration,
23
+ getIsHydrating,
23
24
  getSSRContext,
24
25
  popScope,
25
26
  pushScope,
26
27
  runCleanups,
27
28
  signal,
29
+ startHydration,
28
30
  untrack,
29
31
  useContext
30
- } from "./chunk-4fwcwxn6.js";
32
+ } from "./chunk-2qe6aqhb.js";
31
33
 
32
34
  // src/router/link.ts
33
35
  var DANGEROUS_SCHEMES = ["javascript:", "data:", "vbscript:"];
@@ -46,6 +48,7 @@ function createLink(currentPath, navigate, factoryOptions) {
46
48
  href,
47
49
  children,
48
50
  activeClass,
51
+ class: classProp,
49
52
  className,
50
53
  prefetch
51
54
  }) {
@@ -58,9 +61,10 @@ function createLink(currentPath, navigate, factoryOptions) {
58
61
  mouseEvent.preventDefault();
59
62
  navigate(safeHref);
60
63
  };
64
+ const effectiveClass = className ?? classProp;
61
65
  const props = { href: safeHref };
62
- if (className) {
63
- props.class = className;
66
+ if (effectiveClass) {
67
+ props.class = effectiveClass;
64
68
  }
65
69
  const el = __element("a", props);
66
70
  __on(el, "click", handleClick);
@@ -97,7 +101,13 @@ function createLink(currentPath, navigate, factoryOptions) {
97
101
  return el;
98
102
  };
99
103
  }
100
- function Link({ href, children, activeClass, className }) {
104
+ function Link({
105
+ href,
106
+ children,
107
+ activeClass,
108
+ class: classProp,
109
+ className
110
+ }) {
101
111
  const router = useContext(RouterContext);
102
112
  if (!router) {
103
113
  throw new Error("Link must be used within a RouterContext.Provider (via createRouter)");
@@ -111,9 +121,10 @@ function Link({ href, children, activeClass, className }) {
111
121
  mouseEvent.preventDefault();
112
122
  router.navigate({ to: safeHref });
113
123
  };
124
+ const effectiveClass = className ?? classProp;
114
125
  const props = { href: safeHref };
115
- if (className) {
116
- props.class = className;
126
+ if (effectiveClass) {
127
+ props.class = effectiveClass;
117
128
  }
118
129
  const el = __element("a", props);
119
130
  __on(el, "click", handleClick);
@@ -160,6 +171,7 @@ function Outlet() {
160
171
  const factory = ctx.childComponent;
161
172
  untrack(() => {
162
173
  runCleanups(childCleanups);
174
+ const wasHydrating = isFirstHydrationRender;
163
175
  if (isFirstHydrationRender) {
164
176
  isFirstHydrationRender = false;
165
177
  } else {
@@ -177,15 +189,43 @@ function Outlet() {
177
189
  result.then((mod) => {
178
190
  if (gen !== renderGen)
179
191
  return;
192
+ let node;
180
193
  childCleanups = pushScope();
181
- RouterContext.Provider(router, () => {
182
- const node = mod.default();
183
- __append(container, node);
184
- });
194
+ if (wasHydrating) {
195
+ startHydration(container);
196
+ try {
197
+ RouterContext.Provider(router, () => {
198
+ node = mod.default();
199
+ __append(container, node);
200
+ });
201
+ } finally {
202
+ endHydration();
203
+ }
204
+ if (!container.contains(node)) {
205
+ while (container.firstChild) {
206
+ container.removeChild(container.firstChild);
207
+ }
208
+ container.appendChild(node);
209
+ }
210
+ } else {
211
+ while (container.firstChild) {
212
+ container.removeChild(container.firstChild);
213
+ }
214
+ RouterContext.Provider(router, () => {
215
+ node = mod.default();
216
+ __append(container, node);
217
+ });
218
+ }
185
219
  popScope();
186
220
  });
187
221
  } else {
188
222
  __append(container, result);
223
+ if (getIsHydrating() && !container.contains(result)) {
224
+ while (container.firstChild) {
225
+ container.removeChild(container.firstChild);
226
+ }
227
+ container.appendChild(result);
228
+ }
189
229
  popScope();
190
230
  }
191
231
  } else {
@@ -235,6 +275,7 @@ function RouterView({ router, fallback }) {
235
275
  }
236
276
  runCleanups(pageCleanups);
237
277
  const doRender = () => {
278
+ const wasHydrating = isFirstHydrationRender;
238
279
  if (!isFirstHydrationRender) {
239
280
  while (container.firstChild) {
240
281
  container.removeChild(container.firstChild);
@@ -252,23 +293,58 @@ function RouterView({ router, fallback }) {
252
293
  }
253
294
  const levels = buildLevels(newMatched);
254
295
  const rootFactory = buildInsideOutFactory(newMatched, levels, 0, router);
296
+ let asyncRoute = false;
255
297
  RouterContext.Provider(router, () => {
256
298
  const result = rootFactory();
257
299
  if (result instanceof Promise) {
300
+ asyncRoute = true;
301
+ popScope();
258
302
  result.then((mod) => {
259
303
  if (gen !== renderGen)
260
304
  return;
261
- RouterContext.Provider(router, () => {
262
- const node = mod.default();
263
- container.appendChild(node);
264
- });
305
+ let node;
306
+ pageCleanups = pushScope();
307
+ if (wasHydrating) {
308
+ startHydration(container);
309
+ try {
310
+ RouterContext.Provider(router, () => {
311
+ node = mod.default();
312
+ __append(container, node);
313
+ });
314
+ } finally {
315
+ endHydration();
316
+ }
317
+ if (!container.contains(node)) {
318
+ while (container.firstChild) {
319
+ container.removeChild(container.firstChild);
320
+ }
321
+ container.appendChild(node);
322
+ }
323
+ } else {
324
+ while (container.firstChild) {
325
+ container.removeChild(container.firstChild);
326
+ }
327
+ RouterContext.Provider(router, () => {
328
+ node = mod.default();
329
+ container.appendChild(node);
330
+ });
331
+ }
332
+ popScope();
265
333
  });
266
334
  } else {
267
335
  __append(container, result);
336
+ if (getIsHydrating() && !container.contains(result)) {
337
+ while (container.firstChild) {
338
+ container.removeChild(container.firstChild);
339
+ }
340
+ container.appendChild(result);
341
+ }
268
342
  }
269
343
  });
270
344
  prevLevels = levels;
271
- popScope();
345
+ if (!asyncRoute) {
346
+ popScope();
347
+ }
272
348
  };
273
349
  doRender();
274
350
  });
@@ -1,17 +1,54 @@
1
1
  import {
2
2
  executeLoaders,
3
3
  matchRoute
4
- } from "./chunk-6wd36w21.js";
4
+ } from "./chunk-am9zaw4h.js";
5
5
  import {
6
6
  prefetchNavData
7
7
  } from "./chunk-jrtrk5z4.js";
8
8
  import {
9
9
  isBrowser
10
- } from "./chunk-14eqne2a.js";
10
+ } from "./chunk-bybgyjye.js";
11
11
  import {
12
12
  getSSRContext,
13
13
  signal
14
- } from "./chunk-4fwcwxn6.js";
14
+ } from "./chunk-2qe6aqhb.js";
15
+
16
+ // src/router/view-transitions.ts
17
+ var transitionGen = 0;
18
+ async function withViewTransition(update, config) {
19
+ if (config === undefined || config === false) {
20
+ await update();
21
+ return;
22
+ }
23
+ if (typeof document === "undefined" || !("startViewTransition" in document)) {
24
+ await update();
25
+ return;
26
+ }
27
+ if (typeof window !== "undefined" && window.matchMedia("(prefers-reduced-motion: reduce)").matches) {
28
+ await update();
29
+ return;
30
+ }
31
+ const className = typeof config === "object" && config.className ? config.className : undefined;
32
+ const gen = ++transitionGen;
33
+ if (className) {
34
+ document.documentElement.classList.add(className);
35
+ }
36
+ const transition = document.startViewTransition.call(document, async () => {
37
+ await update();
38
+ });
39
+ try {
40
+ await transition.finished;
41
+ } catch (err) {
42
+ if (err instanceof DOMException && err.name === "AbortError") {
43
+ return;
44
+ }
45
+ throw err;
46
+ } finally {
47
+ if (className && gen === transitionGen) {
48
+ document.documentElement.classList.remove(className);
49
+ }
50
+ }
51
+ }
15
52
 
16
53
  // src/router/navigate.ts
17
54
  var DEFAULT_NAV_THRESHOLD_MS = 500;
@@ -71,6 +108,19 @@ function createRouter(routes, initialUrlOrOptions, maybeOptions) {
71
108
  if (!ctx.discoveredRoutes) {
72
109
  ctx.discoveredRoutes = collectRoutePatterns(routes);
73
110
  }
111
+ }, matchForSSR = function(ctx) {
112
+ registerRoutesForDiscovery(ctx);
113
+ const m = matchRoute(routes, ctx.url);
114
+ if (m && !ctx.matchedRoutePatterns) {
115
+ const fullPaths = [];
116
+ let prefix = "";
117
+ for (const entry of m.matched) {
118
+ prefix = joinPatterns(prefix, entry.route.pattern);
119
+ fullPaths.push(prefix);
120
+ }
121
+ ctx.matchedRoutePatterns = fullPaths;
122
+ }
123
+ return m;
74
124
  };
75
125
  const ssrUrl = initialUrl ?? ssrCtx?.url ?? "/";
76
126
  const fallbackMatch = matchRoute(routes, ssrUrl);
@@ -79,16 +129,14 @@ function createRouter(routes, initialUrlOrOptions, maybeOptions) {
79
129
  get value() {
80
130
  const ctx = getSSRContext();
81
131
  if (ctx) {
82
- registerRoutesForDiscovery(ctx);
83
- return matchRoute(routes, ctx.url);
132
+ return matchForSSR(ctx);
84
133
  }
85
134
  return fallbackMatch;
86
135
  },
87
136
  peek() {
88
137
  const ctx = getSSRContext();
89
138
  if (ctx) {
90
- registerRoutesForDiscovery(ctx);
91
- return matchRoute(routes, ctx.url);
139
+ return matchForSSR(ctx);
92
140
  }
93
141
  return fallbackMatch;
94
142
  },
@@ -242,15 +290,21 @@ function createRouter(routes, initialUrlOrOptions, maybeOptions) {
242
290
  }
243
291
  }
244
292
  }
245
- async function applyNavigation(url2) {
293
+ async function applyNavigation(url2, preMatch, transitionConfig) {
246
294
  if (currentAbort) {
247
295
  currentAbort.abort();
248
296
  }
249
297
  const gen = ++navigationGen;
250
298
  const abort = new AbortController;
251
299
  currentAbort = abort;
252
- const match = matchRoute(routes, url2);
253
- current.value = match;
300
+ const match = preMatch !== undefined ? preMatch : matchRoute(routes, url2);
301
+ if (transitionConfig) {
302
+ await withViewTransition(() => {
303
+ current.value = match;
304
+ }, transitionConfig);
305
+ } else {
306
+ current.value = match;
307
+ }
254
308
  if (match) {
255
309
  visitedUrls.add(normalizeUrl(url2));
256
310
  searchParams.value = match.search;
@@ -278,7 +332,9 @@ function createRouter(routes, initialUrlOrOptions, maybeOptions) {
278
332
  }
279
333
  if (gen !== navigateGen)
280
334
  return;
281
- await applyNavigation(navUrl);
335
+ const match = matchRoute(routes, navUrl);
336
+ const transitionConfig = input.viewTransition ?? match?.route.viewTransition ?? options?.viewTransition;
337
+ await applyNavigation(navUrl, match, transitionConfig);
282
338
  }
283
339
  async function revalidate() {
284
340
  const match = current.value;
@@ -295,7 +351,9 @@ function createRouter(routes, initialUrlOrOptions, maybeOptions) {
295
351
  const onPopState = () => {
296
352
  const popUrl = window.location.pathname + window.location.search;
297
353
  startPrefetch(popUrl);
298
- applyNavigation(popUrl).catch(() => {});
354
+ const match = matchRoute(routes, popUrl);
355
+ const transitionConfig = match?.route.viewTransition ?? options?.viewTransition;
356
+ applyNavigation(popUrl, match, transitionConfig).catch(() => {});
299
357
  };
300
358
  window.addEventListener("popstate", onPopState);
301
359
  function dispose() {