zero-query 0.6.3 → 0.7.5

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 (41) hide show
  1. package/README.md +6 -6
  2. package/cli/commands/build.js +3 -3
  3. package/cli/commands/bundle.js +286 -8
  4. package/cli/commands/dev/index.js +2 -2
  5. package/cli/commands/dev/overlay.js +51 -2
  6. package/cli/commands/dev/server.js +34 -5
  7. package/cli/commands/dev/watcher.js +33 -0
  8. package/cli/scaffold/index.html +1 -0
  9. package/cli/scaffold/scripts/app.js +15 -22
  10. package/cli/scaffold/scripts/components/contacts/contacts.css +0 -7
  11. package/cli/scaffold/scripts/components/contacts/contacts.html +3 -3
  12. package/cli/scaffold/styles/styles.css +1 -0
  13. package/cli/utils.js +111 -6
  14. package/dist/zquery.dist.zip +0 -0
  15. package/dist/zquery.js +379 -27
  16. package/dist/zquery.min.js +3 -16
  17. package/index.d.ts +127 -1290
  18. package/package.json +5 -5
  19. package/src/component.js +11 -1
  20. package/src/core.js +305 -10
  21. package/src/router.js +49 -2
  22. package/tests/component.test.js +304 -0
  23. package/tests/core.test.js +726 -0
  24. package/tests/diff.test.js +194 -0
  25. package/tests/errors.test.js +162 -0
  26. package/tests/expression.test.js +334 -0
  27. package/tests/http.test.js +181 -0
  28. package/tests/reactive.test.js +191 -0
  29. package/tests/router.test.js +332 -0
  30. package/tests/store.test.js +253 -0
  31. package/tests/utils.test.js +353 -0
  32. package/types/collection.d.ts +368 -0
  33. package/types/component.d.ts +210 -0
  34. package/types/errors.d.ts +103 -0
  35. package/types/http.d.ts +81 -0
  36. package/types/misc.d.ts +166 -0
  37. package/types/reactive.d.ts +76 -0
  38. package/types/router.d.ts +132 -0
  39. package/types/ssr.d.ts +49 -0
  40. package/types/store.d.ts +107 -0
  41. package/types/utils.d.ts +142 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zero-query",
3
- "version": "0.6.3",
3
+ "version": "0.7.5",
4
4
  "description": "Lightweight modern frontend library — jQuery-like selectors, reactive components, SPA router, and state management with zero dependencies.",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -9,8 +9,10 @@
9
9
  },
10
10
  "files": [
11
11
  "src",
12
+ "tests",
12
13
  "dist",
13
14
  "cli",
15
+ "types",
14
16
  "index.js",
15
17
  "index.d.ts",
16
18
  "LICENSE",
@@ -52,11 +54,9 @@
52
54
  "publishConfig": {
53
55
  "access": "public"
54
56
  },
55
- "dependencies": {
56
- "zero-http": "^0.2.3"
57
- },
58
57
  "devDependencies": {
59
58
  "jsdom": "^28.1.0",
60
- "vitest": "^4.0.18"
59
+ "vitest": "^4.0.18",
60
+ "zero-http": "^0.2.3"
61
61
  }
62
62
  }
