sibujs 4.10.0 → 4.11.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.
Files changed (60) hide show
  1. package/dist/browser.cjs +1 -1
  2. package/dist/browser.js +4 -4
  3. package/dist/build.cjs +1 -1
  4. package/dist/build.js +10 -10
  5. package/dist/cdn.dev.global.js +1 -1
  6. package/dist/cdn.full.dev.global.js +1 -1
  7. package/dist/cdn.full.global.js +1 -1
  8. package/dist/cdn.global.js +1 -1
  9. package/dist/{chunk-EVI4ZQO3.js → chunk-3Z7AEJMQ.js} +2 -2
  10. package/dist/{chunk-GMMDHJJT.js → chunk-5G53CC6L.js} +4 -4
  11. package/dist/{chunk-VWPMWV7O.js → chunk-5IODQRR3.js} +4 -4
  12. package/dist/{chunk-TOPRMXFY.js → chunk-7V7VFT7E.js} +1 -1
  13. package/dist/{chunk-D6HYFOWR.js → chunk-ADWDDJ5M.js} +1 -1
  14. package/dist/{chunk-GOL3FU5Q.js → chunk-CHQPJY47.js} +1 -1
  15. package/dist/{chunk-2NWHJ2UJ.js → chunk-DEUONJYR.js} +9 -9
  16. package/dist/{chunk-FYUEL5IW.js → chunk-F6B5CKF7.js} +1 -1
  17. package/dist/{chunk-XUQUQJYE.js → chunk-HMOPAC2Z.js} +1 -1
  18. package/dist/{chunk-5PC7OTQW.js → chunk-KFJUMC3Q.js} +1 -1
  19. package/dist/{chunk-IL5MMSCL.js → chunk-KREPZR2U.js} +3 -3
  20. package/dist/{chunk-N6U4GOIU.js → chunk-LQ2C44YH.js} +1 -1
  21. package/dist/{chunk-BMCR7TXG.js → chunk-MCPL5WKQ.js} +3 -3
  22. package/dist/{chunk-ITEL5KPL.js → chunk-NBBFF5VA.js} +5 -5
  23. package/dist/{chunk-7WIHYHWD.js → chunk-OJV2RW4D.js} +1 -1
  24. package/dist/{chunk-54F4TPHK.js → chunk-R244COCR.js} +2 -2
  25. package/dist/{chunk-EVOK663Z.js → chunk-REOAVT2M.js} +1 -1
  26. package/dist/{chunk-IFRIBZ4O.js → chunk-RRKGQKPU.js} +4 -4
  27. package/dist/{chunk-GTS35FLA.js → chunk-VZDMHDVA.js} +2 -2
  28. package/dist/{chunk-JCKUWWHU.js → chunk-WQ7M57JJ.js} +3 -3
  29. package/dist/{chunk-4DCVJ4YA.js → chunk-YXJHLMRH.js} +4 -4
  30. package/dist/data.cjs +1 -1
  31. package/dist/data.js +5 -5
  32. package/dist/devtools.cjs +1 -1
  33. package/dist/devtools.js +4 -4
  34. package/dist/ecosystem.cjs +1 -1
  35. package/dist/ecosystem.js +7 -7
  36. package/dist/extras.cjs +3 -3
  37. package/dist/extras.js +20 -20
  38. package/dist/index.cjs +1 -1
  39. package/dist/index.d.cts +16 -4
  40. package/dist/index.d.ts +16 -4
  41. package/dist/index.js +10 -10
  42. package/dist/motion.cjs +1 -1
  43. package/dist/motion.js +3 -3
  44. package/dist/patterns.cjs +1 -1
  45. package/dist/patterns.js +5 -5
  46. package/dist/performance.cjs +1 -1
  47. package/dist/performance.js +4 -4
  48. package/dist/plugins.cjs +142 -15
  49. package/dist/plugins.d.cts +19 -5
  50. package/dist/plugins.d.ts +19 -5
  51. package/dist/plugins.js +146 -19
  52. package/dist/ssr.cjs +1 -1
  53. package/dist/ssr.js +7 -7
  54. package/dist/testing.cjs +1 -1
  55. package/dist/testing.js +2 -2
  56. package/dist/ui.cjs +1 -1
  57. package/dist/ui.js +7 -7
  58. package/dist/widgets.cjs +1 -1
  59. package/dist/widgets.js +6 -6
  60. package/package.json +1 -1
