@semantic-ui/query
Advanced tools
Comparing version 0.0.20 to 0.0.21
@@ -12,5 +12,5 @@ { | ||
"dependencies": { | ||
"@semantic-ui/utils": "^0.0.20" | ||
"@semantic-ui/utils": "^0.0.21" | ||
}, | ||
"version": "0.0.20" | ||
"version": "0.0.21" | ||
} |
123
src/query.js
@@ -13,3 +13,3 @@ import { isPlainObject, isString, isArray, isDOM, isFunction, findIndex, inArray, isObject, each } from '@semantic-ui/utils'; | ||
constructor(selector, { root = document, pierceShadow = true } = {}) { | ||
constructor(selector, { root = document, pierceShadow = false } = {}) { | ||
let elements = []; | ||
@@ -57,39 +57,77 @@ | ||
querySelectorAllDeep(root, selector, { includeRoot = true } = {}) { | ||
const elements = new Set(); | ||
const domSelector = isDOM(selector); | ||
const stringSelector = isString(selector); | ||
const addElement = (node) => { | ||
if(node == root && !includeRoot) { | ||
return; | ||
/* Note this is a naive implementation for performance reasons | ||
we will add all elements across shadow root boundaries but without | ||
matching complex selectors that would match ACROSS shadow root boundaries | ||
*/ | ||
querySelectorAllDeep(root, selector, includeRoot = true) { | ||
let elements = []; | ||
let domSelector = isDOM(selector); | ||
let domFound = false; | ||
let queriedRoot; | ||
// add root if required | ||
if (includeRoot) { | ||
if(domSelector && root == selector) { | ||
elements.push(root); | ||
} | ||
elements.add(node); | ||
}; | ||
const findElements = (node) => { | ||
if (node.nodeType === Node.ELEMENT_NODE) { | ||
if (domSelector) { | ||
if(node == selector) { | ||
addElement(node); | ||
} | ||
else if(root.matches && root.matches(selector)) { | ||
elements.push(root); | ||
} | ||
} | ||
// query from root | ||
if(domSelector) { | ||
queriedRoot = true; | ||
} | ||
else if(root.querySelectorAll) { | ||
elements.push(...root.querySelectorAll(selector)); | ||
queriedRoot = true; | ||
} | ||
else { | ||
queriedRoot = false; | ||
} | ||
const addElements = (node) => { | ||
if(domSelector && (node === selector || node.contains)) { | ||
if(node.contains(selector)) { | ||
elements.push(selector); | ||
domFound = true; | ||
} | ||
else if (stringSelector && node.matches(selector)) { | ||
addElement(node); | ||
} | ||
else if (node.shadowRoot) { | ||
findElements(node.shadowRoot); | ||
} | ||
} | ||
else if(node.querySelectorAll) { | ||
elements.push(...node.querySelectorAll(selector)); | ||
} | ||
}; | ||
const findElements = (node, query) => { | ||
// if we are querying for a DOM element we can stop searching once we've found it | ||
if(domFound) { | ||
return; | ||
} | ||
// if root element did not support querySelectorAll | ||
// we query each child node then stop | ||
if(query === true) { | ||
addElements(node); | ||
queriedRoot = true; | ||
} | ||
// query at each shadow root | ||
if (node.nodeType === Node.ELEMENT_NODE && node.shadowRoot) { | ||
addElements(node.shadowRoot); | ||
findElements(node.shadowRoot, !queriedRoot); | ||
} | ||
if(node.assignedNodes) { | ||
each(node.assignedNodes(), node => { | ||
findElements(node); | ||
}); | ||
node.assignedNodes().forEach((node) => findElements(node, queriedRoot)); | ||
} | ||
if (node.childNodes) { | ||
node.childNodes.forEach((childNode) => { | ||
findElements(childNode); | ||
}); | ||
if (node.childNodes.length) { | ||
node.childNodes.forEach((node) => findElements(node, queriedRoot)); | ||
} | ||
}; | ||
findElements(root); | ||
return Array.from(elements); | ||
return [...new Set(elements)]; | ||
} | ||
@@ -114,3 +152,3 @@ | ||
if (this.options.pierceShadow) { | ||
return this.querySelectorAllDeep(el, selector, {includeRoot: false }); | ||
return this.querySelectorAllDeep(el, selector, false); | ||
} else { | ||
@@ -225,3 +263,4 @@ return Array.from(el.querySelectorAll(selector)); | ||
return this.closestDeep(el, selector); | ||
} else { | ||
} | ||
else { | ||
return el.closest(selector); | ||
@@ -236,4 +275,6 @@ } | ||
let currentElement = element; | ||
const domSelector = isDOM(selector); | ||
const stringSelector = isString(selector); | ||
while (currentElement) { | ||
if (currentElement.matches(selector)) { | ||
if ((domSelector && currentElement === selector) || (stringSelector && currentElement.matches(selector))) { | ||
return currentElement; | ||
@@ -243,5 +284,7 @@ } | ||
currentElement = currentElement.parentElement; | ||
} else if (currentElement.parentNode && currentElement.parentNode.host) { | ||
} | ||
else if (currentElement.parentNode && currentElement.parentNode.host) { | ||
currentElement = currentElement.parentNode.host; | ||
} else { | ||
} | ||
else { | ||
return; | ||
@@ -279,3 +322,3 @@ } | ||
const target = e.target.closest(targetSelector); | ||
if (target && this.chain(el).find(target).length) { | ||
if (target) { | ||
handler.call(target, e); | ||
@@ -590,5 +633,9 @@ } | ||
}); | ||
} else { | ||
} | ||
else { | ||
// Get the property value from elements | ||
if (this.length === 1) { | ||
if(this.length == 0) { | ||
return undefined; | ||
} | ||
else if (this.length === 1) { | ||
return this[0][name]; | ||
@@ -595,0 +642,0 @@ } else { |
@@ -67,2 +67,3 @@ import { describe, beforeEach, expect, it, vi } from 'vitest'; | ||
}); | ||
it('should accept a custom element as a selector', () => { | ||
@@ -279,2 +280,37 @@ class CustomElement extends HTMLElement {} | ||
describe('closestDeep', () => { | ||
it('should return the closest ancestor matching a selector', () => { | ||
const div = document.createElement('div'); | ||
const span = document.createElement('span'); | ||
div.appendChild(span); | ||
document.body.appendChild(div); | ||
const $span = $('span', { pierceShadow: true }); | ||
const $closest = $span.closest('div'); | ||
expect($closest.get(0)).toBe(div); | ||
}); | ||
it('should return the closest ancestor matching a DOM element', () => { | ||
const div = document.createElement('div'); | ||
const span = document.createElement('span'); | ||
div.appendChild(span); | ||
document.body.appendChild(div); | ||
const $span = $('span', { pierceShadow: true }); | ||
const $closest = $span.closest(div); | ||
expect($closest.get(0)).toBe(div); | ||
}); | ||
it('should return an empty Query instance if no matching ancestor is found', () => { | ||
const div = document.createElement('div'); | ||
const span = document.createElement('span'); | ||
div.appendChild(span); | ||
document.body.appendChild(div); | ||
const $span = $('span', { pierceShadow: true }); | ||
const $closest = $span.closest('p'); | ||
expect($closest.length).toBe(0); | ||
}); | ||
}); | ||
describe('filter', () => { | ||
@@ -281,0 +317,0 @@ |
71160
1804
+ Added@semantic-ui/utils@0.0.21(transitive)
- Removed@semantic-ui/utils@0.0.20(transitive)
Updated@semantic-ui/utils@^0.0.21