UNPKG

@kontent-ai/smart-link

Version:

Kontent.ai Smart Link SDK allowing to automatically inject [smart links](https://docs.kontent.ai/tutorials/develop-apps/build-strong-foundation/set-up-editing-from-preview#a-using-smart-links) to Kontent.ai according to manually specified [HTML data attri

75 lines 3.37 kB
/** * Groups HTML elements by their rendering root element. * The rendering root is determined by traversing up the DOM tree to find an element that is either: * - Positioned (position is not static) * - Has clipped content (overflow is auto, scroll, clip, or hidden) * For table elements (td, th, table), they must be positioned to be considered a rendering root. */ export function groupElementsByRenderingRoot(elements) { const results = new Map(); for (const element of elements) { const root = getRenderingRootForElement(element); const prev = results.get(root) ?? new Set(); results.set(root, prev.add(element)); } return results; } /** * Iterate through node ancestors and find an element which will be used as a parent for * the ksl-container. This element should either be positioned (position is anything except static) or should * have its content clipped. In case of table element (td, th, table) it should be positioned or it will be ignored * (even if its content is clipped). */ export function getRenderingRootForElement(element) { const parentElement = element.parentElement; if (!parentElement) { return null; } const metadata = getRenderingRootMetadata(parentElement); // Table HTML element (td, th, table) can be an offset parent of some node, but unless it is positioned it will not be // used as a offset parent for the absolute positioned child (highlight). That is why we should ignore those elements and // do not use them as parents unless they are positioned. Otherwise, the highlighting might broke for the tables. const isNotTable = !['TD', 'TH', 'TABLE'].includes(parentElement.tagName); return metadata.isPositioned || (metadata.isContentClipped && isNotTable) ? parentElement : getRenderingRootForElement(parentElement); } /** * Gets metadata about an element's rendering properties that determine how it should be used as a container. */ export function getRenderingRootMetadata(root) { const computedStyles = window.getComputedStyle(root); const position = computedStyles.getPropertyValue('position'); const overflow = computedStyles.getPropertyValue('overflow'); return { isPositioned: position !== 'static', isContentClipped: overflow.split(' ').some((value) => ['auto', 'scroll', 'clip', 'hidden'].includes(value)), }; } /** * Iterate through node ancestors until HTMLElement.offsetParent is reached and sum scroll offsets. */ export function getTotalScrollOffset(node) { if (!node) { return [0, 0]; } const offsetParent = node.offsetParent; // HTMLElement.offsetParent can be null when the node is <body> or <html> if (!offsetParent) { return [0, 0]; } const calculateOffset = (currentNode) => { if (offsetParent.isSameNode(currentNode) || !currentNode) { return [0, 0]; } const [scrollTop, scrollLeft] = calculateOffset(currentNode.parentElement); return [scrollTop + currentNode.scrollTop, scrollLeft + currentNode.scrollLeft]; }; return calculateOffset(node.parentElement); } export function createTemplateForCustomElement(html) { const template = document.createElement('template'); template.innerHTML = html; return template; } //# sourceMappingURL=domElement.js.map