@atlaskit/editor-plugin-block-controls
Version:
Block controls plugin for @atlaskit/editor-core
117 lines (111 loc) • 5.11 kB
JavaScript
;
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;
};