package/dist/plugins.cjs CHANGED
@@ -2381,7 +2381,7 @@ function forEachSubscriber(signal2, visit) {
2381
2381
  }
2382
2382
 
2383
2383
  // src/reactivity/track.ts
2384
- var _runtimeVersion = true ? "4.10.0" : "dev";
2384
+ var _runtimeVersion = true ? "4.11.0" : "dev";
2385
2385
  var REGISTRY_KEY = /* @__PURE__ */ Symbol.for("sibujs.reactive.v1");
2386
2386
  function resolveReactiveApi() {
2387
2387
  const g2 = globalThis;
@@ -3458,11 +3458,28 @@ function normalizePathname(path2) {
3458
3458
  function parseQuery(query) {
3459
3459
  return Object.fromEntries(new URLSearchParams(query));
3460
3460
  }
3461
+ function parseQueryAll(query) {
3462
+ const all = /* @__PURE__ */ new Map();
3463
+ for (const [key, value] of new URLSearchParams(query)) {
3464
+ const values = all.get(key);
3465
+ if (values) values.push(value);
3466
+ else all.set(key, [value]);
3467
+ }
3468
+ return Object.fromEntries(all);
3469
+ }
3470
+ function serializeQuery(query) {
3471
+ const search = new URLSearchParams();
3472
+ for (const [key, value] of Object.entries(query)) {
3473
+ if (Array.isArray(value)) for (const v of value) search.append(key, String(v));
3474
+ else search.append(key, String(value));
3475
+ }
3476
+ return search.toString();
3477
+ }
3461
3478
  function paramsIdentity(params) {
3462
3479
  return JSON.stringify(Object.entries(params).sort(([a2], [b2]) => a2 < b2 ? -1 : a2 > b2 ? 1 : 0));
3463
3480
  }
3464
3481
  function queryIdentity(query) {
3465
- return paramsIdentity(typeof query === "string" ? parseQuery(query) : query);
3482
+ return paramsIdentity(typeof query === "string" ? parseQueryAll(query) : query);
3466
3483
  }
3467
3484
  function isPathnameAncestor(target, current) {
3468
3485
  if (target === current) return true;
@@ -4138,6 +4155,7 @@ var _SibuRouter = class _SibuRouter {
4138
4155
  path: "/",
4139
4156
  params: {},
4140
4157
  query: {},
4158
+ queryAll: {},
4141
4159
  hash: "",
4142
4160
  meta: {},
4143
4161
  matched: []
@@ -4164,6 +4182,7 @@ var _SibuRouter = class _SibuRouter {
4164
4182
  createRouteContext(fullPath) {
4165
4183
  const { path: path2, query: queryString, hash } = splitRouteUrl(fullPath);
4166
4184
  const query = parseQuery(queryString);
4185
+ const queryAll = parseQueryAll(queryString);
4167
4186
  const match = this.matcher.match(path2 || "/");
4168
4187
  const params = match?.params || {};
4169
4188
  const meta2 = match?.route.meta || {};
@@ -4172,6 +4191,7 @@ var _SibuRouter = class _SibuRouter {
4172
4191
  path: path2 || "/",
4173
4192
  params,
4174
4193
  query,
4194
+ queryAll,
4175
4195
  hash,
4176
4196
  meta: meta2,
4177
4197
  matched
@@ -4317,8 +4337,9 @@ var _SibuRouter = class _SibuRouter {
4317
4337
  path2 = path2.replace(new RegExp(`:${key}(?=[/?#]|$)`, "g"), encodeURIComponent(value));
4318
4338
  }
4319
4339
  }
4320
- if (to.query && Object.keys(to.query).length > 0) {
4321
- path2 += `?${new URLSearchParams(to.query).toString()}`;
4340
+ const search = to.query ? serializeQuery(to.query) : "";
4341
+ if (search) {
4342
+ path2 += `?${search}`;
4322
4343
  }
4323
4344
  if (to.hash) {
4324
4345
  path2 += `#${to.hash}`;
@@ -4327,10 +4348,11 @@ var _SibuRouter = class _SibuRouter {
4327
4348
  }
4328
4349
  isSameRoute(from, to) {
4329
4350
  if (from.matched.length === 0 && to.matched.length > 0) return false;
4330
- return from.path === to.path && paramsIdentity(from.params) === paramsIdentity(to.params) && queryIdentity(from.query) === queryIdentity(to.query) && from.hash === to.hash;
4351
+ return from.path === to.path && paramsIdentity(from.params) === paramsIdentity(to.params) && queryIdentity(from.queryAll) === queryIdentity(to.queryAll) && from.hash === to.hash;
4331
4352
  }
4332
4353
  updateHistory(to, options) {
4333
- const fullPath = this.options.base + to.path + (Object.keys(to.query).length ? `?${new URLSearchParams(to.query).toString()}` : "") + (to.hash ? `#${to.hash}` : "");
4354
+ const search = serializeQuery(to.queryAll);
4355
+ const fullPath = this.options.base + to.path + (search ? `?${search}` : "") + (to.hash ? `#${to.hash}` : "");
4334
4356
  const h = globalThis.history;
4335
4357
  if (!h) return;
4336
4358
  if (options.replace) {
@@ -4513,6 +4535,65 @@ function abortReasonOf(signal2) {
4513
4535
  }
4514
4536
  var ROUTER_KEY = /* @__PURE__ */ Symbol.for("sibujs.router.v1");
4515
4537
  var _routerRef = globalThis[ROUTER_KEY] ?? (globalThis[ROUTER_KEY] = { current: null });
4538
+ var [routerRevision, setRouterRevision] = signal(0);
4539
+ var awaitingParent = /* @__PURE__ */ new Map();
4540
+ var parentObserver = null;
4541
+ function stopParentObserverIfIdle() {
4542
+ if (parentObserver && awaitingParent.size === 0) {
4543
+ parentObserver.disconnect();
4544
+ parentObserver = null;
4545
+ }
4546
+ }
4547
+ function whenAnchorAttached(anchor, run) {
4548
+ let cancelled = false;
4549
+ queueMicrotask(() => {
4550
+ if (cancelled) return;
4551
+ if (anchor.parentNode) {
4552
+ cancelled = true;
4553
+ run();
4554
+ return;
4555
+ }
4556
+ if (typeof MutationObserver === "undefined" || typeof document === "undefined") return;
4557
+ awaitingParent.set(anchor, () => {
4558
+ cancelled = true;
4559
+ run();
4560
+ });
4561
+ if (!parentObserver) {
4562
+ parentObserver = new MutationObserver(() => {
4563
+ for (const [node, cb] of awaitingParent) {
4564
+ if (!node.parentNode) continue;
4565
+ awaitingParent.delete(node);
4566
+ cb();
4567
+ }
4568
+ stopParentObserverIfIdle();
4569
+ });
4570
+ parentObserver.observe(document, { childList: true, subtree: true });
4571
+ }
4572
+ });
4573
+ return () => {
4574
+ if (cancelled) return;
4575
+ cancelled = true;
4576
+ awaitingParent.delete(anchor);
4577
+ stopParentObserverIfIdle();
4578
+ };
4579
+ }
4580
+ function attachRetry(anchor, rerun) {
4581
+ const run = bindOwnerScope2(rerun);
4582
+ let cancelWait = null;
4583
+ return {
4584
+ request: () => {
4585
+ if (cancelWait) return;
4586
+ cancelWait = whenAnchorAttached(anchor, () => {
4587
+ cancelWait = null;
4588
+ run();
4589
+ });
4590
+ },
4591
+ cancel: () => {
4592
+ cancelWait?.();
4593
+ cancelWait = null;
4594
+ }
4595
+ };
4596
+ }
4516
4597
  function normalizeRoutes(routes) {
4517
4598
  return routes.map((route2) => {
4518
4599
  const normalizedChildren = route2.children && route2.children.length > 0 ? normalizeRoutes(route2.children) : route2.children;
@@ -4544,6 +4625,7 @@ function createRouter(routesOrOptions, options = {}) {
4544
4625
  }
4545
4626
  _routerRef.current = new SibuRouter(routes, options);
4546
4627
  ensureRouterPagehide();
4628
+ setRouterRevision((n) => n + 1);
4547
4629
  return _routerRef.current;
4548
4630
  }
4549
4631
  function setRoutes(routes) {
@@ -4699,6 +4781,9 @@ function Route() {
4699
4781
  let currentKey = null;
4700
4782
  let routeTorn = false;
4701
4783
  const commitTarget = (seq) => routeTorn || seq !== navSeq ? null : anchor.parentNode;
4784
+ const retryIfDetached = (seq) => {
4785
+ if (!routeTorn && seq === navSeq && !anchor.parentNode) attachWait.request();
4786
+ };
4702
4787
  const release = (node) => {
4703
4788
  if (!node) return;
4704
4789
  disposeOwned(node);
@@ -4781,6 +4866,7 @@ function Route() {
4781
4866
  anchor.parentNode.insertBefore(errorNode, anchor.nextSibling);
4782
4867
  };
4783
4868
  const update = async () => {
4869
+ routerRevision();
4784
4870
  if (routeTorn || !_routerRef.current) return;
4785
4871
  const seq = ++navSeq;
4786
4872
  const route2 = scopedRoute(_routerRef.current);
@@ -4814,11 +4900,15 @@ function Route() {
4814
4900
  showLoading();
4815
4901
  }
4816
4902
  const plan = await _routerRef.current.loadPlan(routeDef, route2.path);
4817
- if (!commitTarget(seq)) return;
4903
+ if (!commitTarget(seq)) {
4904
+ retryIfDetached(seq);
4905
+ return;
4906
+ }
4818
4907
  const node = await instantiateScoped(_routerRef.current, plan, routeDef, route2.path, route2);
4819
4908
  const parent = commitTarget(seq);
4820
4909
  if (!parent) {
4821
4910
  release(node);
4911
+ retryIfDetached(seq);
4822
4912
  return;
4823
4913
  }
4824
4914
  if (node) {
@@ -4832,15 +4922,31 @@ function Route() {
4832
4922
  if (routeTorn || seq !== navSeq) return;
4833
4923
  hideLoading();
4834
4924
  console.error("[Route] Component error:", error);
4835
- showError(error instanceof Error ? error : new Error(String(error)), routeDef);
4925
+ fail(seq, error, routeDef);
4836
4926
  }
4837
4927
  }
4838
4928
  } catch (error) {
4839
4929
  if (seq !== navSeq) return;
4840
4930
  if (routeTorn) return;
4841
4931
  console.error("[Route] Update failed:", error);
4842
- showError(error instanceof Error ? error : new Error(String(error)));
4932
+ fail(seq, error);
4933
+ }
4934
+ };
4935
+ let unshownFailure = null;
4936
+ const fail = (seq, error, routeDef) => {
4937
+ const err = error instanceof Error ? error : new Error(String(error));
4938
+ if (anchor.parentNode) {
4939
+ showError(err, routeDef);
4940
+ return;
4843
4941
  }
4942
+ unshownFailure = { seq, error: err, routeDef };
4943
+ attachWait.request();
4944
+ };
4945
+ const onAttached = () => {
4946
+ const failure = unshownFailure;
4947
+ unshownFailure = null;
4948
+ if (failure && failure.seq === navSeq) showError(failure.error, failure.routeDef);
4949
+ else update();
4844
4950
  };
4845
4951
  let routeInitialized = false;
4846
4952
  const originalUpdate = update;
@@ -4848,6 +4954,7 @@ function Route() {
4848
4954
  await originalUpdate();
4849
4955
  routeInitialized = true;
4850
4956
  };
4957
+ const attachWait = attachRetry(anchor, onAttached);
4851
4958
  const routeTeardown = track2(wrappedUpdate);
4852
4959
  if (!routeInitialized) {
4853
4960
  queueMicrotask(
@@ -4861,6 +4968,8 @@ function Route() {
4861
4968
  routeTorn = true;
4862
4969
  navSeq++;
4863
4970
  routeTeardown();
4971
+ attachWait.cancel();
4972
+ unshownFailure = null;
4864
4973
  cleanupNodes();
4865
4974
  currentTopRoute = null;
4866
4975
  currentKey = null;
@@ -4884,6 +4993,7 @@ function KeepAliveRoute(options) {
4884
4993
  let updateSeq = 0;
4885
4994
  let kaTorn = false;
4886
4995
  const update = async () => {
4996
+ routerRevision();
4887
4997
  if (kaTorn || !_routerRef.current) return;
4888
4998
  const seq = ++updateSeq;
4889
4999
  const router2 = _routerRef.current;
@@ -4901,13 +5011,16 @@ function KeepAliveRoute(options) {
4901
5011
  return;
4902
5012
  }
4903
5013
  if (!("component" in routeDef)) return;
4904
- const cacheKey = JSON.stringify([route2.path, queryIdentity(route2.query), route2.hash]);
5014
+ const cacheKey = JSON.stringify([route2.path, queryIdentity(route2.queryAll), route2.hash]);
4905
5015
  const shouldCache = !includeNames || routeDef.name != null && includeNames.includes(routeDef.name);
4906
5016
  if (cacheKey === currentKey && currentNode) {
4907
5017
  updateInstanceRoute(currentNode, route2);
4908
5018
  return;
4909
5019
  }
4910
- if (!anchor.parentNode) return;
5020
+ if (!anchor.parentNode) {
5021
+ attachWait.request();
5022
+ return;
5023
+ }
4911
5024
  let node = null;
4912
5025
  let fromCache = false;
4913
5026
  if (shouldCache && cache.has(cacheKey)) {
@@ -4932,6 +5045,7 @@ function KeepAliveRoute(options) {
4932
5045
  const parent = anchor.parentNode;
4933
5046
  if (!parent) {
4934
5047
  if (!fromCache) disposeOwned(node);
5048
+ attachWait.request();
4935
5049
  return;
4936
5050
  }
4937
5051
  if (currentNode && currentNode !== node) {
@@ -4970,6 +5084,7 @@ function KeepAliveRoute(options) {
4970
5084
  await update();
4971
5085
  initialized = true;
4972
5086
  };
5087
+ const attachWait = attachRetry(anchor, update);
4973
5088
  const kaTeardown = track2(wrappedUpdate);
4974
5089
  if (!initialized) {
4975
5090
  queueMicrotask(
@@ -4983,6 +5098,7 @@ function KeepAliveRoute(options) {
4983
5098
  kaTorn = true;
4984
5099
  updateSeq++;
4985
5100
  kaTeardown();
5101
+ attachWait.cancel();
4986
5102
  for (const node of cache.values()) {
4987
5103
  disposeOwned(node);
4988
5104
  if (node.parentNode) node.parentNode.removeChild(node);
@@ -5027,7 +5143,7 @@ function RouterLink(props, children) {
5027
5143
  const route2 = routeGetter();
5028
5144
  const currentPath = normalizePathname(route2.path);
5029
5145
  const isActive = kind === "internal" && isPathnameAncestor(targetPath, currentPath);
5030
- const isExactActive = kind === "internal" && currentPath === targetPath && queryIdentity(route2.query) === targetQuery && route2.hash === hrefHash;
5146
+ const isExactActive = kind === "internal" && currentPath === targetPath && queryIdentity(route2.queryAll) === targetQuery && route2.hash === hrefHash;
5031
5147
  const classes = [];
5032
5148
  if (isActive) {
5033
5149
  if (activeClass) classes.push(activeClass);
@@ -5222,12 +5338,16 @@ function Outlet() {
5222
5338
  currentKey = null;
5223
5339
  };
5224
5340
  const commitTarget = (seq) => outletTorn || seq !== navSeq ? null : anchor.parentNode;
5341
+ const retryIfDetached = (seq) => {
5342
+ if (!outletTorn && seq === navSeq && !anchor.parentNode) attachWait.request();
5343
+ };
5225
5344
  const release = (node) => {
5226
5345
  if (!node) return;
5227
5346
  disposeOwned(node);
5228
5347
  node.parentNode?.removeChild(node);
5229
5348
  };
5230
5349
  const update = async () => {
5350
+ routerRevision();
5231
5351
  if (outletTorn || !_routerRef.current) return;
5232
5352
  const seq = ++navSeq;
5233
5353
  const route2 = scopedRoute(_routerRef.current);
@@ -5248,11 +5368,15 @@ function Outlet() {
5248
5368
  try {
5249
5369
  const cacheKey = `${route2.path}\0${childRoute.path}`;
5250
5370
  const plan = await _routerRef.current.loadPlan(childRoute, cacheKey);
5251
- if (!commitTarget(seq)) return;
5371
+ if (!commitTarget(seq)) {
5372
+ retryIfDetached(seq);
5373
+ return;
5374
+ }
5252
5375
  const node = await instantiateScoped(_routerRef.current, plan, childRoute, cacheKey, route2);
5253
5376
  const parent = commitTarget(seq);
5254
5377
  if (!parent) {
5255
5378
  release(node);
5379
+ retryIfDetached(seq);
5256
5380
  return;
5257
5381
  }
5258
5382
  if (!node) return;
@@ -5266,6 +5390,7 @@ function Outlet() {
5266
5390
  console.error("[Outlet] Failed to render child route:", error);
5267
5391
  }
5268
5392
  };
5393
+ const attachWait = attachRetry(anchor, update);
5269
5394
  const outletTeardown = track2(update);
5270
5395
  if (!anchor.parentNode) {
5271
5396
  queueMicrotask(
@@ -5279,6 +5404,7 @@ function Outlet() {
5279
5404
  outletTorn = true;
5280
5405
  navSeq++;
5281
5406
  outletTeardown();
5407
+ attachWait.cancel();
5282
5408
  if (currentNode) {
5283
5409
  disposeOwned(currentNode);
5284
5410
  if (currentNode.parentNode) currentNode.parentNode.removeChild(currentNode);
@@ -5306,6 +5432,7 @@ function routerState() {
5306
5432
  currentPath: () => scopedRoute(router2).path,
5307
5433
  params: () => scopedRoute(router2).params,
5308
5434
  query: () => scopedRoute(router2).query,
5435
+ queryAll: () => scopedRoute(router2).queryAll,
5309
5436
  hash: () => scopedRoute(router2).hash,
5310
5437
  meta: () => scopedRoute(router2).meta,
5311
5438
  isNavigating: () => router2.isNavigating,
@@ -6021,7 +6148,7 @@ var CDN_ENTRY_POINTS = {
6021
6148
  };
6022
6149
  var packageInfo = {
6023
6150
  name: "sibujs",
6024
- version: true ? "4.10.0" : "dev",
6151
+ version: true ? "4.11.0" : "dev",
6025
6152
  entryPoints: MODULE_ENTRY_POINTS,
6026
6153
  /**
6027
6154
  * Generate the package.json `exports` map. Module entries resolve to the
@@ -6166,7 +6293,7 @@ var env = {
6166
6293
  };
6167
6294
 
6168
6295
  // src/plugins/versioning.ts
6169
- var VERSION = true ? "4.10.0" : "dev";
6296
+ var VERSION = true ? "4.11.0" : "dev";
6170
6297
  var NUM = "(?:0|[1-9]\\d*)";
6171
6298
  var PRE_ID = `(?:${NUM}|\\d*[a-zA-Z-][0-9a-zA-Z-]*)`;
6172
6299
  var BUILD_ID = "[0-9a-zA-Z-]+";
@@ -177,16 +177,29 @@ type LazyComponent = () => Promise<{
177
177
  default: Component;
178
178
  }>;
179
179
  type Params = Record<string, string>;
180
+ /** Every value of every query key, in URL order: `?tag=a&tag=b` is `{ tag: ["a", "b"] }`. */
181
+ type QueryValues = Readonly<Record<string, readonly string[]>>;
182
+ /**
183
+ * The query of a navigation object. An array value repeats its key once per
184
+ * value, in order: `{ tag: ["a", "b"] }` is `?tag=a&tag=b`.
185
+ */
186
+ type NavigationQuery = Readonly<Record<string, string | readonly string[]>>;
180
187
  interface RouteContext {
181
188
  readonly path: string;
182
189
  readonly params: Params;
183
190
  /**
184
191
  * The decoded query (`+` is a space, `%XX` is decoded). A repeated key keeps
185
- * its last value: `?tag=a&tag=b` is `{ tag: "b" }`. Two locations are the
186
- * same route — for duplicate detection and `RouterLink` exact-active — when
187
- * their queries have the same entries in any order.
192
+ * its last value here: `?tag=a&tag=b` is `{ tag: "b" }`. Read
193
+ * {@link RouteContext.queryAll} for every value.
188
194
  */
189
195
  readonly query: Params;
196
+ /**
197
+ * Every value of every query key, in URL order, with the same decoding as
198
+ * `query`: `?tag=a&tag=b` is `{ tag: ["a", "b"] }`. Two locations are the
199
+ * same route — for duplicate detection and `RouterLink` exact-active — when
200
+ * these match, key order aside.
201
+ */
202
+ readonly queryAll: QueryValues;
190
203
  readonly hash: string;
191
204
  readonly meta: RouteMeta;
192
205
  readonly matched: RouteDef[];
@@ -345,7 +358,7 @@ type NavigationTarget = string | {
345
358
  path?: string;
346
359
  name?: string;
347
360
  params?: Params;
348
- query?: Params;
361
+ query?: NavigationQuery;
349
362
  hash?: string;
350
363
  };
351
364
  /**
@@ -812,6 +825,7 @@ declare function routerState(): {
812
825
  currentPath: () => string;
813
826
  params: () => Params;
814
827
  query: () => Params;
828
+ queryAll: () => QueryValues;
815
829
  hash: () => string;
816
830
  meta: () => RouteMeta;
817
831
  isNavigating: () => boolean;
@@ -960,4 +974,4 @@ declare function createSSRRouter(routes: SSRRouteDef[]): {
960
974
  }) => string;
961
975
  };
962
976
 
963
- export { type AsyncComponent, type AsyncRoute, type Component, type ComponentRoute, type Guard, type GuardResult, KeepAliveRoute, type LazyComponent, type LazyRoute, type NavigationFailure, type NavigationFailureReason, type NavigationGuard, type NavigationNext, type NavigationResult, type NavigationTarget, Outlet, type Params, type RedirectRoute, Route, type RouteBase, type RouteContext, type RouteDef, type RouteMeta, type RouteTransitionOptions, RouterLink, type RouterOptions, type RouterPlugin, type SSRRouteDef, type SSRRouteState, type ScrollBehavior, type ScrollPosition, SibuRouter, Suspense, Trans, type TranslationParams, __getNavigationEpoch, __removeRouterPagehideHandler, addRoute, afterEach, back, beforeEach, beforeResolve, buildURL, createMemoryRouter, createRouter, createSSRRouter, deserializeRouteState, destroyRouter, forward, getAvailableLocales, getLocale, getRouteInfo, getRouteTransition, go, hasRoute, hasTranslation, hydrateRouter, lazy, navigate, preloadRoute, push, registerTranslations, removeRoute, renderRouteToDocument, renderRouteToString, replace, resolveServerRoute, route, router, routerPlugin, routerState, serializeRouteState, setLocale, setRouteTransition, setRoutes, t, translated };
977
+ export { type AsyncComponent, type AsyncRoute, type Component, type ComponentRoute, type Guard, type GuardResult, KeepAliveRoute, type LazyComponent, type LazyRoute, type NavigationFailure, type NavigationFailureReason, type NavigationGuard, type NavigationNext, type NavigationQuery, type NavigationResult, type NavigationTarget, Outlet, type Params, type QueryValues, type RedirectRoute, Route, type RouteBase, type RouteContext, type RouteDef, type RouteMeta, type RouteTransitionOptions, RouterLink, type RouterOptions, type RouterPlugin, type SSRRouteDef, type SSRRouteState, type ScrollBehavior, type ScrollPosition, SibuRouter, Suspense, Trans, type TranslationParams, __getNavigationEpoch, __removeRouterPagehideHandler, addRoute, afterEach, back, beforeEach, beforeResolve, buildURL, createMemoryRouter, createRouter, createSSRRouter, deserializeRouteState, destroyRouter, forward, getAvailableLocales, getLocale, getRouteInfo, getRouteTransition, go, hasRoute, hasTranslation, hydrateRouter, lazy, navigate, preloadRoute, push, registerTranslations, removeRoute, renderRouteToDocument, renderRouteToString, replace, resolveServerRoute, route, router, routerPlugin, routerState, serializeRouteState, setLocale, setRouteTransition, setRoutes, t, translated };
package/dist/plugins.d.ts CHANGED
@@ -177,16 +177,29 @@ type LazyComponent = () => Promise<{
177
177
  default: Component;
178
178
  }>;
179
179
  type Params = Record<string, string>;
180
+ /** Every value of every query key, in URL order: `?tag=a&tag=b` is `{ tag: ["a", "b"] }`. */
181
+ type QueryValues = Readonly<Record<string, readonly string[]>>;
182
+ /**
183
+ * The query of a navigation object. An array value repeats its key once per
184
+ * value, in order: `{ tag: ["a", "b"] }` is `?tag=a&tag=b`.
185
+ */
186
+ type NavigationQuery = Readonly<Record<string, string | readonly string[]>>;
180
187
  interface RouteContext {
181
188
  readonly path: string;
182
189
  readonly params: Params;
183
190
  /**
184
191
  * The decoded query (`+` is a space, `%XX` is decoded). A repeated key keeps
185
- * its last value: `?tag=a&tag=b` is `{ tag: "b" }`. Two locations are the
186
- * same route — for duplicate detection and `RouterLink` exact-active — when
187
- * their queries have the same entries in any order.
192
+ * its last value here: `?tag=a&tag=b` is `{ tag: "b" }`. Read
193
+ * {@link RouteContext.queryAll} for every value.
188
194
  */
189
195
  readonly query: Params;
196
+ /**
197
+ * Every value of every query key, in URL order, with the same decoding as
198
+ * `query`: `?tag=a&tag=b` is `{ tag: ["a", "b"] }`. Two locations are the
199
+ * same route — for duplicate detection and `RouterLink` exact-active — when
200
+ * these match, key order aside.
201
+ */
202
+ readonly queryAll: QueryValues;
190
203
  readonly hash: string;
191
204
  readonly meta: RouteMeta;
192
205
  readonly matched: RouteDef[];
@@ -345,7 +358,7 @@ type NavigationTarget = string | {
345
358
  path?: string;
346
359
  name?: string;
347
360
  params?: Params;
348
- query?: Params;
361
+ query?: NavigationQuery;
349
362
  hash?: string;
350
363
  };
351
364
  /**
@@ -812,6 +825,7 @@ declare function routerState(): {
812
825
  currentPath: () => string;
813
826
  params: () => Params;
814
827
  query: () => Params;
828
+ queryAll: () => QueryValues;
815
829
  hash: () => string;
816
830
  meta: () => RouteMeta;
817
831
  isNavigating: () => boolean;
@@ -960,4 +974,4 @@ declare function createSSRRouter(routes: SSRRouteDef[]): {
960
974
  }) => string;
961
975
  };
962
976
 
963
- export { type AsyncComponent, type AsyncRoute, type Component, type ComponentRoute, type Guard, type GuardResult, KeepAliveRoute, type LazyComponent, type LazyRoute, type NavigationFailure, type NavigationFailureReason, type NavigationGuard, type NavigationNext, type NavigationResult, type NavigationTarget, Outlet, type Params, type RedirectRoute, Route, type RouteBase, type RouteContext, type RouteDef, type RouteMeta, type RouteTransitionOptions, RouterLink, type RouterOptions, type RouterPlugin, type SSRRouteDef, type SSRRouteState, type ScrollBehavior, type ScrollPosition, SibuRouter, Suspense, Trans, type TranslationParams, __getNavigationEpoch, __removeRouterPagehideHandler, addRoute, afterEach, back, beforeEach, beforeResolve, buildURL, createMemoryRouter, createRouter, createSSRRouter, deserializeRouteState, destroyRouter, forward, getAvailableLocales, getLocale, getRouteInfo, getRouteTransition, go, hasRoute, hasTranslation, hydrateRouter, lazy, navigate, preloadRoute, push, registerTranslations, removeRoute, renderRouteToDocument, renderRouteToString, replace, resolveServerRoute, route, router, routerPlugin, routerState, serializeRouteState, setLocale, setRouteTransition, setRoutes, t, translated };
977
+ export { type AsyncComponent, type AsyncRoute, type Component, type ComponentRoute, type Guard, type GuardResult, KeepAliveRoute, type LazyComponent, type LazyRoute, type NavigationFailure, type NavigationFailureReason, type NavigationGuard, type NavigationNext, type NavigationQuery, type NavigationResult, type NavigationTarget, Outlet, type Params, type QueryValues, type RedirectRoute, Route, type RouteBase, type RouteContext, type RouteDef, type RouteMeta, type RouteTransitionOptions, RouterLink, type RouterOptions, type RouterPlugin, type SSRRouteDef, type SSRRouteState, type ScrollBehavior, type ScrollPosition, SibuRouter, Suspense, Trans, type TranslationParams, __getNavigationEpoch, __removeRouterPagehideHandler, addRoute, afterEach, back, beforeEach, beforeResolve, buildURL, createMemoryRouter, createRouter, createSSRRouter, deserializeRouteState, destroyRouter, forward, getAvailableLocales, getLocale, getRouteInfo, getRouteTransition, go, hasRoute, hasTranslation, hydrateRouter, lazy, navigate, preloadRoute, push, registerTranslations, removeRoute, renderRouteToDocument, renderRouteToString, replace, resolveServerRoute, route, router, routerPlugin, routerState, serializeRouteState, setLocale, setRouteTransition, setRoutes, t, translated };