UNPKG

@atlaskit/editor-plugin-show-diff

Version:

ShowDiff plugin for @atlaskit/editor-core

66 lines (63 loc) 2.79 kB
/** * Extra space above the scrolled-to element so it does not sit flush under the * viewport edge (helps with sticky table headers, toolbars, etc.). * * Implemented with `scroll-margin-top` so we still use the browser’s native * `scrollIntoView`, which scrolls every relevant scrollport (nested containers * and the window). A single manual `scrollTop` on one ancestor often misses * outer scroll or mis-identifies the active scroll container. */ const SCROLL_TOP_MARGIN_PX = 100; /** * Scrolls to the current position/selection of the document. It does the same as scrollIntoView() * but without requiring the focus on the editor, thus it can be called at any time. */ function scrollToSelection(node) { const element = node instanceof Element ? node : (node === null || node === void 0 ? void 0 : node.parentElement) instanceof Element ? node.parentElement : null; if (!(element instanceof HTMLElement)) { return; } // scroll-margin is included in scroll-into-view math; it does not change layout. const previousScrollMarginTop = element.style.scrollMarginTop; element.style.scrollMarginTop = `${SCROLL_TOP_MARGIN_PX}px`; try { element.scrollIntoView({ behavior: 'smooth', block: 'start' }); } finally { element.style.scrollMarginTop = previousScrollMarginTop; } } /** * Schedules scrolling to the decoration at the given index after the next frame. * * @returns A function that cancels the scheduled `requestAnimationFrame` if it has not run yet. */ export const scrollToActiveDecoration = (view, decorations, activeIndex) => { const decoration = decorations[activeIndex]; if (!decoration) { return () => {}; } let rafId = requestAnimationFrame(() => { var _decoration$spec; rafId = null; if (((_decoration$spec = decoration.spec) === null || _decoration$spec === void 0 ? void 0 : _decoration$spec.key) === 'diff-widget-active') { var _decoration$type; // @ts-expect-error - decoration.type is not typed public API const widgetDom = decoration === null || decoration === void 0 ? void 0 : (_decoration$type = decoration.type) === null || _decoration$type === void 0 ? void 0 : _decoration$type.toDOM; scrollToSelection(widgetDom); } else { var _view$domAtPos; const targetNode = view.nodeDOM(decoration === null || decoration === void 0 ? void 0 : decoration.from); const node = targetNode instanceof Element ? targetNode : (_view$domAtPos = view.domAtPos(decoration === null || decoration === void 0 ? void 0 : decoration.from)) === null || _view$domAtPos === void 0 ? void 0 : _view$domAtPos.node; scrollToSelection(node); } }); return () => { if (rafId !== null) { cancelAnimationFrame(rafId); rafId = null; } }; };