package/src/component.js CHANGED
@@ -381,11 +381,14 @@ class Component {
381
381
  if (def.styleUrl && !def._styleLoaded) {
382
382
  const su = def.styleUrl;
383
383
  if (typeof su === 'string') {
384
- def._externalStyles = await _fetchResource(_resolveUrl(su, base));
384
+ const resolved = _resolveUrl(su, base);
385
+ def._externalStyles = await _fetchResource(resolved);
386
+ def._resolvedStyleUrls = [resolved];
385
387
  } else if (Array.isArray(su)) {
386
388
  const urls = su.map(u => _resolveUrl(u, base));
387
389
  const results = await Promise.all(urls.map(u => _fetchResource(u)));
388
390
  def._externalStyles = results.join('\n');
391
+ def._resolvedStyleUrls = urls;
389
392
  }
390
393
  def._styleLoaded = true;
391
394
  }
@@ -512,6 +515,13 @@ class Component {
512
515
  const styleEl = document.createElement('style');
513
516
  styleEl.textContent = scoped;
514
517
  styleEl.setAttribute('data-zq-component', this._def._name || '');
518
+ styleEl.setAttribute('data-zq-scope', scopeAttr);
519
+ if (this._def._resolvedStyleUrls) {
520
+ styleEl.setAttribute('data-zq-style-urls', this._def._resolvedStyleUrls.join(' '));
521
+ if (this._def.styles) {
522
+ styleEl.setAttribute('data-zq-inline', this._def.styles);
523
+ }
524
+ }
515
525
  document.head.appendChild(styleEl);
516
526
  this._styleEl = styleEl;
517
527
  }
package/src/core.js CHANGED
@@ -75,8 +75,96 @@ export class ZQueryCollection {
75
75
  return new ZQueryCollection(sibs);
76
76
  }
77
77
 
78
- next() { return new ZQueryCollection(this.elements.map(el => el.nextElementSibling).filter(Boolean)); }
79
- prev() { return new ZQueryCollection(this.elements.map(el => el.previousElementSibling).filter(Boolean)); }
78
+ next(selector) {
79
+ const els = this.elements.map(el => el.nextElementSibling).filter(Boolean);
80
+ return new ZQueryCollection(selector ? els.filter(el => el.matches(selector)) : els);
81
+ }
82
+
83
+ prev(selector) {
84
+ const els = this.elements.map(el => el.previousElementSibling).filter(Boolean);
85
+ return new ZQueryCollection(selector ? els.filter(el => el.matches(selector)) : els);
86
+ }
87
+
88
+ nextAll(selector) {
89
+ const result = [];
90
+ this.elements.forEach(el => {
91
+ let sib = el.nextElementSibling;
92
+ while (sib) {
93
+ if (!selector || sib.matches(selector)) result.push(sib);
94
+ sib = sib.nextElementSibling;
95
+ }
96
+ });
97
+ return new ZQueryCollection(result);
98
+ }
99
+
100
+ nextUntil(selector, filter) {
101
+ const result = [];
102
+ this.elements.forEach(el => {
103
+ let sib = el.nextElementSibling;
104
+ while (sib) {
105
+ if (selector && sib.matches(selector)) break;
106
+ if (!filter || sib.matches(filter)) result.push(sib);
107
+ sib = sib.nextElementSibling;
108
+ }
109
+ });
110
+ return new ZQueryCollection(result);
111
+ }
112
+
113
+ prevAll(selector) {
114
+ const result = [];
115
+ this.elements.forEach(el => {
116
+ let sib = el.previousElementSibling;
117
+ while (sib) {
118
+ if (!selector || sib.matches(selector)) result.push(sib);
119
+ sib = sib.previousElementSibling;
120
+ }
121
+ });
122
+ return new ZQueryCollection(result);
123
+ }
124
+
125
+ prevUntil(selector, filter) {
126
+ const result = [];
127
+ this.elements.forEach(el => {
128
+ let sib = el.previousElementSibling;
129
+ while (sib) {
130
+ if (selector && sib.matches(selector)) break;
131
+ if (!filter || sib.matches(filter)) result.push(sib);
132
+ sib = sib.previousElementSibling;
133
+ }
134
+ });
135
+ return new ZQueryCollection(result);
136
+ }
137
+
138
+ parents(selector) {
139
+ const result = [];
140
+ this.elements.forEach(el => {
141
+ let parent = el.parentElement;
142
+ while (parent) {
143
+ if (!selector || parent.matches(selector)) result.push(parent);
144
+ parent = parent.parentElement;
145
+ }
146
+ });
147
+ return new ZQueryCollection([...new Set(result)]);
148
+ }
149
+
150
+ parentsUntil(selector, filter) {
151
+ const result = [];
152
+ this.elements.forEach(el => {
153
+ let parent = el.parentElement;
154
+ while (parent) {
155
+ if (selector && parent.matches(selector)) break;
156
+ if (!filter || parent.matches(filter)) result.push(parent);
157
+ parent = parent.parentElement;
158
+ }
159
+ });
160
+ return new ZQueryCollection([...new Set(result)]);
161
+ }
162
+
163
+ contents() {
164
+ const result = [];
165
+ this.elements.forEach(el => result.push(...el.childNodes));
166
+ return new ZQueryCollection(result);
167
+ }
80
168
 
81
169
  filter(selector) {
82
170
  if (typeof selector === 'function') {
@@ -96,6 +184,42 @@ export class ZQueryCollection {
96
184
  return new ZQueryCollection(this.elements.filter(el => el.querySelector(selector)));
97
185
  }
98
186
 
187
+ is(selector) {
188
+ if (typeof selector === 'function') {
189
+ return this.elements.some((el, i) => selector.call(el, i, el));
190
+ }
191
+ return this.elements.some(el => el.matches(selector));
192
+ }
193
+
194
+ slice(start, end) {
195
+ return new ZQueryCollection(this.elements.slice(start, end));
196
+ }
197
+
198
+ add(selector, context) {
199
+ const toAdd = (selector instanceof ZQueryCollection)
200
+ ? selector.elements
201
+ : (selector instanceof Node)
202
+ ? [selector]
203
+ : Array.from((context || document).querySelectorAll(selector));
204
+ return new ZQueryCollection([...this.elements, ...toAdd]);
205
+ }
206
+
207
+ get(index) {
208
+ if (index === undefined) return [...this.elements];
209
+ return index < 0 ? this.elements[this.length + index] : this.elements[index];
210
+ }
211
+
212
+ index(selector) {
213
+ if (selector === undefined) {
214
+ const el = this.first();
215
+ return el ? Array.from(el.parentElement.children).indexOf(el) : -1;
216
+ }
217
+ const target = (typeof selector === 'string')
218
+ ? document.querySelector(selector)
219
+ : selector;
220
+ return this.elements.indexOf(target);
221
+ }
222
+
99
223
  // --- Classes -------------------------------------------------------------
100
224
 
101
225
  addClass(...names) {
@@ -108,8 +232,12 @@ export class ZQueryCollection {
108
232
  return this.each((_, el) => el.classList.remove(...classes));
109
233
  }
110
234
 
111
- toggleClass(name, force) {
112
- return this.each((_, el) => el.classList.toggle(name, force));
235
+ toggleClass(...args) {
236
+ const force = typeof args[args.length - 1] === 'boolean' ? args.pop() : undefined;
237
+ const classes = args.flatMap(n => n.split(/\s+/));
238
+ return this.each((_, el) => {
239
+ classes.forEach(c => force !== undefined ? el.classList.toggle(c, force) : el.classList.toggle(c));
240
+ });
113
241
  }
114
242
 
115
243
  hasClass(name) {
@@ -163,6 +291,60 @@ export class ZQueryCollection {
163
291
  return el ? { top: el.offsetTop, left: el.offsetLeft } : null;
164
292
  }
165
293
 
294
+ scrollTop(value) {
295
+ if (value === undefined) {
296
+ const el = this.first();
297
+ return el === window ? window.scrollY : el?.scrollTop;
298
+ }
299
+ return this.each((_, el) => {
300
+ if (el === window) window.scrollTo(window.scrollX, value);
301
+ else el.scrollTop = value;
302
+ });
303
+ }
304
+
305
+ scrollLeft(value) {
306
+ if (value === undefined) {
307
+ const el = this.first();
308
+ return el === window ? window.scrollX : el?.scrollLeft;
309
+ }
310
+ return this.each((_, el) => {
311
+ if (el === window) window.scrollTo(value, window.scrollY);
312
+ else el.scrollLeft = value;
313
+ });
314
+ }
315
+
316
+ innerWidth() {
317
+ const el = this.first();
318
+ return el?.clientWidth;
319
+ }
320
+
321
+ innerHeight() {
322
+ const el = this.first();
323
+ return el?.clientHeight;
324
+ }
325
+
326
+ outerWidth(includeMargin = false) {
327
+ const el = this.first();
328
+ if (!el) return undefined;
329
+ let w = el.offsetWidth;
330
+ if (includeMargin) {
331
+ const style = getComputedStyle(el);
332
+ w += parseFloat(style.marginLeft) + parseFloat(style.marginRight);
333
+ }
334
+ return w;
335
+ }
336
+
337
+ outerHeight(includeMargin = false) {
338
+ const el = this.first();
339
+ if (!el) return undefined;
340
+ let h = el.offsetHeight;
341
+ if (includeMargin) {
342
+ const style = getComputedStyle(el);
343
+ h += parseFloat(style.marginTop) + parseFloat(style.marginBottom);
344
+ }
345
+ return h;
346
+ }
347
+
166
348
  // --- Content -------------------------------------------------------------
167
349
 
168
350
  html(content) {
@@ -242,6 +424,73 @@ export class ZQueryCollection {
242
424
  });
243
425
  }
244
426
 
427
+ appendTo(target) {
428
+ const dest = typeof target === 'string' ? document.querySelector(target) : target instanceof ZQueryCollection ? target.first() : target;
429
+ if (dest) this.each((_, el) => dest.appendChild(el));
430
+ return this;
431
+ }
432
+
433
+ prependTo(target) {
434
+ const dest = typeof target === 'string' ? document.querySelector(target) : target instanceof ZQueryCollection ? target.first() : target;
435
+ if (dest) this.each((_, el) => dest.insertBefore(el, dest.firstChild));
436
+ return this;
437
+ }
438
+
439
+ insertAfter(target) {
440
+ const ref = typeof target === 'string' ? document.querySelector(target) : target instanceof ZQueryCollection ? target.first() : target;
441
+ if (ref && ref.parentNode) this.each((_, el) => ref.parentNode.insertBefore(el, ref.nextSibling));
442
+ return this;
443
+ }
444
+
445
+ insertBefore(target) {
446
+ const ref = typeof target === 'string' ? document.querySelector(target) : target instanceof ZQueryCollection ? target.first() : target;
447
+ if (ref && ref.parentNode) this.each((_, el) => ref.parentNode.insertBefore(el, ref));
448
+ return this;
449
+ }
450
+
451
+ replaceAll(target) {
452
+ const targets = typeof target === 'string'
453
+ ? Array.from(document.querySelectorAll(target))
454
+ : target instanceof ZQueryCollection ? target.elements : [target];
455
+ targets.forEach((t, i) => {
456
+ const nodes = i === 0 ? this.elements : this.elements.map(el => el.cloneNode(true));
457
+ nodes.forEach(el => t.parentNode.insertBefore(el, t));
458
+ t.remove();
459
+ });
460
+ return this;
461
+ }
462
+
463
+ unwrap(selector) {
464
+ this.elements.forEach(el => {
465
+ const parent = el.parentElement;
466
+ if (!parent || parent === document.body) return;
467
+ if (selector && !parent.matches(selector)) return;
468
+ parent.replaceWith(...parent.childNodes);
469
+ });
470
+ return this;
471
+ }
472
+
473
+ wrapAll(wrapper) {
474
+ const w = typeof wrapper === 'string' ? createFragment(wrapper).firstElementChild : wrapper.cloneNode(true);
475
+ const first = this.first();
476
+ if (!first) return this;
477
+ first.parentNode.insertBefore(w, first);
478
+ this.each((_, el) => w.appendChild(el));
479
+ return this;
480
+ }
481
+
482
+ wrapInner(wrapper) {
483
+ return this.each((_, el) => {
484
+ const w = typeof wrapper === 'string' ? createFragment(wrapper).firstElementChild : wrapper.cloneNode(true);
485
+ while (el.firstChild) w.appendChild(el.firstChild);
486
+ el.appendChild(w);
487
+ });
488
+ }
489
+
490
+ detach() {
491
+ return this.each((_, el) => el.remove());
492
+ }
493
+
245
494
  // --- Visibility ----------------------------------------------------------
246
495
 
247
496
  show(display = '') {
@@ -267,9 +516,10 @@ export class ZQueryCollection {
267
516
  events.forEach(evt => {
268
517
  if (typeof selectorOrHandler === 'function') {
269
518
  el.addEventListener(evt, selectorOrHandler);
270
- } else {
271
- // Delegated event
519
+ } else if (typeof selectorOrHandler === 'string') {
520
+ // Delegated event — only works on elements that support closest()
272
521
  el.addEventListener(evt, (e) => {
522
+ if (!e.target || typeof e.target.closest !== 'function') return;
273
523
  const target = e.target.closest(selectorOrHandler);
274
524
  if (target && el.contains(target)) handler.call(target, e);
275
525
  });
@@ -302,6 +552,10 @@ export class ZQueryCollection {
302
552
  submit(fn) { return fn ? this.on('submit', fn) : this.trigger('submit'); }
303
553
  focus() { this.first()?.focus(); return this; }
304
554
  blur() { this.first()?.blur(); return this; }
555
+ hover(enterFn, leaveFn) {
556
+ this.on('mouseenter', enterFn);
557
+ return this.on('mouseleave', leaveFn || enterFn);
558
+ }
305
559
 
306
560
  // --- Animation -----------------------------------------------------------
307
561
 
@@ -333,6 +587,40 @@ export class ZQueryCollection {
333
587
  return this.animate({ opacity: '0' }, duration).then(col => col.hide());
334
588
  }
335
589
 
590
+ fadeToggle(duration = 300) {
591
+ return Promise.all(this.elements.map(el => {
592
+ const visible = getComputedStyle(el).opacity !== '0' && getComputedStyle(el).display !== 'none';
593
+ const col = new ZQueryCollection([el]);
594
+ return visible ? col.fadeOut(duration) : col.fadeIn(duration);
595
+ })).then(() => this);
596
+ }
597
+
598
+ fadeTo(duration, opacity) {
599
+ return this.animate({ opacity: String(opacity) }, duration);
600
+ }
601
+
602
+ slideDown(duration = 300) {
603
+ return this.each((_, el) => {
604
+ el.style.display = '';
605
+ el.style.overflow = 'hidden';
606
+ const h = el.scrollHeight + 'px';
607
+ el.style.maxHeight = '0';
608
+ el.style.transition = `max-height ${duration}ms ease`;
609
+ requestAnimationFrame(() => { el.style.maxHeight = h; });
610
+ setTimeout(() => { el.style.maxHeight = ''; el.style.overflow = ''; el.style.transition = ''; }, duration);
611
+ });
612
+ }
613
+
614
+ slideUp(duration = 300) {
615
+ return this.each((_, el) => {
616
+ el.style.overflow = 'hidden';
617
+ el.style.maxHeight = el.scrollHeight + 'px';
618
+ el.style.transition = `max-height ${duration}ms ease`;
619
+ requestAnimationFrame(() => { el.style.maxHeight = '0'; });
620
+ setTimeout(() => { el.style.display = 'none'; el.style.maxHeight = ''; el.style.overflow = ''; el.style.transition = ''; }, duration);
621
+ });
622
+ }
623
+
336
624
  slideToggle(duration = 300) {
337
625
  return this.each((_, el) => {
338
626
  if (el.style.display === 'none' || getComputedStyle(el).display === 'none') {
@@ -480,7 +768,7 @@ query.children = (parentId) => {
480
768
  return new ZQueryCollection(p ? Array.from(p.children) : []);
481
769
  };
482
770
 
483
- // Create element shorthand
771
+ // Create element shorthand — returns ZQueryCollection for chaining
484
772
  query.create = (tag, attrs = {}, ...children) => {
485
773
  const el = document.createElement(tag);
486
774
  for (const [k, v] of Object.entries(attrs)) {
@@ -494,7 +782,7 @@ query.create = (tag, attrs = {}, ...children) => {
494
782
  if (typeof child === 'string') el.appendChild(document.createTextNode(child));
495
783
  else if (child instanceof Node) el.appendChild(child);
496
784
  });
497
- return el;
785
+ return new ZQueryCollection(el);
498
786
  };
499
787
 
500
788
  // DOM ready
@@ -503,17 +791,24 @@ query.ready = (fn) => {
503
791
  else document.addEventListener('DOMContentLoaded', fn);
504
792
  };
505
793
 
506
- // Global event listeners — supports direct and delegated forms
794
+ // Global event listeners — supports direct, delegated, and target-bound forms
507
795
  // $.on('keydown', handler) → direct listener on document
508
796
  // $.on('click', '.btn', handler) → delegated via closest()
797
+ // $.on('scroll', window, handler) → direct listener on target
509
798
  query.on = (event, selectorOrHandler, handler) => {
510
799
  if (typeof selectorOrHandler === 'function') {
511
800
  // 2-arg: direct document listener (keydown, resize, etc.)
512
801
  document.addEventListener(event, selectorOrHandler);
513
802
  return;
514
803
  }
515
- // 3-arg: delegated
804
+ // EventTarget (window, element, etc.) — direct listener on target
805
+ if (typeof selectorOrHandler === 'object' && typeof selectorOrHandler.addEventListener === 'function') {
806
+ selectorOrHandler.addEventListener(event, handler);
807
+ return;
808
+ }
809
+ // 3-arg string: delegated
516
810
  document.addEventListener(event, (e) => {
811
+ if (!e.target || typeof e.target.closest !== 'function') return;
517
812
  const target = e.target.closest(selectorOrHandler);
518
813
  if (target) handler.call(target, e);
519
814
  });
package/src/router.js CHANGED
@@ -78,7 +78,21 @@ class Router {
78
78
  if (!link) return;
79
79
  if (link.getAttribute('target') === '_blank') return;
80
80
  e.preventDefault();
81
- this.navigate(link.getAttribute('z-link'));
81
+ let href = link.getAttribute('z-link');
82
+ // Support z-link-params for dynamic :param interpolation
83
+ const paramsAttr = link.getAttribute('z-link-params');
84
+ if (paramsAttr) {
85
+ try {
86
+ const params = JSON.parse(paramsAttr);
87
+ href = this._interpolateParams(href, params);
88
+ } catch { /* ignore malformed JSON */ }
89
+ }
90
+ this.navigate(href);
91
+ // z-to-top modifier: scroll to top after navigation
92
+ if (link.hasAttribute('z-to-top')) {
93
+ const scrollBehavior = link.getAttribute('z-to-top') || 'instant';
94
+ window.scrollTo({ top: 0, behavior: scrollBehavior });
95
+ }
82
96
  });
83
97
 
84
98
  // Initial resolve
@@ -122,7 +136,23 @@ class Router {
122
136
 
123
137
  // --- Navigation ----------------------------------------------------------
124
138
 
139
+ /**
140
+ * Interpolate :param placeholders in a path with the given values.
141
+ * @param {string} path — e.g. '/user/:id/posts/:pid'
142
+ * @param {Object} params — e.g. { id: 42, pid: 7 }
143
+ * @returns {string}
144
+ */
145
+ _interpolateParams(path, params) {
146
+ if (!params || typeof params !== 'object') return path;
147
+ return path.replace(/:([\w]+)/g, (_, key) => {
148
+ const val = params[key];
149
+ return val != null ? encodeURIComponent(String(val)) : ':' + key;
150
+ });
151
+ }
152
+
125
153
  navigate(path, options = {}) {
154
+ // Interpolate :param placeholders if options.params is provided
155
+ if (options.params) path = this._interpolateParams(path, options.params);
126
156
  // Separate hash fragment (e.g. /docs/getting-started#cli-bundler)
127
157
  const [cleanPath, fragment] = (path || '').split('#');
128
158
  let normalized = this._normalizePath(cleanPath);
@@ -140,6 +170,8 @@ class Router {
140
170
  }
141
171
 
142
172
  replace(path, options = {}) {
173
+ // Interpolate :param placeholders if options.params is provided
174
+ if (options.params) path = this._interpolateParams(path, options.params);
143
175
  const [cleanPath, fragment] = (path || '').split('#');
144
176
  let normalized = this._normalizePath(cleanPath);
145
177
  const hash = fragment ? '#' + fragment : '';
@@ -253,6 +285,7 @@ class Router {
253
285
  // Prevent re-entrant calls (e.g. listener triggering navigation)
254
286
  if (this._resolving) return;
255
287
  this._resolving = true;
288
+ this._redirectCount = 0;
256
289
  try {
257
290
  await this.__resolve();
258
291
  } finally {
@@ -294,7 +327,21 @@ class Router {
294
327
  const result = await guard(to, from);
295
328
  if (result === false) return; // Cancel
296
329
  if (typeof result === 'string') { // Redirect
297
- return this.navigate(result);
330
+ if (++this._redirectCount > 10) {
331
+ reportError(ErrorCode.ROUTER_GUARD, 'Too many guard redirects (possible loop)', { to }, null);
332
+ return;
333
+ }
334
+ // Update URL directly and re-resolve (avoids re-entrancy block)
335
+ const [rPath, rFrag] = result.split('#');
336
+ const rNorm = this._normalizePath(rPath || '/');
337
+ const rHash = rFrag ? '#' + rFrag : '';
338
+ if (this._mode === 'hash') {
339
+ if (rFrag) window.__zqScrollTarget = rFrag;
340
+ window.location.replace('#' + rNorm);
341
+ } else {
342
+ window.history.replaceState({}, '', this._base + rNorm + rHash);
343
+ }
344
+ return this.__resolve();
298
345
  }
299
346
  } catch (err) {
300
347
  reportError(ErrorCode.ROUTER_GUARD, 'Before-guard threw', { to, from }, err);