UNPKG

@atlaskit/editor-plugin-block-controls

Version:

Block controls plugin for @atlaskit/editor-core

116 lines (115 loc) 7.55 kB
import { fg } from '@atlaskit/platform-feature-flags/fg'; import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals'; import { expValEqualsNoExposure } from '@atlaskit/tmp-editor-statsig/exp-val-equals-no-exposure'; import { getNodeTypeWithLevel } from './decorations-common'; const OPAQUE_BLOCKS = new Set(['table', 'bulletList', 'orderedList', 'taskList', 'decisionList', 'mediaSingle']); const EXCLUDED_BLOCKS = new Set(['listItem', 'tableRow', 'tableCell', 'tableHeader', 'caption']); const isPanelNodeTypeName = nodeTypeName => nodeTypeName === 'panel' || nodeTypeName === 'panel_c1' && expValEqualsNoExposure('platform_editor_controls_reliable_anchor', 'isEnabled', true) && fg('platform_editor_controls_reliable_anchor_patch_1'); const redirectParagraphToWrappedMedia = (view, $target, targetPosition) => { const node = view.state.doc.nodeAt(targetPosition); if (!node || node.type.name !== 'paragraph') { return { position: targetPosition, node }; } const index = $target.index(); for (const siblingIndex of [index - 1, index + 1]) { if (siblingIndex < 0 || siblingIndex >= $target.parent.childCount) { continue; } const 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 }; }; /** Resolves hover from PM structure so the first hover can create its sparse candidate. */ export const handleSparseMouseOver = (view, event, api) => { var _api$editorDisabled$s, _api$editorDisabled, _api$editorDisabled$s2, _api$editorViewMode, _api$editorViewMode$s, _api$showDiff$sharedS, _api$showDiff, _api$showDiff$sharedS2, _api$userIntent, _api$userIntent$share, _$pos$nodeAfter, _controls$activeNode, _anchors$get, _anchors$get2; const controls = api === null || api === void 0 ? void 0 : api.blockControls.sharedState.currentState(); if (!api || controls !== null && controls !== void 0 && controls.isDragging || !(event.target instanceof Element) || event.target === view.dom) { return false; } const editorDisabled = (_api$editorDisabled$s = (_api$editorDisabled = api.editorDisabled) === null || _api$editorDisabled === void 0 ? void 0 : (_api$editorDisabled$s2 = _api$editorDisabled.sharedState.currentState()) === null || _api$editorDisabled$s2 === void 0 ? void 0 : _api$editorDisabled$s2.editorDisabled) !== null && _api$editorDisabled$s !== void 0 ? _api$editorDisabled$s : false; const editorViewMode = (_api$editorViewMode = api.editorViewMode) === null || _api$editorViewMode === void 0 ? void 0 : (_api$editorViewMode$s = _api$editorViewMode.sharedState.currentState()) === null || _api$editorViewMode$s === void 0 ? void 0 : _api$editorViewMode$s.mode; if (editorDisabled && (editorViewMode !== 'view' || !(controls !== null && controls !== void 0 && controls.rightSideControlsEnabled))) { return false; } const isDisplayingDiff = (_api$showDiff$sharedS = (_api$showDiff = api.showDiff) === null || _api$showDiff === void 0 ? void 0 : (_api$showDiff$sharedS2 = _api$showDiff.sharedState.currentState()) === null || _api$showDiff$sharedS2 === void 0 ? void 0 : _api$showDiff$sharedS2.isDisplayingChanges) !== null && _api$showDiff$sharedS !== void 0 ? _api$showDiff$sharedS : false; const currentUserIntent = (_api$userIntent = api.userIntent) === null || _api$userIntent === void 0 ? void 0 : (_api$userIntent$share = _api$userIntent.sharedState.currentState()) === null || _api$userIntent$share === void 0 ? void 0 : _api$userIntent$share.currentUserIntent; if ((isDisplayingDiff || currentUserIntent === 'reviewing') && expValEqualsNoExposure('platform_editor_diff_plugin_extended', 'isEnabled', true)) { return false; } let position; try { position = view.posAtDOM(event.target, 0); } catch { return false; } const $pos = view.state.doc.resolve(position); let targetPosition; let opaque = false; for (let depth = 1; depth <= $pos.depth; depth++) { const node = $pos.node(depth); if (!node.isBlock || EXCLUDED_BLOCKS.has(node.type.name)) { continue; } 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)) { // 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. const nodeAfterDOM = view.nodeDOM(position); if (nodeAfterDOM instanceof Element && nodeAfterDOM.contains(event.target)) { targetPosition = position; } } if (targetPosition === undefined) { return false; } const initialNode = view.state.doc.nodeAt(targetPosition); if (!initialNode) { return false; } const target = redirectParagraphToWrappedMedia(view, view.state.doc.resolve(targetPosition), targetPosition); targetPosition = target.position; const node = target.node; if (!node || (controls === null || controls === void 0 ? void 0 : (_controls$activeNode = controls.activeNode) === null || _controls$activeNode === void 0 ? void 0 : _controls$activeNode.pos) === targetPosition) { return false; } const $target = view.state.doc.resolve(targetPosition); if ($target.depth > 0 && (node.type.name === 'paragraph' || node.type.name === 'heading') && node.content.size === 0) { return false; } const parentNode = $target.parent; const parentPosition = $target.depth > 0 ? $target.before($target.depth) : undefined; const 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; } if (node.type.name === 'layoutColumn' && parentNode.type.name === 'layoutSection' && parentNode.childCount === 1 && expValEqualsNoExposure('advanced_layouts', 'isEnabled', true) && !expValEquals('platform_editor_layout_column_menu', 'isEnabled', true)) { return false; } const anchors = controls === null || controls === void 0 ? void 0 : controls.surfaceAnchors; const 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); const rootPos = $target.depth > 0 ? $target.before(1) : targetPosition; const rootNode = view.state.doc.nodeAt(rootPos); const 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, getNodeTypeWithLevel(node), undefined, rootPos, rootAnchorName !== null && rootAnchorName !== void 0 ? rootAnchorName : anchorName, getNodeTypeWithLevel(rootNode))); return false; };