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.
- package/README.md +6 -6
- package/cli/commands/build.js +3 -3
- package/cli/commands/bundle.js +286 -8
- package/cli/commands/dev/index.js +2 -2
- package/cli/commands/dev/overlay.js +51 -2
- package/cli/commands/dev/server.js +34 -5
- package/cli/commands/dev/watcher.js +33 -0
- package/cli/scaffold/index.html +1 -0
- package/cli/scaffold/scripts/app.js +15 -22
- package/cli/scaffold/scripts/components/contacts/contacts.css +0 -7
- package/cli/scaffold/scripts/components/contacts/contacts.html +3 -3
- package/cli/scaffold/styles/styles.css +1 -0
- package/cli/utils.js +111 -6
- package/dist/zquery.dist.zip +0 -0
- package/dist/zquery.js +379 -27
- package/dist/zquery.min.js +3 -16
- package/index.d.ts +127 -1290
- package/package.json +5 -5
- package/src/component.js +11 -1
- package/src/core.js +305 -10
- package/src/router.js +49 -2
- package/tests/component.test.js +304 -0
- package/tests/core.test.js +726 -0
- package/tests/diff.test.js +194 -0
- package/tests/errors.test.js +162 -0
- package/tests/expression.test.js +334 -0
- package/tests/http.test.js +181 -0
- package/tests/reactive.test.js +191 -0
- package/tests/router.test.js +332 -0
- package/tests/store.test.js +253 -0
- package/tests/utils.test.js +353 -0
- package/types/collection.d.ts +368 -0
- package/types/component.d.ts +210 -0
- package/types/errors.d.ts +103 -0
- package/types/http.d.ts +81 -0
- package/types/misc.d.ts +166 -0
- package/types/reactive.d.ts +76 -0
- package/types/router.d.ts +132 -0
- package/types/ssr.d.ts +49 -0
- package/types/store.d.ts +107 -0
- package/types/utils.d.ts +142 -0
package/dist/zquery.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* zQuery (zeroQuery) v0.
|
|
2
|
+
* zQuery (zeroQuery) v0.7.5
|
|
3
3
|
* Lightweight Frontend Library
|
|
4
4
|
* https://github.com/tonywied17/zero-query
|
|
5
|
-
* (c) 2026 Anthony Wiedman
|
|
5
|
+
* (c) 2026 Anthony Wiedman - MIT License
|
|
6
6
|
*/
|
|
7
7
|
(function(global) {
|
|
8
8
|
'use strict';
|
|
9
9
|
|
|
10
|
-
// --- src/errors.js
|
|
10
|
+
// --- src/errors.js -----------------------------------------------
|
|
11
11
|
/**
|
|
12
12
|
* zQuery Errors — Structured error handling system
|
|
13
13
|
*
|
|
@@ -164,7 +164,7 @@ function validate(value, name, expectedType) {
|
|
|
164
164
|
}
|
|
165
165
|
}
|
|
166
166
|
|
|
167
|
-
// --- src/reactive.js
|
|
167
|
+
// --- src/reactive.js ---------------------------------------------
|
|
168
168
|
/**
|
|
169
169
|
* zQuery Reactive — Proxy-based deep reactivity system
|
|
170
170
|
*
|
|
@@ -315,7 +315,7 @@ function effect(fn) {
|
|
|
315
315
|
};
|
|
316
316
|
}
|
|
317
317
|
|
|
318
|
-
// --- src/core.js
|
|
318
|
+
// --- src/core.js -------------------------------------------------
|
|
319
319
|
/**
|
|
320
320
|
* zQuery Core — Selector engine & chainable DOM collection
|
|
321
321
|
*
|
|
@@ -393,8 +393,96 @@ class ZQueryCollection {
|
|
|
393
393
|
return new ZQueryCollection(sibs);
|
|
394
394
|
}
|
|
395
395
|
|
|
396
|
-
next() {
|
|
397
|
-
|
|
396
|
+
next(selector) {
|
|
397
|
+
const els = this.elements.map(el => el.nextElementSibling).filter(Boolean);
|
|
398
|
+
return new ZQueryCollection(selector ? els.filter(el => el.matches(selector)) : els);
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
prev(selector) {
|
|
402
|
+
const els = this.elements.map(el => el.previousElementSibling).filter(Boolean);
|
|
403
|
+
return new ZQueryCollection(selector ? els.filter(el => el.matches(selector)) : els);
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
nextAll(selector) {
|
|
407
|
+
const result = [];
|
|
408
|
+
this.elements.forEach(el => {
|
|
409
|
+
let sib = el.nextElementSibling;
|
|
410
|
+
while (sib) {
|
|
411
|
+
if (!selector || sib.matches(selector)) result.push(sib);
|
|
412
|
+
sib = sib.nextElementSibling;
|
|
413
|
+
}
|
|
414
|
+
});
|
|
415
|
+
return new ZQueryCollection(result);
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
nextUntil(selector, filter) {
|
|
419
|
+
const result = [];
|
|
420
|
+
this.elements.forEach(el => {
|
|
421
|
+
let sib = el.nextElementSibling;
|
|
422
|
+
while (sib) {
|
|
423
|
+
if (selector && sib.matches(selector)) break;
|
|
424
|
+
if (!filter || sib.matches(filter)) result.push(sib);
|
|
425
|
+
sib = sib.nextElementSibling;
|
|
426
|
+
}
|
|
427
|
+
});
|
|
428
|
+
return new ZQueryCollection(result);
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
prevAll(selector) {
|
|
432
|
+
const result = [];
|
|
433
|
+
this.elements.forEach(el => {
|
|
434
|
+
let sib = el.previousElementSibling;
|
|
435
|
+
while (sib) {
|
|
436
|
+
if (!selector || sib.matches(selector)) result.push(sib);
|
|
437
|
+
sib = sib.previousElementSibling;
|
|
438
|
+
}
|
|
439
|
+
});
|
|
440
|
+
return new ZQueryCollection(result);
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
prevUntil(selector, filter) {
|
|
444
|
+
const result = [];
|
|
445
|
+
this.elements.forEach(el => {
|
|
446
|
+
let sib = el.previousElementSibling;
|
|
447
|
+
while (sib) {
|
|
448
|
+
if (selector && sib.matches(selector)) break;
|
|
449
|
+
if (!filter || sib.matches(filter)) result.push(sib);
|
|
450
|
+
sib = sib.previousElementSibling;
|
|
451
|
+
}
|
|
452
|
+
});
|
|
453
|
+
return new ZQueryCollection(result);
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
parents(selector) {
|
|
457
|
+
const result = [];
|
|
458
|
+
this.elements.forEach(el => {
|
|
459
|
+
let parent = el.parentElement;
|
|
460
|
+
while (parent) {
|
|
461
|
+
if (!selector || parent.matches(selector)) result.push(parent);
|
|
462
|
+
parent = parent.parentElement;
|
|
463
|
+
}
|
|
464
|
+
});
|
|
465
|
+
return new ZQueryCollection([...new Set(result)]);
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
parentsUntil(selector, filter) {
|
|
469
|
+
const result = [];
|
|
470
|
+
this.elements.forEach(el => {
|
|
471
|
+
let parent = el.parentElement;
|
|
472
|
+
while (parent) {
|
|
473
|
+
if (selector && parent.matches(selector)) break;
|
|
474
|
+
if (!filter || parent.matches(filter)) result.push(parent);
|
|
475
|
+
parent = parent.parentElement;
|
|
476
|
+
}
|
|
477
|
+
});
|
|
478
|
+
return new ZQueryCollection([...new Set(result)]);
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
contents() {
|
|
482
|
+
const result = [];
|
|
483
|
+
this.elements.forEach(el => result.push(...el.childNodes));
|
|
484
|
+
return new ZQueryCollection(result);
|
|
485
|
+
}
|
|
398
486
|
|
|
399
487
|
filter(selector) {
|
|
400
488
|
if (typeof selector === 'function') {
|
|
@@ -414,6 +502,42 @@ class ZQueryCollection {
|
|
|
414
502
|
return new ZQueryCollection(this.elements.filter(el => el.querySelector(selector)));
|
|
415
503
|
}
|
|
416
504
|
|
|
505
|
+
is(selector) {
|
|
506
|
+
if (typeof selector === 'function') {
|
|
507
|
+
return this.elements.some((el, i) => selector.call(el, i, el));
|
|
508
|
+
}
|
|
509
|
+
return this.elements.some(el => el.matches(selector));
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
slice(start, end) {
|
|
513
|
+
return new ZQueryCollection(this.elements.slice(start, end));
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
add(selector, context) {
|
|
517
|
+
const toAdd = (selector instanceof ZQueryCollection)
|
|
518
|
+
? selector.elements
|
|
519
|
+
: (selector instanceof Node)
|
|
520
|
+
? [selector]
|
|
521
|
+
: Array.from((context || document).querySelectorAll(selector));
|
|
522
|
+
return new ZQueryCollection([...this.elements, ...toAdd]);
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
get(index) {
|
|
526
|
+
if (index === undefined) return [...this.elements];
|
|
527
|
+
return index < 0 ? this.elements[this.length + index] : this.elements[index];
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
index(selector) {
|
|
531
|
+
if (selector === undefined) {
|
|
532
|
+
const el = this.first();
|
|
533
|
+
return el ? Array.from(el.parentElement.children).indexOf(el) : -1;
|
|
534
|
+
}
|
|
535
|
+
const target = (typeof selector === 'string')
|
|
536
|
+
? document.querySelector(selector)
|
|
537
|
+
: selector;
|
|
538
|
+
return this.elements.indexOf(target);
|
|
539
|
+
}
|
|
540
|
+
|
|
417
541
|
// --- Classes -------------------------------------------------------------
|
|
418
542
|
|
|
419
543
|
addClass(...names) {
|
|
@@ -426,8 +550,12 @@ class ZQueryCollection {
|
|
|
426
550
|
return this.each((_, el) => el.classList.remove(...classes));
|
|
427
551
|
}
|
|
428
552
|
|
|
429
|
-
toggleClass(
|
|
430
|
-
|
|
553
|
+
toggleClass(...args) {
|
|
554
|
+
const force = typeof args[args.length - 1] === 'boolean' ? args.pop() : undefined;
|
|
555
|
+
const classes = args.flatMap(n => n.split(/\s+/));
|
|
556
|
+
return this.each((_, el) => {
|
|
557
|
+
classes.forEach(c => force !== undefined ? el.classList.toggle(c, force) : el.classList.toggle(c));
|
|
558
|
+
});
|
|
431
559
|
}
|
|
432
560
|
|
|
433
561
|
hasClass(name) {
|
|
@@ -481,6 +609,60 @@ class ZQueryCollection {
|
|
|
481
609
|
return el ? { top: el.offsetTop, left: el.offsetLeft } : null;
|
|
482
610
|
}
|
|
483
611
|
|
|
612
|
+
scrollTop(value) {
|
|
613
|
+
if (value === undefined) {
|
|
614
|
+
const el = this.first();
|
|
615
|
+
return el === window ? window.scrollY : el?.scrollTop;
|
|
616
|
+
}
|
|
617
|
+
return this.each((_, el) => {
|
|
618
|
+
if (el === window) window.scrollTo(window.scrollX, value);
|
|
619
|
+
else el.scrollTop = value;
|
|
620
|
+
});
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
scrollLeft(value) {
|
|
624
|
+
if (value === undefined) {
|
|
625
|
+
const el = this.first();
|
|
626
|
+
return el === window ? window.scrollX : el?.scrollLeft;
|
|
627
|
+
}
|
|
628
|
+
return this.each((_, el) => {
|
|
629
|
+
if (el === window) window.scrollTo(value, window.scrollY);
|
|
630
|
+
else el.scrollLeft = value;
|
|
631
|
+
});
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
innerWidth() {
|
|
635
|
+
const el = this.first();
|
|
636
|
+
return el?.clientWidth;
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
innerHeight() {
|
|
640
|
+
const el = this.first();
|
|
641
|
+
return el?.clientHeight;
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
outerWidth(includeMargin = false) {
|
|
645
|
+
const el = this.first();
|
|
646
|
+
if (!el) return undefined;
|
|
647
|
+
let w = el.offsetWidth;
|
|
648
|
+
if (includeMargin) {
|
|
649
|
+
const style = getComputedStyle(el);
|
|
650
|
+
w += parseFloat(style.marginLeft) + parseFloat(style.marginRight);
|
|
651
|
+
}
|
|
652
|
+
return w;
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
outerHeight(includeMargin = false) {
|
|
656
|
+
const el = this.first();
|
|
657
|
+
if (!el) return undefined;
|
|
658
|
+
let h = el.offsetHeight;
|
|
659
|
+
if (includeMargin) {
|
|
660
|
+
const style = getComputedStyle(el);
|
|
661
|
+
h += parseFloat(style.marginTop) + parseFloat(style.marginBottom);
|
|
662
|
+
}
|
|
663
|
+
return h;
|
|
664
|
+
}
|
|
665
|
+
|
|
484
666
|
// --- Content -------------------------------------------------------------
|
|
485
667
|
|
|
486
668
|
html(content) {
|
|
@@ -560,6 +742,73 @@ class ZQueryCollection {
|
|
|
560
742
|
});
|
|
561
743
|
}
|
|
562
744
|
|
|
745
|
+
appendTo(target) {
|
|
746
|
+
const dest = typeof target === 'string' ? document.querySelector(target) : target instanceof ZQueryCollection ? target.first() : target;
|
|
747
|
+
if (dest) this.each((_, el) => dest.appendChild(el));
|
|
748
|
+
return this;
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
prependTo(target) {
|
|
752
|
+
const dest = typeof target === 'string' ? document.querySelector(target) : target instanceof ZQueryCollection ? target.first() : target;
|
|
753
|
+
if (dest) this.each((_, el) => dest.insertBefore(el, dest.firstChild));
|
|
754
|
+
return this;
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
insertAfter(target) {
|
|
758
|
+
const ref = typeof target === 'string' ? document.querySelector(target) : target instanceof ZQueryCollection ? target.first() : target;
|
|
759
|
+
if (ref && ref.parentNode) this.each((_, el) => ref.parentNode.insertBefore(el, ref.nextSibling));
|
|
760
|
+
return this;
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
insertBefore(target) {
|
|
764
|
+
const ref = typeof target === 'string' ? document.querySelector(target) : target instanceof ZQueryCollection ? target.first() : target;
|
|
765
|
+
if (ref && ref.parentNode) this.each((_, el) => ref.parentNode.insertBefore(el, ref));
|
|
766
|
+
return this;
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
replaceAll(target) {
|
|
770
|
+
const targets = typeof target === 'string'
|
|
771
|
+
? Array.from(document.querySelectorAll(target))
|
|
772
|
+
: target instanceof ZQueryCollection ? target.elements : [target];
|
|
773
|
+
targets.forEach((t, i) => {
|
|
774
|
+
const nodes = i === 0 ? this.elements : this.elements.map(el => el.cloneNode(true));
|
|
775
|
+
nodes.forEach(el => t.parentNode.insertBefore(el, t));
|
|
776
|
+
t.remove();
|
|
777
|
+
});
|
|
778
|
+
return this;
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
unwrap(selector) {
|
|
782
|
+
this.elements.forEach(el => {
|
|
783
|
+
const parent = el.parentElement;
|
|
784
|
+
if (!parent || parent === document.body) return;
|
|
785
|
+
if (selector && !parent.matches(selector)) return;
|
|
786
|
+
parent.replaceWith(...parent.childNodes);
|
|
787
|
+
});
|
|
788
|
+
return this;
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
wrapAll(wrapper) {
|
|
792
|
+
const w = typeof wrapper === 'string' ? createFragment(wrapper).firstElementChild : wrapper.cloneNode(true);
|
|
793
|
+
const first = this.first();
|
|
794
|
+
if (!first) return this;
|
|
795
|
+
first.parentNode.insertBefore(w, first);
|
|
796
|
+
this.each((_, el) => w.appendChild(el));
|
|
797
|
+
return this;
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
wrapInner(wrapper) {
|
|
801
|
+
return this.each((_, el) => {
|
|
802
|
+
const w = typeof wrapper === 'string' ? createFragment(wrapper).firstElementChild : wrapper.cloneNode(true);
|
|
803
|
+
while (el.firstChild) w.appendChild(el.firstChild);
|
|
804
|
+
el.appendChild(w);
|
|
805
|
+
});
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
detach() {
|
|
809
|
+
return this.each((_, el) => el.remove());
|
|
810
|
+
}
|
|
811
|
+
|
|
563
812
|
// --- Visibility ----------------------------------------------------------
|
|
564
813
|
|
|
565
814
|
show(display = '') {
|
|
@@ -585,9 +834,10 @@ class ZQueryCollection {
|
|
|
585
834
|
events.forEach(evt => {
|
|
586
835
|
if (typeof selectorOrHandler === 'function') {
|
|
587
836
|
el.addEventListener(evt, selectorOrHandler);
|
|
588
|
-
} else {
|
|
589
|
-
// Delegated event
|
|
837
|
+
} else if (typeof selectorOrHandler === 'string') {
|
|
838
|
+
// Delegated event — only works on elements that support closest()
|
|
590
839
|
el.addEventListener(evt, (e) => {
|
|
840
|
+
if (!e.target || typeof e.target.closest !== 'function') return;
|
|
591
841
|
const target = e.target.closest(selectorOrHandler);
|
|
592
842
|
if (target && el.contains(target)) handler.call(target, e);
|
|
593
843
|
});
|
|
@@ -620,6 +870,10 @@ class ZQueryCollection {
|
|
|
620
870
|
submit(fn) { return fn ? this.on('submit', fn) : this.trigger('submit'); }
|
|
621
871
|
focus() { this.first()?.focus(); return this; }
|
|
622
872
|
blur() { this.first()?.blur(); return this; }
|
|
873
|
+
hover(enterFn, leaveFn) {
|
|
874
|
+
this.on('mouseenter', enterFn);
|
|
875
|
+
return this.on('mouseleave', leaveFn || enterFn);
|
|
876
|
+
}
|
|
623
877
|
|
|
624
878
|
// --- Animation -----------------------------------------------------------
|
|
625
879
|
|
|
@@ -651,6 +905,40 @@ class ZQueryCollection {
|
|
|
651
905
|
return this.animate({ opacity: '0' }, duration).then(col => col.hide());
|
|
652
906
|
}
|
|
653
907
|
|
|
908
|
+
fadeToggle(duration = 300) {
|
|
909
|
+
return Promise.all(this.elements.map(el => {
|
|
910
|
+
const visible = getComputedStyle(el).opacity !== '0' && getComputedStyle(el).display !== 'none';
|
|
911
|
+
const col = new ZQueryCollection([el]);
|
|
912
|
+
return visible ? col.fadeOut(duration) : col.fadeIn(duration);
|
|
913
|
+
})).then(() => this);
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
fadeTo(duration, opacity) {
|
|
917
|
+
return this.animate({ opacity: String(opacity) }, duration);
|
|
918
|
+
}
|
|
919
|
+
|
|
920
|
+
slideDown(duration = 300) {
|
|
921
|
+
return this.each((_, el) => {
|
|
922
|
+
el.style.display = '';
|
|
923
|
+
el.style.overflow = 'hidden';
|
|
924
|
+
const h = el.scrollHeight + 'px';
|
|
925
|
+
el.style.maxHeight = '0';
|
|
926
|
+
el.style.transition = `max-height ${duration}ms ease`;
|
|
927
|
+
requestAnimationFrame(() => { el.style.maxHeight = h; });
|
|
928
|
+
setTimeout(() => { el.style.maxHeight = ''; el.style.overflow = ''; el.style.transition = ''; }, duration);
|
|
929
|
+
});
|
|
930
|
+
}
|
|
931
|
+
|
|
932
|
+
slideUp(duration = 300) {
|
|
933
|
+
return this.each((_, el) => {
|
|
934
|
+
el.style.overflow = 'hidden';
|
|
935
|
+
el.style.maxHeight = el.scrollHeight + 'px';
|
|
936
|
+
el.style.transition = `max-height ${duration}ms ease`;
|
|
937
|
+
requestAnimationFrame(() => { el.style.maxHeight = '0'; });
|
|
938
|
+
setTimeout(() => { el.style.display = 'none'; el.style.maxHeight = ''; el.style.overflow = ''; el.style.transition = ''; }, duration);
|
|
939
|
+
});
|
|
940
|
+
}
|
|
941
|
+
|
|
654
942
|
slideToggle(duration = 300) {
|
|
655
943
|
return this.each((_, el) => {
|
|
656
944
|
if (el.style.display === 'none' || getComputedStyle(el).display === 'none') {
|
|
@@ -798,7 +1086,7 @@ query.children = (parentId) => {
|
|
|
798
1086
|
return new ZQueryCollection(p ? Array.from(p.children) : []);
|
|
799
1087
|
};
|
|
800
1088
|
|
|
801
|
-
// Create element shorthand
|
|
1089
|
+
// Create element shorthand — returns ZQueryCollection for chaining
|
|
802
1090
|
query.create = (tag, attrs = {}, ...children) => {
|
|
803
1091
|
const el = document.createElement(tag);
|
|
804
1092
|
for (const [k, v] of Object.entries(attrs)) {
|
|
@@ -812,7 +1100,7 @@ query.create = (tag, attrs = {}, ...children) => {
|
|
|
812
1100
|
if (typeof child === 'string') el.appendChild(document.createTextNode(child));
|
|
813
1101
|
else if (child instanceof Node) el.appendChild(child);
|
|
814
1102
|
});
|
|
815
|
-
return el;
|
|
1103
|
+
return new ZQueryCollection(el);
|
|
816
1104
|
};
|
|
817
1105
|
|
|
818
1106
|
// DOM ready
|
|
@@ -821,17 +1109,24 @@ query.ready = (fn) => {
|
|
|
821
1109
|
else document.addEventListener('DOMContentLoaded', fn);
|
|
822
1110
|
};
|
|
823
1111
|
|
|
824
|
-
// Global event listeners — supports direct and
|
|
1112
|
+
// Global event listeners — supports direct, delegated, and target-bound forms
|
|
825
1113
|
// $.on('keydown', handler) → direct listener on document
|
|
826
1114
|
// $.on('click', '.btn', handler) → delegated via closest()
|
|
1115
|
+
// $.on('scroll', window, handler) → direct listener on target
|
|
827
1116
|
query.on = (event, selectorOrHandler, handler) => {
|
|
828
1117
|
if (typeof selectorOrHandler === 'function') {
|
|
829
1118
|
// 2-arg: direct document listener (keydown, resize, etc.)
|
|
830
1119
|
document.addEventListener(event, selectorOrHandler);
|
|
831
1120
|
return;
|
|
832
1121
|
}
|
|
833
|
-
//
|
|
1122
|
+
// EventTarget (window, element, etc.) — direct listener on target
|
|
1123
|
+
if (typeof selectorOrHandler === 'object' && typeof selectorOrHandler.addEventListener === 'function') {
|
|
1124
|
+
selectorOrHandler.addEventListener(event, handler);
|
|
1125
|
+
return;
|
|
1126
|
+
}
|
|
1127
|
+
// 3-arg string: delegated
|
|
834
1128
|
document.addEventListener(event, (e) => {
|
|
1129
|
+
if (!e.target || typeof e.target.closest !== 'function') return;
|
|
835
1130
|
const target = e.target.closest(selectorOrHandler);
|
|
836
1131
|
if (target) handler.call(target, e);
|
|
837
1132
|
});
|
|
@@ -845,7 +1140,7 @@ query.off = (event, handler) => {
|
|
|
845
1140
|
// Extend collection prototype (like $.fn in jQuery)
|
|
846
1141
|
query.fn = ZQueryCollection.prototype;
|
|
847
1142
|
|
|
848
|
-
// --- src/expression.js
|
|
1143
|
+
// --- src/expression.js -------------------------------------------
|
|
849
1144
|
/**
|
|
850
1145
|
* zQuery Expression Parser — CSP-safe expression evaluator
|
|
851
1146
|
*
|
|
@@ -1653,7 +1948,7 @@ function safeEval(expr, scope) {
|
|
|
1653
1948
|
}
|
|
1654
1949
|
}
|
|
1655
1950
|
|
|
1656
|
-
// --- src/diff.js
|
|
1951
|
+
// --- src/diff.js -------------------------------------------------
|
|
1657
1952
|
/**
|
|
1658
1953
|
* zQuery Diff — Lightweight DOM morphing engine
|
|
1659
1954
|
*
|
|
@@ -1935,7 +2230,7 @@ function _getKey(node) {
|
|
|
1935
2230
|
return node.getAttribute('z-key') || null;
|
|
1936
2231
|
}
|
|
1937
2232
|
|
|
1938
|
-
// --- src/component.js
|
|
2233
|
+
// --- src/component.js --------------------------------------------
|
|
1939
2234
|
/**
|
|
1940
2235
|
* zQuery Component — Lightweight reactive component system
|
|
1941
2236
|
*
|
|
@@ -2318,11 +2613,14 @@ class Component {
|
|
|
2318
2613
|
if (def.styleUrl && !def._styleLoaded) {
|
|
2319
2614
|
const su = def.styleUrl;
|
|
2320
2615
|
if (typeof su === 'string') {
|
|
2321
|
-
|
|
2616
|
+
const resolved = _resolveUrl(su, base);
|
|
2617
|
+
def._externalStyles = await _fetchResource(resolved);
|
|
2618
|
+
def._resolvedStyleUrls = [resolved];
|
|
2322
2619
|
} else if (Array.isArray(su)) {
|
|
2323
2620
|
const urls = su.map(u => _resolveUrl(u, base));
|
|
2324
2621
|
const results = await Promise.all(urls.map(u => _fetchResource(u)));
|
|
2325
2622
|
def._externalStyles = results.join('\n');
|
|
2623
|
+
def._resolvedStyleUrls = urls;
|
|
2326
2624
|
}
|
|
2327
2625
|
def._styleLoaded = true;
|
|
2328
2626
|
}
|
|
@@ -2449,6 +2747,13 @@ class Component {
|
|
|
2449
2747
|
const styleEl = document.createElement('style');
|
|
2450
2748
|
styleEl.textContent = scoped;
|
|
2451
2749
|
styleEl.setAttribute('data-zq-component', this._def._name || '');
|
|
2750
|
+
styleEl.setAttribute('data-zq-scope', scopeAttr);
|
|
2751
|
+
if (this._def._resolvedStyleUrls) {
|
|
2752
|
+
styleEl.setAttribute('data-zq-style-urls', this._def._resolvedStyleUrls.join(' '));
|
|
2753
|
+
if (this._def.styles) {
|
|
2754
|
+
styleEl.setAttribute('data-zq-inline', this._def.styles);
|
|
2755
|
+
}
|
|
2756
|
+
}
|
|
2452
2757
|
document.head.appendChild(styleEl);
|
|
2453
2758
|
this._styleEl = styleEl;
|
|
2454
2759
|
}
|
|
@@ -3235,7 +3540,7 @@ function style(urls, opts = {}) {
|
|
|
3235
3540
|
};
|
|
3236
3541
|
}
|
|
3237
3542
|
|
|
3238
|
-
// --- src/router.js
|
|
3543
|
+
// --- src/router.js -----------------------------------------------
|
|
3239
3544
|
/**
|
|
3240
3545
|
* zQuery Router — Client-side SPA router
|
|
3241
3546
|
*
|
|
@@ -3315,7 +3620,21 @@ class Router {
|
|
|
3315
3620
|
if (!link) return;
|
|
3316
3621
|
if (link.getAttribute('target') === '_blank') return;
|
|
3317
3622
|
e.preventDefault();
|
|
3318
|
-
|
|
3623
|
+
let href = link.getAttribute('z-link');
|
|
3624
|
+
// Support z-link-params for dynamic :param interpolation
|
|
3625
|
+
const paramsAttr = link.getAttribute('z-link-params');
|
|
3626
|
+
if (paramsAttr) {
|
|
3627
|
+
try {
|
|
3628
|
+
const params = JSON.parse(paramsAttr);
|
|
3629
|
+
href = this._interpolateParams(href, params);
|
|
3630
|
+
} catch { /* ignore malformed JSON */ }
|
|
3631
|
+
}
|
|
3632
|
+
this.navigate(href);
|
|
3633
|
+
// z-to-top modifier: scroll to top after navigation
|
|
3634
|
+
if (link.hasAttribute('z-to-top')) {
|
|
3635
|
+
const scrollBehavior = link.getAttribute('z-to-top') || 'instant';
|
|
3636
|
+
window.scrollTo({ top: 0, behavior: scrollBehavior });
|
|
3637
|
+
}
|
|
3319
3638
|
});
|
|
3320
3639
|
|
|
3321
3640
|
// Initial resolve
|
|
@@ -3359,7 +3678,23 @@ class Router {
|
|
|
3359
3678
|
|
|
3360
3679
|
// --- Navigation ----------------------------------------------------------
|
|
3361
3680
|
|
|
3681
|
+
/**
|
|
3682
|
+
* Interpolate :param placeholders in a path with the given values.
|
|
3683
|
+
* @param {string} path — e.g. '/user/:id/posts/:pid'
|
|
3684
|
+
* @param {Object} params — e.g. { id: 42, pid: 7 }
|
|
3685
|
+
* @returns {string}
|
|
3686
|
+
*/
|
|
3687
|
+
_interpolateParams(path, params) {
|
|
3688
|
+
if (!params || typeof params !== 'object') return path;
|
|
3689
|
+
return path.replace(/:([\w]+)/g, (_, key) => {
|
|
3690
|
+
const val = params[key];
|
|
3691
|
+
return val != null ? encodeURIComponent(String(val)) : ':' + key;
|
|
3692
|
+
});
|
|
3693
|
+
}
|
|
3694
|
+
|
|
3362
3695
|
navigate(path, options = {}) {
|
|
3696
|
+
// Interpolate :param placeholders if options.params is provided
|
|
3697
|
+
if (options.params) path = this._interpolateParams(path, options.params);
|
|
3363
3698
|
// Separate hash fragment (e.g. /docs/getting-started#cli-bundler)
|
|
3364
3699
|
const [cleanPath, fragment] = (path || '').split('#');
|
|
3365
3700
|
let normalized = this._normalizePath(cleanPath);
|
|
@@ -3377,6 +3712,8 @@ class Router {
|
|
|
3377
3712
|
}
|
|
3378
3713
|
|
|
3379
3714
|
replace(path, options = {}) {
|
|
3715
|
+
// Interpolate :param placeholders if options.params is provided
|
|
3716
|
+
if (options.params) path = this._interpolateParams(path, options.params);
|
|
3380
3717
|
const [cleanPath, fragment] = (path || '').split('#');
|
|
3381
3718
|
let normalized = this._normalizePath(cleanPath);
|
|
3382
3719
|
const hash = fragment ? '#' + fragment : '';
|
|
@@ -3490,6 +3827,7 @@ class Router {
|
|
|
3490
3827
|
// Prevent re-entrant calls (e.g. listener triggering navigation)
|
|
3491
3828
|
if (this._resolving) return;
|
|
3492
3829
|
this._resolving = true;
|
|
3830
|
+
this._redirectCount = 0;
|
|
3493
3831
|
try {
|
|
3494
3832
|
await this.__resolve();
|
|
3495
3833
|
} finally {
|
|
@@ -3531,7 +3869,21 @@ class Router {
|
|
|
3531
3869
|
const result = await guard(to, from);
|
|
3532
3870
|
if (result === false) return; // Cancel
|
|
3533
3871
|
if (typeof result === 'string') { // Redirect
|
|
3534
|
-
|
|
3872
|
+
if (++this._redirectCount > 10) {
|
|
3873
|
+
reportError(ErrorCode.ROUTER_GUARD, 'Too many guard redirects (possible loop)', { to }, null);
|
|
3874
|
+
return;
|
|
3875
|
+
}
|
|
3876
|
+
// Update URL directly and re-resolve (avoids re-entrancy block)
|
|
3877
|
+
const [rPath, rFrag] = result.split('#');
|
|
3878
|
+
const rNorm = this._normalizePath(rPath || '/');
|
|
3879
|
+
const rHash = rFrag ? '#' + rFrag : '';
|
|
3880
|
+
if (this._mode === 'hash') {
|
|
3881
|
+
if (rFrag) window.__zqScrollTarget = rFrag;
|
|
3882
|
+
window.location.replace('#' + rNorm);
|
|
3883
|
+
} else {
|
|
3884
|
+
window.history.replaceState({}, '', this._base + rNorm + rHash);
|
|
3885
|
+
}
|
|
3886
|
+
return this.__resolve();
|
|
3535
3887
|
}
|
|
3536
3888
|
} catch (err) {
|
|
3537
3889
|
reportError(ErrorCode.ROUTER_GUARD, 'Before-guard threw', { to, from }, err);
|
|
@@ -3610,7 +3962,7 @@ function getRouter() {
|
|
|
3610
3962
|
return _activeRouter;
|
|
3611
3963
|
}
|
|
3612
3964
|
|
|
3613
|
-
// --- src/store.js
|
|
3965
|
+
// --- src/store.js ------------------------------------------------
|
|
3614
3966
|
/**
|
|
3615
3967
|
* zQuery Store — Global reactive state management
|
|
3616
3968
|
*
|
|
@@ -3796,7 +4148,7 @@ function getStore(name = 'default') {
|
|
|
3796
4148
|
return _stores.get(name) || null;
|
|
3797
4149
|
}
|
|
3798
4150
|
|
|
3799
|
-
// --- src/http.js
|
|
4151
|
+
// --- src/http.js -------------------------------------------------
|
|
3800
4152
|
/**
|
|
3801
4153
|
* zQuery HTTP — Lightweight fetch wrapper
|
|
3802
4154
|
*
|
|
@@ -3983,7 +4335,7 @@ const http = {
|
|
|
3983
4335
|
raw: (url, opts) => fetch(url, opts),
|
|
3984
4336
|
};
|
|
3985
4337
|
|
|
3986
|
-
// --- src/utils.js
|
|
4338
|
+
// --- src/utils.js ------------------------------------------------
|
|
3987
4339
|
/**
|
|
3988
4340
|
* zQuery Utils — Common utility functions
|
|
3989
4341
|
*
|
|
@@ -4256,7 +4608,7 @@ class EventBus {
|
|
|
4256
4608
|
|
|
4257
4609
|
const bus = new EventBus();
|
|
4258
4610
|
|
|
4259
|
-
// --- index.js (assembly)
|
|
4611
|
+
// --- index.js (assembly) ------------------------------------------
|
|
4260
4612
|
/**
|
|
4261
4613
|
* ┌---------------------------------------------------------┐
|
|
4262
4614
|
* │ zQuery (zeroQuery) — Lightweight Frontend Library │
|
|
@@ -4399,7 +4751,7 @@ $.ZQueryError = ZQueryError;
|
|
|
4399
4751
|
$.ErrorCode = ErrorCode;
|
|
4400
4752
|
|
|
4401
4753
|
// --- Meta ------------------------------------------------------------------
|
|
4402
|
-
$.version = '0.
|
|
4754
|
+
$.version = '0.7.5';
|
|
4403
4755
|
$.meta = {}; // populated at build time by CLI bundler
|
|
4404
4756
|
|
|
4405
4757
|
$.noConflict = () => {
|