UNPKG

@atlaskit/editor-common

Version:

A package that contains common classes and components for editor and renderer

114 lines (104 loc) 4.95 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.popupWithNestedElement = exports.getSelectionAncestorDOM = exports.getPopupContainerFromEditorView = exports.getNodeQuery = exports.containsPopupWithNestedElement = void 0; /** * Finds the direct child of the ProseMirror root element that contains the current selection. * * Starting from the DOM node at the selection position, this function walks up the DOM tree * until it reaches the ProseMirror root, then returns the last element before the root * (i.e., the second top-level ancestor). * * This is useful for attaching MutationObservers to the narrowest subtree that contains * the selection, while still capturing all relevant mutations within that branch. * * @param editorView - The ProseMirror EditorView instance * @returns The direct child of PM root containing the selection, or null if not found */ var getSelectionAncestorDOM = exports.getSelectionAncestorDOM = function getSelectionAncestorDOM(editorView) { if (!editorView) { return null; } var pmDom = editorView.dom; var selection = editorView.state.selection; // nodeDOM can return null when editor loses focus (e.g. toolbar click) or for certain positions. // Fall back to domAtPos which resolves the DOM node at the given position. var currentNode = editorView.nodeDOM(selection.from); if (!currentNode) { try { var _editorView$domAtPos = editorView.domAtPos(selection.from), node = _editorView$domAtPos.node; currentNode = node instanceof HTMLElement ? node : node.parentElement; } catch (_unused) { return null; } } var lastValidAncestor = currentNode; while (currentNode instanceof HTMLElement && currentNode !== pmDom) { lastValidAncestor = currentNode; currentNode = currentNode.parentElement; } return lastValidAncestor instanceof HTMLElement ? lastValidAncestor : null; }; /** * Checks if a given node contains a popup with a nested element identified by a specific test ID. * * @param node - The node to check. * @param nestedElementQuery - The query to look for the nested element. * @returns True if the node contains the popup, false otherwise. */ var containsPopupWithNestedElement = exports.containsPopupWithNestedElement = function containsPopupWithNestedElement(node, nestedElementQuery) { if (!(node instanceof HTMLElement)) { return false; } // Check if node itself has the popup attribute and contains the element matching the nestedElementQuery if (node.matches('[data-editor-popup="true"]')) { return !!node.querySelector(nestedElementQuery); } // Check if any direct child with popup attribute contains the element matching the nestedElementQuery return !!node.querySelector(":scope > [data-editor-popup=\"true\"] ".concat(nestedElementQuery)); }; /** * Returns the popup with a nested element identified by a specific test ID if it exists. * * @param node - The node to check. * @param nestedElementQuery - The query to look for the nested element. * @returns Element if the node contains the popup, undefined otherwise. */ var popupWithNestedElement = exports.popupWithNestedElement = function popupWithNestedElement(node, nestedElementQuery) { if (!(node instanceof HTMLElement)) { return undefined; } // Check if node itself has the popup attribute and contains the element matching the nestedElementQuery if (node.matches('[data-editor-popup="true"]')) { return node.querySelector(nestedElementQuery); } // Check if any direct child with popup attribute contains the element matching the nestedElementQuery return node.querySelector(":scope > [data-editor-popup=\"true\"] ".concat(nestedElementQuery)); }; /** * Searches for the popup container element relative to the provided editor view element. * * @param editorViewEl - The editor view HTMLElement. * @returns The popup container HTMLElement if found, otherwise undefined. */ var getPopupContainerFromEditorView = exports.getPopupContainerFromEditorView = function getPopupContainerFromEditorView(editorViewEl) { var editorContentArea = editorViewEl === null || editorViewEl === void 0 ? void 0 : editorViewEl.closest('.ak-editor-content-area'); var pluginsComponentsWrapper = editorContentArea === null || editorContentArea === void 0 ? void 0 : editorContentArea.querySelector(':scope > [data-testid="plugins-components-wrapper"]'); return pluginsComponentsWrapper || undefined; }; /** * Checks if a node matches or contains the node given by the provided query css selector * * @param query - CSS selector string * @returns true if node matches or contains query or false otherwise */ var getNodeQuery = exports.getNodeQuery = function getNodeQuery(query) { return function (node) { if (!node || !(node instanceof Element)) { return false; } return node.matches(query) || node.querySelector(query) !== null; }; };