shadow.js 2.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051
  1. /**
  2. * Traverses the slots of the open shadowroots and returns all children matching the query.
  3. * @param {ShadowRoot | HTMLElement} root
  4. * @param skipNode
  5. * @param isMatch
  6. * @param {number} maxDepth
  7. * @param {number} depth
  8. * @returns {HTMLElement[]}
  9. */
  10. export function queryShadowRoot(root, skipNode, isMatch, maxDepth = 20, depth = 0) {
  11. let matches = [];
  12. // If the depth is above the max depth, abort the searching here.
  13. if (depth >= maxDepth) {
  14. return matches;
  15. }
  16. // Traverses a slot element
  17. const traverseSlot = ($slot) => {
  18. // Only check nodes that are of the type Node.ELEMENT_NODE
  19. // Read more here https://developer.mozilla.org/en-US/docs/Web/API/Node/nodeType
  20. const assignedNodes = $slot.assignedNodes().filter(node => node.nodeType === 1);
  21. if (assignedNodes.length > 0) {
  22. return queryShadowRoot(assignedNodes[0].parentElement, skipNode, isMatch, maxDepth, depth + 1);
  23. }
  24. return [];
  25. };
  26. // Go through each child and continue the traversing if necessary
  27. // Even though the typing says that children can't be undefined, Edge 15 sometimes gives an undefined value.
  28. // Therefore we fallback to an empty array if it is undefined.
  29. const children = Array.from(root.children || []);
  30. for (const $child of children) {
  31. // Check if the node and its descendants should be skipped
  32. if (skipNode($child)) {
  33. continue;
  34. }
  35. // If the child matches we always add it
  36. if (isMatch($child)) {
  37. matches.push($child);
  38. }
  39. if ($child.shadowRoot != null) {
  40. matches.push(...queryShadowRoot($child.shadowRoot, skipNode, isMatch, maxDepth, depth + 1));
  41. }
  42. else if ($child.tagName === "SLOT") {
  43. matches.push(...traverseSlot($child));
  44. }
  45. else {
  46. matches.push(...queryShadowRoot($child, skipNode, isMatch, maxDepth, depth + 1));
  47. }
  48. }
  49. return matches;
  50. }
  51. //# sourceMappingURL=shadow.js.map