UNPKG

@atlaskit/editor-plugin-show-diff

Version:

ShowDiff plugin for @atlaskit/editor-core

114 lines (109 loc) • 5.11 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.scrollToDecoration = void 0; var _table = require("@atlaskit/editor-common/styles/table"); var _getStickyHeaderHeight = require("@atlaskit/editor-common/table/get-sticky-header-height"); var _fg = require("@atlaskit/platform-feature-flags/fg"); var _decorationKeys = require("./decorations/decorationKeys"); var _getWidgetElement = require("./decorations/utils/getWidgetElement"); /** * 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. */ var SCROLL_TOP_MARGIN_PX = 100; function updateScrollTargetMargin(view, targetPos, api) { var _api$limitedMode; var isLimitedModeEnabled = Boolean(api === null || api === void 0 || (_api$limitedMode = api.limitedMode) === null || _api$limitedMode === void 0 || (_api$limitedMode = _api$limitedMode.sharedState.currentState()) === null || _api$limitedMode === void 0 ? void 0 : _api$limitedMode.enabled); var tableHeaderHeight = isLimitedModeEnabled ? undefined : (0, _getStickyHeaderHeight.getStickyHeaderHeight)(view, targetPos); view.dom.style.setProperty(_decorationKeys.SCROLL_TARGET_MARGIN_CSS_PROPERTY, "".concat(tableHeaderHeight ? tableHeaderHeight + _table.tableMarginTop : 0, "px")); } function scrollToSelection(node) { // ProseMirror may return a text node; scroll its parent element instead. var element = node instanceof Element ? node : node === null || node === void 0 ? void 0 : node.parentElement; if (!(element instanceof HTMLElement)) { return; } var scrollOptions = { behavior: 'smooth', block: 'start' }; if ((0, _fg.fg)('platform_editor_ai_suggestion_table_scroll_fix')) { scrollOptions.inline = 'center'; } if ((0, _fg.fg)('platform_editor_ai_show_diff_patch_1')) { element.scrollIntoView(scrollOptions); return; } // scroll-margin is included in scroll-into-view math; it does not change layout. var previousScrollMarginTop = element.style.scrollMarginTop; element.style.scrollMarginTop = "".concat(SCROLL_TOP_MARGIN_PX, "px"); try { element.scrollIntoView(scrollOptions); } finally { element.style.scrollMarginTop = previousScrollMarginTop; } } function resolveScrollTarget(view, target) { var _view$domAtPos; if ((0, _decorationKeys.isDiffDecoration)(target) && target.spec.decorationType === 'widget') { return (0, _getWidgetElement.getWidgetElement)(target); } if ((0, _decorationKeys.isDiffDecoration)(target) && (0, _fg.fg)('platform_editor_ai_show_diff_patch_2')) { var _Array$from$find; return (_Array$from$find = Array.from(view.dom.querySelectorAll('[data-diff-id]')).find(function (element) { return element.dataset.diffId === target.spec.diffId; })) !== null && _Array$from$find !== void 0 ? _Array$from$find : view.nodeDOM(target.from); } var targetNode = view.nodeDOM(target.from); return targetNode instanceof Element ? targetNode : (_view$domAtPos = view.domAtPos(target.from)) === null || _view$domAtPos === void 0 ? void 0 : _view$domAtPos.node; } /** * Schedules scrolling to the decoration at the given index after the next frame. Defaults to the * first decoration when no index is provided. * * @returns A function that cancels the scheduled `requestAnimationFrame` if it has not run yet. */ var scrollToDecoration = exports.scrollToDecoration = function scrollToDecoration(view, decorations) { var activeIndex = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0; var api = arguments.length > 3 ? arguments[3] : undefined; var decoration = decorations[activeIndex]; if (!decoration) { return function () {}; } // A grouped decoration spans a whole customer-facing edit, which can visually start with a // deleted-content widget rather than at the group's `from` position — see `scrollTarget` in // `getScrollableDecorations`. Only set under `platform_editor_ai_show_diff_patch_1`. var target = (0, _decorationKeys.isDiffDecoration)(decoration) && decoration.spec.scrollTarget || decoration; var rafId = null; var cancelled = false; var scrollToTarget = function scrollToTarget() { if (view.isDestroyed) { return; } if ((0, _fg.fg)('platform_editor_ai_show_diff_patch_1')) { updateScrollTargetMargin(view, target.from, api); } scrollToSelection(resolveScrollTarget(view, target)); }; // Called from the plugin's post-DOM update hook; defer measurement until layout can settle. rafId = requestAnimationFrame(function () { rafId = null; if (!cancelled) { scrollToTarget(); } }); return function () { cancelled = true; if (rafId !== null) { cancelAnimationFrame(rafId); rafId = null; } }; };