@atlaskit/editor-common
Version:
A package that contains common classes and components for editor and renderer
114 lines (104 loc) • 4.95 kB
JavaScript
;
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;
};
};