UNPKG

@atlaskit/editor-plugin-block-controls

Version:

Block controls plugin for @atlaskit/editor-core

117 lines (111 loc) 5.11 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.handleMouseMove = exports.handleMouseLeave = exports.handleMouseEnter = void 0; var _commands = require("./commands"); var _pmPlugin = require("./pm-plugin"); /** Per-view pending hover state; avoids cross-editor singleton. */ var pendingByView = new WeakMap(); /** Per-view RAF handle so clearPendingHoverSide cancels only that view's callback. */ var rafIdByView = new WeakMap(); var cancelScheduledProcessForView = function cancelScheduledProcessForView(view) { var id = rafIdByView.get(view); if (id !== undefined) { cancelAnimationFrame(id); rafIdByView.delete(view); } }; var clearPendingHoverSide = function clearPendingHoverSide(view) { pendingByView.delete(view); cancelScheduledProcessForView(view); }; var BLOCK_SELECTORS = '[data-node-anchor], [data-drag-handler-anchor-name]'; var RIGHT_EDGE_SELECTOR = '[data-blocks-right-edge-button-container]'; /** * Process hover position and set left/right side. Only invoked when right-side controls are * enabled (confluence_remix_button_right_side_block_fg); handleMouseMove returns early otherwise. */ var processHoverSide = function processHoverSide(view) { var event = pendingByView.get(view); if (!event) { return; } pendingByView.delete(view); rafIdByView.delete(view); var editorContentArea = view.dom.closest('.ak-editor-content-area'); if (!(editorContentArea instanceof HTMLElement)) { return; } var state = (0, _pmPlugin.getInteractionTrackingState)(view.state); var target = event.target instanceof HTMLElement ? event.target : null; // When hovering over block controls directly, infer side from which control we're over. // This is more reliable than bounds when controls are in portals outside the editor DOM. var rightEdgeElement = target === null || target === void 0 ? void 0 : target.closest(RIGHT_EDGE_SELECTOR); if (rightEdgeElement) { if ((state === null || state === void 0 ? void 0 : state.hoverSide) !== 'right') { (0, _commands.setHoverSide)(view, 'right'); } return; } var leftControlElement = target === null || target === void 0 ? void 0 : target.closest('[data-blocks-drag-handle-container], [data-testid="block-ctrl-drag-handle"], [data-testid="block-ctrl-drag-handle-container"], [data-testid="block-ctrl-decorator-widget"], [data-testid="block-ctrl-quick-insert-button"]'); if (leftControlElement) { if ((state === null || state === void 0 ? void 0 : state.hoverSide) !== 'left') { (0, _commands.setHoverSide)(view, 'left'); } return; } // Primary path: depth-1 block (doc direct child). Decorations-anchor sets [data-drag-handler-anchor-depth="1"] // on every root block (table, layoutSection, expand, etc.), so we get the whole block without per-type logic. var blockElement = target === null || target === void 0 ? void 0 : target.closest(BLOCK_SELECTORS); var depth1Block = blockElement instanceof HTMLElement ? blockElement.closest('[data-drag-handler-anchor-depth="1"]') : null; var boundsElement = depth1Block instanceof HTMLElement ? depth1Block : editorContentArea; if (!boundsElement) { if ((state === null || state === void 0 ? void 0 : state.hoverSide) !== undefined) { (0, _commands.clearHoverSide)(view); } return; } var _boundsElement$getBou = boundsElement.getBoundingClientRect(), left = _boundsElement$getBou.left, right = _boundsElement$getBou.right; var midpoint = (left + right) / 2; var nextHoverSide = event.clientX > midpoint ? 'right' : 'left'; if ((state === null || state === void 0 ? void 0 : state.hoverSide) !== nextHoverSide) { (0, _commands.setHoverSide)(view, nextHoverSide); } }; var handleMouseMove = exports.handleMouseMove = function handleMouseMove(view, event) { var rightSideControlsEnabled = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false; var state = (0, _pmPlugin.getInteractionTrackingState)(view.state); // if user has stopped editing and moved their mouse, show block controls again if (state !== null && state !== void 0 && state.isEditing) { (0, _commands.stopEditing)(view); } // Only track hover side when right-side controls are enabled (single source: confluence_remix_button_right_side_block_fg via config) if (!rightSideControlsEnabled) { return false; } if (!(event instanceof MouseEvent)) { return false; } pendingByView.set(view, event); cancelScheduledProcessForView(view); var id = requestAnimationFrame(function () { processHoverSide(view); }); rafIdByView.set(view, id); return false; }; var handleMouseLeave = exports.handleMouseLeave = function handleMouseLeave(view) { var rightSideControlsEnabled = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; if (rightSideControlsEnabled) { clearPendingHoverSide(view); } (0, _commands.mouseLeave)(view); return false; }; var handleMouseEnter = exports.handleMouseEnter = function handleMouseEnter(view) { (0, _commands.mouseEnter)(view); return false; };