UNPKG

@atlaskit/editor-plugin-block-controls

Version:

Block controls plugin for @atlaskit/editor-core

138 lines (135 loc) • 8.78 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.isSparseHoverSuppressed = exports.handleSparseHoverTarget = void 0; var _nodeAnchorProvider = require("@atlaskit/editor-common/node-anchor-provider"); var _fg = require("@atlaskit/platform-feature-flags/fg"); var _expValEqualsNoExposure = require("@atlaskit/tmp-editor-statsig/exp-val-equals-no-exposure"); var _decorationsCommon = require("./decorations-common"); var OPAQUE_BLOCKS = new Set(['bulletList', 'orderedList', 'taskList', 'decisionList', 'mediaSingle']); var EXCLUDED_BLOCKS = new Set(['listItem', 'tableRow', 'tableCell', 'tableHeader', 'caption']); var TABLE_CELLS = new Set(['tableCell', 'tableHeader']); var isPanelNodeTypeName = function isPanelNodeTypeName(nodeTypeName) { return nodeTypeName === 'panel' || nodeTypeName === 'panel_c1' && (0, _expValEqualsNoExposure.expValEqualsNoExposure)('platform_editor_controls_reliable_anchor', 'isEnabled', true) && (0, _fg.fg)('platform_editor_controls_reliable_anchor_patch_1'); }; var redirectParagraphToWrappedMedia = function redirectParagraphToWrappedMedia(view, $target, targetPosition) { var node = view.state.doc.nodeAt(targetPosition); if (!node || node.type.name !== 'paragraph') { return { position: targetPosition, node: node }; } var index = $target.index(); for (var _i = 0, _arr = [index - 1, index + 1]; _i < _arr.length; _i++) { var siblingIndex = _arr[_i]; if (siblingIndex < 0 || siblingIndex >= $target.parent.childCount) { continue; } var sibling = $target.parent.child(siblingIndex); if ((sibling.type.name === 'mediaSingle' || sibling.type.name === 'embedCard') && (sibling.attrs.layout === 'wrap-left' || sibling.attrs.layout === 'wrap-right')) { return { position: siblingIndex < index ? targetPosition - sibling.nodeSize : targetPosition + node.nodeSize, node: sibling }; } } return { position: targetPosition, node: node }; }; /** Whether hovering must not show block controls under sparse surfaces. */ var isSparseHoverSuppressed = exports.isSparseHoverSuppressed = function isSparseHoverSuppressed(view, api) { var _api$limitedMode, _getNodeIdProvider, _api$typeAhead, _api$editorDisabled$s, _api$editorDisabled, _api$editorViewMode, _api$showDiff$sharedS, _api$showDiff, _api$userIntent; if (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 && _api$limitedMode.enabled || (_getNodeIdProvider = (0, _nodeAnchorProvider.getNodeIdProvider)(view)) !== null && _getNodeIdProvider !== void 0 && _getNodeIdProvider.isLimitedMode()) { return true; } var controls = api === null || api === void 0 ? void 0 : api.blockControls.sharedState.currentState(); if (controls !== null && controls !== void 0 && controls.isDragging || api !== null && api !== void 0 && (_api$typeAhead = api.typeAhead) !== null && _api$typeAhead !== void 0 && (_api$typeAhead = _api$typeAhead.sharedState.currentState()) !== null && _api$typeAhead !== void 0 && _api$typeAhead.isOpen) { return true; } var editorDisabled = (_api$editorDisabled$s = api === null || api === void 0 || (_api$editorDisabled = api.editorDisabled) === null || _api$editorDisabled === void 0 || (_api$editorDisabled = _api$editorDisabled.sharedState.currentState()) === null || _api$editorDisabled === void 0 ? void 0 : _api$editorDisabled.editorDisabled) !== null && _api$editorDisabled$s !== void 0 ? _api$editorDisabled$s : false; var editorViewMode = api === null || api === void 0 || (_api$editorViewMode = api.editorViewMode) === null || _api$editorViewMode === void 0 || (_api$editorViewMode = _api$editorViewMode.sharedState.currentState()) === null || _api$editorViewMode === void 0 ? void 0 : _api$editorViewMode.mode; if (editorDisabled && (editorViewMode !== 'view' || !(controls !== null && controls !== void 0 && controls.rightSideControlsEnabled))) { return true; } var isDisplayingDiff = (_api$showDiff$sharedS = api === null || api === void 0 || (_api$showDiff = api.showDiff) === null || _api$showDiff === void 0 || (_api$showDiff = _api$showDiff.sharedState.currentState()) === null || _api$showDiff === void 0 ? void 0 : _api$showDiff.isDisplayingChanges) !== null && _api$showDiff$sharedS !== void 0 ? _api$showDiff$sharedS : false; return isDisplayingDiff || (api === null || api === void 0 || (_api$userIntent = api.userIntent) === null || _api$userIntent === void 0 || (_api$userIntent = _api$userIntent.sharedState.currentState()) === null || _api$userIntent === void 0 ? void 0 : _api$userIntent.currentUserIntent) === 'reviewing'; }; /** * Shows controls for the block that owns `target`, resolved from PM structure so the first hover * can create its sparse candidate. Callers check `isSparseHoverSuppressed` first. */ var handleSparseHoverTarget = exports.handleSparseHoverTarget = function handleSparseHoverTarget(view, target, api) { var _$pos$nodeAfter, _controls$activeNode, _anchors$get, _anchors$get2; if (!api || target === view.dom) { return false; } var controls = api.blockControls.sharedState.currentState(); var position; try { position = view.posAtDOM(target, 0); } catch (_unused) { return false; } var $pos = view.state.doc.resolve(position); var targetPosition; var opaque = false; for (var depth = 1; depth <= $pos.depth; depth++) { var _node = $pos.node(depth); if (!_node.isBlock || EXCLUDED_BLOCKS.has(_node.type.name)) { continue; } // Legacy hover excludes direct cell children, but can target deeper blocks inside them. if (!TABLE_CELLS.has($pos.node(depth - 1).type.name)) { targetPosition = $pos.before(depth); } if (OPAQUE_BLOCKS.has(_node.type.name)) { opaque = true; break; } } if (!opaque && (_$pos$nodeAfter = $pos.nodeAfter) !== null && _$pos$nodeAfter !== void 0 && _$pos$nodeAfter.isBlock && !EXCLUDED_BLOCKS.has($pos.nodeAfter.type.name) && !TABLE_CELLS.has($pos.parent.type.name)) { // Browser positions over non-editable node chrome can resolve to the first editable child. // Keep the ancestor unless that child actually owns the hovered DOM target. var nodeAfterDOM = view.nodeDOM(position); if (nodeAfterDOM instanceof Element && nodeAfterDOM.contains(target)) { targetPosition = position; } } if (targetPosition === undefined) { return false; } var initialNode = view.state.doc.nodeAt(targetPosition); if (!initialNode) { return false; } var redirected = redirectParagraphToWrappedMedia(view, view.state.doc.resolve(targetPosition), targetPosition); targetPosition = redirected.position; var node = redirected.node; if (!node || (controls === null || controls === void 0 || (_controls$activeNode = controls.activeNode) === null || _controls$activeNode === void 0 ? void 0 : _controls$activeNode.pos) === targetPosition) { return false; } var $target = view.state.doc.resolve(targetPosition); if ($target.depth > 0 && (node.type.name === 'paragraph' || node.type.name === 'heading') && node.content.size === 0) { return false; } var parentNode = $target.parent; var parentPosition = $target.depth > 0 ? $target.before($target.depth) : undefined; var parentDOM = parentPosition === undefined ? undefined : view.nodeDOM(parentPosition); if (isPanelNodeTypeName(parentNode.type.name) && !(parentDOM instanceof HTMLElement && parentDOM.classList.contains('ak-editor-panel__no-icon')) && $target.index() === 0) { return false; } var anchors = controls === null || controls === void 0 ? void 0 : controls.surfaceAnchors; var anchorName = (_anchors$get = anchors === null || anchors === void 0 ? void 0 : anchors.get(targetPosition)) !== null && _anchors$get !== void 0 ? _anchors$get : api.core.actions.getAnchorIdForNode(node, targetPosition); var rootPos = $target.depth > 0 ? $target.before(1) : targetPosition; var rootNode = view.state.doc.nodeAt(rootPos); var rootAnchorName = (_anchors$get2 = anchors === null || anchors === void 0 ? void 0 : anchors.get(rootPos)) !== null && _anchors$get2 !== void 0 ? _anchors$get2 : rootNode ? api.core.actions.getAnchorIdForNode(rootNode, rootPos) : undefined; if (!anchorName || !rootNode) { return false; } api.core.actions.execute(api.blockControls.commands.showDragHandleAt(targetPosition, anchorName, (0, _decorationsCommon.getNodeTypeWithLevel)(node), undefined, rootPos, rootAnchorName !== null && rootAnchorName !== void 0 ? rootAnchorName : anchorName, (0, _decorationsCommon.getNodeTypeWithLevel)(rootNode))); return false; };