UNPKG

@esri/calcite-components

Version:

Web Components for Esri's Calcite Design System.

138 lines (137 loc) 5.31 kB
import { CSS_UTILITY } from "./resources"; import { guid } from "./guid"; /** * This helper will guarantee an ID on the provided element. * * If it already has an ID, it will be preserved, otherwise a unique one will be generated and assigned. * * @returns {string} The element's ID. */ export function ensureId(el) { if (!el) { return ""; } return (el.id = el.id || `${el.tagName.toLowerCase()}-${guid()}`); } export function nodeListToArray(nodeList) { return Array.isArray(nodeList) ? nodeList : Array.from(nodeList); } export function getAttributes(el, blockList) { return Array.from(el.attributes) .filter((a) => a && !blockList.includes(a.name)) .reduce((acc, { name, value }) => (Object.assign(Object.assign({}, acc), { [name]: value })), {}); } export function getThemeName(el) { return closestElementCrossShadowBoundary(`.${CSS_UTILITY.darkTheme}`, el) ? "dark" : "light"; } export function getElementDir(el) { return getElementProp(el, "dir", "ltr", true); } export function getElementProp(el, prop, fallbackValue, crossShadowBoundary = false) { const selector = `[${prop}]`; const closest = crossShadowBoundary ? closestElementCrossShadowBoundary(selector, el) : el.closest(selector); return closest ? closest.getAttribute(prop) : fallbackValue; } export function getRootNode(el) { return el.getRootNode(); } export function getHost(root) { return root.host || null; } // Queries an element's rootNode and any ancestor rootNodes. // based on https://stackoverflow.com/q/54520554/194216 export function queryElementsRoots(element, selector) { // Gets the rootNode and any ancestor rootNodes (shadowRoot or document) of an element and queries them for a selector. function queryFromAll(el, allResults) { if (!el) { return allResults; } if (el.assignedSlot) { el = el.assignedSlot; } const rootNode = getRootNode(el); const results = Array.from(rootNode.querySelectorAll(selector)); const uniqueResults = results.filter((result) => !allResults.includes(result)); allResults = [...allResults, ...uniqueResults]; const host = getHost(rootNode); return host ? queryFromAll(host, allResults) : allResults; } return queryFromAll(element, []); } // Queries an element's rootNode and any ancestor rootNodes. // based on https://stackoverflow.com/q/54520554/194216 export function queryElementRoots(element, selector) { // Gets the rootNode and any ancestor rootNodes (shadowRoot or document) of an element and queries them for a selector. function queryFrom(el) { if (!el) { return null; } if (el.assignedSlot) { el = el.assignedSlot; } const rootNode = getRootNode(el); const found = rootNode.querySelector(selector); const host = getHost(rootNode); return found ? found : host ? queryFrom(host) : null; } return queryFrom(element); } function closestElementCrossShadowBoundary(selector, base = this) { // based on https://stackoverflow.com/q/54520554/194216 function closestFrom(el) { if (!el || el === document || el === window) { return null; } const found = el.closest(selector); return found ? found : closestFrom(el.getRootNode().host); } return closestFrom(base); } export function isCalciteFocusable(el) { return typeof (el === null || el === void 0 ? void 0 : el.setFocus) === "function"; } export async function focusElement(el) { if (!el) { return; } return isCalciteFocusable(el) ? el.setFocus() : el.focus(); } export function getSlotted(element, slotName, options) { const slotSelector = `[slot="${slotName}"]`; if (options === null || options === void 0 ? void 0 : options.all) { return queryMultiple(element, slotSelector, options); } return querySingle(element, slotSelector, options); } function queryMultiple(element, slotSelector, options) { let matches = Array.from(element.querySelectorAll(slotSelector)); matches = options && options.direct === false ? matches : matches.filter((el) => el.parentElement === element); const selector = options === null || options === void 0 ? void 0 : options.selector; return selector ? matches .map((item) => Array.from(item.querySelectorAll(selector))) .reduce((previousValue, currentValue) => [...previousValue, ...currentValue], []) .filter((match) => !!match) : matches; } function querySingle(element, slotSelector, options) { let match = element.querySelector(slotSelector); match = options && options.direct === false ? match : (match === null || match === void 0 ? void 0 : match.parentElement) === element ? match : null; const selector = options === null || options === void 0 ? void 0 : options.selector; return selector ? match.querySelector(selector) : match; } export function filterDirectChildren(el, selector) { return Array.from(el.children).filter((child) => child.matches(selector)); } export function hasLabel(labelEl, el) { return labelEl.contains(el); } // set a default icon from a defined set or allow an override with an icon name string export function setRequestedIcon(iconObject, iconValue, matchedValue) { if (typeof iconValue === "string" && iconValue !== "") { return iconValue; } else if (iconValue === "") { return iconObject[matchedValue]; } }