@cocreate/utils 1.37.3 → 1.38.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 (3) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/package.json +1 -1
  3. package/src/index.js +168 -118
package/CHANGELOG.md CHANGED
@@ -1,3 +1,19 @@
1
+ # [1.38.0](https://github.com/CoCreate-app/CoCreate-utils/compare/v1.37.3...v1.38.0) (2025-04-11)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * query elements ([663eec4](https://github.com/CoCreate-app/CoCreate-utils/commit/663eec46c92716c298e45cd4fa6ec48be616a9a1))
7
+ * Selector === "" retuning null ([e8fd9fb](https://github.com/CoCreate-app/CoCreate-utils/commit/e8fd9fb726f78477e9ea5a15e9bf08097bc9250f))
8
+ * special selector split ([94dd267](https://github.com/CoCreate-app/CoCreate-utils/commit/94dd267d4028945c9813c4bc7be33bcc7d0494d3))
9
+ * variable typo selector ([fe101f5](https://github.com/CoCreate-app/CoCreate-utils/commit/fe101f5a9c728d054466b21524cfc2b0ece07e8a))
10
+
11
+
12
+ ### Features
13
+
14
+ * improve queryElements() ([0e05425](https://github.com/CoCreate-app/CoCreate-utils/commit/0e05425fc68394004ef2c78f3bd2004447b2233a))
15
+ * prefix-document to query document ([21644d9](https://github.com/CoCreate-app/CoCreate-utils/commit/21644d940e1f20530f5594b751d596b4aa431fc4))
16
+
1
17
  ## [1.37.3](https://github.com/CoCreate-app/CoCreate-utils/compare/v1.37.2...v1.37.3) (2024-12-22)
2
18
 
3
19
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cocreate/utils",
3
- "version": "1.37.3",
3
+ "version": "1.38.0",
4
4
  "description": "A simple utils component in vanilla javascript. Easily configured using HTML5 attributes and/or JavaScript API.",
5
5
  "keywords": [
6
6
  "utils",
package/src/index.js CHANGED
@@ -540,131 +540,142 @@
540
540
  return path;
541
541
  }
542
542
 
543
- function queryElements({ element, prefix, type, selector }) {
544
- let elements = new Map();
545
- if (!element) element = document;
543
+ const queryTypes = [
544
+ "selector",
545
+ "closest",
546
+ "parent",
547
+ "next",
548
+ "previous",
549
+ "document",
550
+ "frame",
551
+ "top"
552
+ ];
553
+
554
+ const queryTypesRegex = new RegExp(`\\$(?:${queryTypes.join("|")})\\b`); // Find the *first* match
555
+
556
+ function queryElements({ element = document, prefix, type, selector }) {
557
+ let elements = new Set();
558
+
546
559
  let hasAttribute = false;
547
560
 
548
- if (selector) {
549
- if (!type) type = ["selector"];
550
- else if (!Array.isArray(type)) type = [type];
551
- } else type = ["selector", "closest", "parent", "next", "previous"];
561
+ if (!selector) {
562
+ if (!prefix && element.nodeType === 1) {
563
+ for (let attr of element.attributes) {
564
+ let parts = attr.name.split("-");
565
+ if (parts.length < 2) continue;
566
+
567
+ let possibleType = parts.pop();
568
+ if (queryTypes.includes(possibleType)) {
569
+ type = [possibleType];
570
+ prefix = parts.join("-");
571
+ break;
572
+ }
573
+ }
574
+ if (!prefix) return false;
575
+ } else if (!type && element.nodeType === 1) {
576
+ for (let i = 0; i < queryTypes.length; i++) {
577
+ if (element.hasAttribute(`${prefix}-${queryTypes[i]}`)) {
578
+ type = [queryTypes[i]];
579
+ }
580
+ }
581
+ }
582
+ }
583
+
584
+ if (!type) type = selector ? ["selector"] : queryTypes;
585
+
586
+ if (!Array.isArray(type)) type = [type];
552
587
 
553
588
  for (let i = 0; i < type.length; i++) {
554
- let Selector = selector;
555
- if (!Selector && element.nodeType !== 9) {
589
+ if (!selector && element.nodeType !== 9) {
556
590
  let name = prefix + "-" + type[i];
557
591
  if (!element.hasAttribute(name)) continue;
558
592
  hasAttribute = true;
559
- Selector = element.getAttribute(name);
593
+ selector = element.getAttribute(name);
594
+ type = [type[i]];
595
+ }
596
+
597
+ let mainElement = element;
598
+ if (
599
+ [
600
+ "parent",
601
+ "next",
602
+ "previous",
603
+ "document",
604
+ "frame",
605
+ "top"
606
+ ].includes(type[i])
607
+ ) {
608
+ mainElement = queryType(mainElement, type[i]);
560
609
  }
561
610
 
562
- if (Selector) {
563
- let selectors = Selector.split(/,(?![^()]*\))/g);
611
+ if (!selector) {
612
+ elements.add(mainElement);
613
+ } else {
614
+ let selectors = selector.split(/,(?![^()]*\))/g);
564
615
 
565
616
  for (let j = 0; j < selectors.length; j++) {
617
+ if (!selectors[j]) continue;
618
+
619
+ let queriedElement = mainElement;
620
+
566
621
  if (selectors[j].includes("@")) {
567
622
  selectors[j] = checkMediaQueries(selectors[j]);
568
623
  if (selectors[j] === false) continue;
569
624
  }
570
625
 
571
- let queriedElement = element;
572
- let specialSelectors = selectors[j].split(";");
573
- for (let k = 0; k < specialSelectors.length; k++) {
574
- // TODO: Support an array of queried elements and branch off to return matches for each
575
- // if (!Array.isArray(queriedElement)) {
576
- // queriedElement = [queriedElement]
577
- // }
578
-
579
- if (!specialSelectors[k]) continue;
580
- if (k === 0) {
581
- if (type[i] === "parent")
582
- queriedElement = queriedElement.parentElement;
583
- else if (type[i] === "next")
584
- queriedElement =
585
- queriedElement.nextElementSibling;
586
- else if (type[i] === "previous")
587
- queriedElement =
588
- queriedElement.previousElementSibling;
589
- } else if (queriedElement.contentDocument) {
590
- queriedElement = queriedElement.contentDocument;
591
- }
626
+ if (type[i] === "closest") {
627
+ let [closestSelector, remainingSelector = ""] =
628
+ selectors[j].split(/\s+/, 2);
629
+ queriedElement =
630
+ queriedElement.closest(closestSelector);
592
631
 
593
- switch (
594
- (specialSelectors[k] = specialSelectors[k].trim())
595
- ) {
596
- case "top":
597
- queriedElement = window.top.document;
598
- break;
599
- case "frame":
600
- if (queriedElement.nodeType === 9)
601
- queriedElement =
602
- queriedElement.window.frameElement;
603
- else if (queriedElement.contentDocument)
604
- queriedElement =
605
- queriedElement.contentDocument;
606
- break;
607
- case "document":
608
- queriedElement = document;
609
- break;
610
- case "parent":
611
- queriedElement = queriedElement.parentElement;
612
- break;
613
- case "next":
614
- queriedElement =
615
- queriedElement.nextElementSibling;
616
- break;
617
- case "previous":
618
- queriedElement =
619
- queriedElement.previousElementSibling;
620
- break;
621
- default:
622
- if (k === 0 && type[i] === "closest")
623
- if (specialSelectors[k].includes(" ")) {
624
- let [firstSelector, ...restSelectors] =
625
- specialSelectors[k].split(/ (.+)/);
626
- queriedElement =
627
- queriedElement.closest(
628
- firstSelector
629
- );
630
- if (restSelectors.length > 0) {
631
- if (restSelectors[0].endsWith("[]"))
632
- queriedElement =
633
- queriedElement.querySelectorAll(
634
- restSelectors[0].slice(
635
- 0,
636
- -2
637
- )
638
- );
639
- else
640
- queriedElement =
641
- queriedElement.querySelector(
642
- restSelectors[0]
643
- );
644
- }
645
- } else {
646
- // If no space, just use the selector with closest
647
- queriedElement = queriedElement.closest(
648
- specialSelectors[k]
649
- );
650
- }
651
- else if (
652
- specialSelectors[k] === "$clickedElement"
653
- ) {
654
- queriedElement =
655
- queriedElement.clickedElement;
656
- } else if (specialSelectors[k].endsWith("[]"))
657
- queriedElement =
658
- queriedElement.querySelectorAll(
659
- specialSelectors[k].slice(0, -2)
660
- );
661
- else
662
- queriedElement =
663
- queriedElement.querySelector(
664
- specialSelectors[k]
665
- );
632
+ if (!queriedElement) continue;
633
+
634
+ selectors[j] = remainingSelector;
635
+ }
636
+
637
+ let remainingSelector = selectors[j].trim();
638
+ let match;
639
+
640
+ while (
641
+ (match = queryTypesRegex.exec(remainingSelector)) !==
642
+ null
643
+ ) {
644
+ const matchIndex = match.index;
645
+ const operator = match[0];
646
+
647
+ // Process the part before the operator (if any)
648
+ const part = remainingSelector
649
+ .substring(0, matchIndex)
650
+ .trim()
651
+ .replace(/,$/, "");
652
+ if (part) {
653
+ queriedElement = querySelector(
654
+ queriedElement,
655
+ part
656
+ );
657
+ if (!queriedElement) break;
666
658
  }
659
+
660
+ // Process the operator
661
+ queriedElement = queryType(
662
+ queriedElement,
663
+ operator.substring(1)
664
+ );
667
665
  if (!queriedElement) break;
666
+
667
+ // Remove the processed part and operator from the remaining selector
668
+ remainingSelector = remainingSelector
669
+ .substring(matchIndex + operator.length)
670
+ .trim();
671
+ }
672
+
673
+ // Process the remaining part after the last operator (if any)
674
+ if (remainingSelector) {
675
+ queriedElement = querySelector(
676
+ queriedElement,
677
+ remainingSelector.trim().replace(/,$/, "")
678
+ );
668
679
  }
669
680
 
670
681
  if (
@@ -672,27 +683,66 @@
672
683
  queriedElement instanceof HTMLCollection ||
673
684
  queriedElement instanceof NodeList
674
685
  ) {
675
- for (let el of queriedElement) elements.set(el, "");
676
- } else if (queriedElement) {
677
- elements.set(queriedElement, "");
686
+ for (let el of queriedElement) {
687
+ if (el instanceof Element) {
688
+ elements.add(el);
689
+ }
690
+ }
691
+ } else if (queriedElement instanceof Element) {
692
+ elements.add(queriedElement);
678
693
  }
679
694
  }
680
- } else if (Selector === "") {
681
- if (type[i] === "parent")
682
- elements.set(element.parentElement, "");
683
- else if (type[i] === "next")
684
- elements.set(element.nextElementSibling, "");
685
- else if (type[i] === "previous")
686
- elements.set(element.previousElementSibling, "");
687
695
  }
688
696
  }
689
697
 
690
- if (!hasAttribute && !selector) elements = false;
691
- else elements = Array.from(elements.keys());
698
+ if (!hasAttribute && !selector) {
699
+ elements = false;
700
+ } else {
701
+ elements = Array.from(elements);
702
+ }
692
703
 
693
704
  return elements;
694
705
  }
695
706
 
707
+ function queryType(element, type) {
708
+ if (!element) return null;
709
+
710
+ switch (type) {
711
+ case "top":
712
+ return window.top.document;
713
+ case "frame":
714
+ // ✅ If element is a document, return the iframe element containing it
715
+ if (element.nodeType === 9) return window.frameElement;
716
+ // ✅ If element is an iframe, return it as is
717
+ return element;
718
+ case "document":
719
+ // ✅ If element is a document, return itself, else return `ownerDocument`
720
+ return element.nodeType === 9 ? element : element.ownerDocument;
721
+ case "parent":
722
+ // ✅ If it's a document, return the parent document (if inside an iframe)
723
+ if (element.nodeType === 9) {
724
+ return element.defaultView !== window.top
725
+ ? element.defaultView.parent.document
726
+ : null;
727
+ }
728
+ // ✅ Otherwise, return parent element
729
+ return element.parentElement;
730
+ case "next":
731
+ return element.nextElementSibling;
732
+ case "previous":
733
+ return element.previousElementSibling;
734
+ default:
735
+ return null;
736
+ }
737
+ }
738
+
739
+ function querySelector(element, selector) {
740
+ if (!element) return null;
741
+ return selector.endsWith("[]")
742
+ ? element.querySelectorAll(selector.slice(0, -2))
743
+ : element.querySelector(selector);
744
+ }
745
+
696
746
  const mediaRanges = {
697
747
  xs: [0, 575],
698
748
  sm: [576, 768],