/** * Wait for an element to be added to the DOM or shadow DOM. * @param {ShadowRoot | Document} root - The root to observe. * @param {string} selector - The selector of the element to wait for. * @param {number} [timeout] - The time in milliseconds to wait before rejecting the promise. * @return {Promise} - A promise that resolves with the element when it is added to the DOM or shadow DOM. */ function waitForElement(root, selector, timeout = 1000) { let timeoutId; return new Promise((resolve, reject) => { let element = root.querySelector(selector); if (element) { resolve(element); return; } const observer = new MutationObserver((mutations) => { mutations.forEach((mutation) => { if (mutation.type !== "childList") { return; } mutation.addedNodes.forEach((node) => { if (node.nodeType !== Node.ELEMENT_NODE) { return; } if (node.matches(selector)) { observer.disconnect(); clearTimeout(timeoutId); resolve(node); return; } const shadowElement = node?.shadowRoot?.querySelector(selector); if (shadowElement) { observer.disconnect(); clearTimeout(timeoutId); resolve(shadowElement); return; } if (node.shadowRoot) { observer.observe(node.shadowRoot, { childList: true, subtree: true, }); } element = root.querySelector(selector); if (element) { observer.disconnect(); clearTimeout(timeoutId); resolve(element); } }); }); }); observer.observe(root, { childList: true, subtree: true }); timeoutId = setTimeout(() => { observer.disconnect(); reject(new Error(`Element not found: ${selector}`)); }, timeout); }); } export default waitForElement;