@atlaskit/editor-plugin-block-controls
Version:
Block controls plugin for @atlaskit/editor-core
308 lines (303 loc) • 15.4 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.EDITOR_BLOCK_CONTROLS_DROP_INDICATOR_OFFSET = exports.EDITOR_BLOCK_CONTROLS_DROP_INDICATOR_GAP = exports.DropTarget = void 0;
var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
var _react = require("react");
var _react2 = require("@emotion/react");
var _hooks = require("@atlaskit/editor-common/hooks");
var _box = require("@atlaskit/pragmatic-drag-and-drop-react-drop-indicator/box");
var _adapter = require("@atlaskit/pragmatic-drag-and-drop/element/adapter");
var _constants = require("@atlaskit/theme/constants");
var _expValEquals = require("@atlaskit/tmp-editor-statsig/exp-val-equals");
var _experiments = require("@atlaskit/tmp-editor-statsig/experiments");
var _decorationsCommon = require("../pm-plugins/decorations-common");
var _activeAnchorTracker = require("../pm-plugins/utils/active-anchor-tracker");
var _anchorUtils = require("../pm-plugins/utils/anchor-utils");
var _inlineDropTarget = require("../pm-plugins/utils/inline-drop-target");
var _consts = require("./consts");
var _inlineDropTarget2 = require("./inline-drop-target");
/**
* @jsxRuntime classic
* @jsx jsx
*/
// eslint-disable-next-line @atlaskit/ui-styling-standard/use-compiled, @typescript-eslint/consistent-type-imports
var DEFAULT_DROP_INDICATOR_WIDTH = 760;
var EDITOR_BLOCK_CONTROLS_DROP_INDICATOR_WIDTH = '--editor-block-controls-drop-indicator-width';
var EDITOR_BLOCK_CONTROLS_DROP_TARGET_LEFT_MARGIN = '--editor-block-controls-drop-target-leftMargin';
var EDITOR_BLOCK_CONTROLS_DROP_TARGET_ZINDEX = '--editor-block-controls-drop-target-zindex';
var EDITOR_BLOCK_CONTROLS_DROP_INDICATOR_OFFSET = exports.EDITOR_BLOCK_CONTROLS_DROP_INDICATOR_OFFSET = '--editor-block-controls-drop-indicator-offset';
var EDITOR_BLOCK_CONTROLS_DROP_INDICATOR_GAP = exports.EDITOR_BLOCK_CONTROLS_DROP_INDICATOR_GAP = '--editor-block-controls-drop-indicator-gap';
var styleDropTarget = (0, _react2.css)({
marginLeft: "calc(-1 * var(".concat(EDITOR_BLOCK_CONTROLS_DROP_TARGET_LEFT_MARGIN, ", 0))"),
paddingLeft: "var(".concat(EDITOR_BLOCK_CONTROLS_DROP_TARGET_LEFT_MARGIN, ", 0)"),
position: 'absolute',
left: '0',
display: 'block',
zIndex: "var(".concat(EDITOR_BLOCK_CONTROLS_DROP_TARGET_ZINDEX, ", 110)"),
transform: "translateY(var(".concat(EDITOR_BLOCK_CONTROLS_DROP_INDICATOR_OFFSET, ", 0))")
});
var styleDropIndicator = (0, _react2.css)({
height: '100%',
margin: '0 auto',
position: 'relative',
width: "var(".concat(EDITOR_BLOCK_CONTROLS_DROP_INDICATOR_WIDTH, ", 100%)"),
display: 'none'
});
var styleDropIndicatorVisible = (0, _react2.css)({
display: 'block'
});
var nestedDropIndicatorStyle = (0, _react2.css)({
position: 'relative'
});
var dropZoneStyles = (0, _react2.css)({
margin: 0,
position: 'absolute',
width: '100%',
zIndex: 110,
minHeight: '4px'
});
var nestedDropZoneStyle = (0, _react2.css)({
left: '4px',
right: '4px',
width: 'unset'
});
var enableDropZone = ['paragraph', 'mediaSingle', 'heading', 'codeBlock', 'decisionList', 'bulletList', 'orderedList', 'taskList', 'extension', 'blockCard'];
var enableDropZoneNext = ['paragraph', 'mediaSingle', 'heading', 'codeBlock', 'decisionList', 'bulletList', 'orderedList', 'taskList', 'extension', 'blockCard', 'syncBlock'];
var getEnableDropZone = function getEnableDropZone() {
if ((0, _experiments.editorExperiment)('platform_synced_block_patch_6', true, {
exposure: true
})) {
return enableDropZoneNext;
}
return enableDropZone;
};
// This z index is used in container like layout
var fullHeightStyleAdjustZIndexStyle = (0, _react2.css)({
zIndex: 0
});
var HoverZone = function HoverZone(_ref) {
var _onDragEnter = _ref.onDragEnter,
onDragLeave = _ref.onDragLeave,
onDrop = _ref.onDrop,
node = _ref.node,
pos = _ref.pos,
parent = _ref.parent,
editorWidth = _ref.editorWidth,
anchorRectCache = _ref.anchorRectCache,
position = _ref.position,
isNestedDropTarget = _ref.isNestedDropTarget,
dropTargetStyle = _ref.dropTargetStyle,
api = _ref.api;
var ref = (0, _react.useRef)(null);
var isRemainingheight = dropTargetStyle === 'remainingHeight';
var anchorName = (0, _react.useMemo)(function () {
if ((0, _expValEquals.expValEquals)('platform_editor_native_anchor_with_dnd', 'isEnabled', true)) {
if (node && typeof pos === 'number') {
var posOffset = position === 'upper' ? -node.nodeSize : 0;
return (api === null || api === void 0 ? void 0 : api.core.actions.getAnchorIdForNode(node, pos + posOffset)) || '';
}
return '';
}
return node ? (0, _decorationsCommon.getNodeAnchor)(node) : '';
}, [api, node, pos, position]);
var _useActiveAnchorTrack = (0, _activeAnchorTracker.useActiveAnchorTracker)(anchorName),
_useActiveAnchorTrack2 = (0, _slicedToArray2.default)(_useActiveAnchorTrack, 2),
_isActive = _useActiveAnchorTrack2[0],
setActiveAnchor = _useActiveAnchorTrack2[1];
var isInsideBodiedSyncBlock = parent && parent.type.name === 'bodiedSyncBlock' && (0, _experiments.editorExperiment)('platform_synced_block', true) && (0, _experiments.editorExperiment)('platform_synced_block_patch_6', true, {
exposure: true
});
(0, _react.useEffect)(function () {
if (ref.current) {
return (0, _adapter.dropTargetForElements)({
element: ref.current,
onDragEnter: function onDragEnter() {
if ((!isNestedDropTarget || isInsideBodiedSyncBlock) && (0, _experiments.editorExperiment)('advanced_layouts', true)) {
setActiveAnchor();
}
_onDragEnter();
},
onDragLeave: onDragLeave,
onDrop: onDrop
});
}
}, [isNestedDropTarget, isInsideBodiedSyncBlock, _onDragEnter, onDragLeave, onDrop, setActiveAnchor]);
var hoverZoneUpperStyle = (0, _react.useMemo)(function () {
var heightStyleOffset = "var(--editor-block-controls-drop-indicator-gap, 0)/2";
var transformOffset = "var(".concat(EDITOR_BLOCK_CONTROLS_DROP_INDICATOR_OFFSET, ", 0)");
var heightStyle = anchorName && getEnableDropZone().includes((node === null || node === void 0 ? void 0 : node.type.name) || '') ? (0, _anchorUtils.isAnchorSupported)() ? "calc(anchor-size(".concat(anchorName, " height)/2 + ").concat(heightStyleOffset, ")") : "calc(".concat(((anchorRectCache === null || anchorRectCache === void 0 ? void 0 : anchorRectCache.getHeight(anchorName)) || 0) / 2, "px + ").concat(heightStyleOffset, ")") : '4px';
var transform = position === 'upper' ? "translateY(calc(-100% + ".concat(transformOffset, "))") : "translateY(".concat(transformOffset, ")");
return (0, _react2.css)({
// eslint-disable-next-line @atlaskit/ui-styling-standard/no-unsafe-values
height: heightStyle,
// eslint-disable-next-line @atlaskit/ui-styling-standard/no-unsafe-values
transform: transform,
// eslint-disable-next-line @atlaskit/ui-styling-standard/no-unsafe-values
maxWidth: "".concat(editorWidth || 0, "px")
});
}, [anchorName, anchorRectCache, editorWidth, node === null || node === void 0 ? void 0 : node.type.name, position]);
/**
* 1. Above the last empty line
* 2. Below the last element
*
* Both cases will take the remaining height of the the container
*/
var heightStyle = (0, _react.useMemo)(function () {
// only apply upper drop zone
if (isRemainingheight && position === 'upper') {
// previous node
var _anchorName = node ? (0, _expValEquals.expValEquals)('platform_editor_native_anchor_with_dnd', 'isEnabled', true) ? (api === null || api === void 0 ? void 0 : api.core.actions.getAnchorIdForNode(node, pos || -1)) || '' : (0, _decorationsCommon.getNodeAnchor)(node) : '';
var top = 'unset';
if (_anchorName) {
var enabledDropZone = getEnableDropZone().includes((node === null || node === void 0 ? void 0 : node.type.name) || '');
if ((0, _anchorUtils.isAnchorSupported)()) {
top = enabledDropZone ? "calc(anchor(".concat(_anchorName, " 50%))") : "calc(anchor(".concat(_anchorName, " bottom) - 4px)");
} else if (anchorRectCache) {
var preNodeTopPos = anchorRectCache.getTop(_anchorName) || 0;
var prevNodeHeight = anchorRectCache.getHeight(_anchorName) || 0;
top = enabledDropZone ? "calc(".concat(preNodeTopPos, "px + ").concat(prevNodeHeight / 2, "px)") : "calc(".concat(preNodeTopPos, "px + ").concat(prevNodeHeight, "px - 4px)");
} else {
// Should not happen
return null;
}
} else {
// first empty paragraph
top = '4px';
}
return (0, _react2.css)({
// eslint-disable-next-line @atlaskit/ui-styling-standard/no-unsafe-values
top: top,
bottom: '4px',
height: 'unset',
zIndex: 10,
transform: 'none'
});
}
return null;
}, [anchorRectCache, api, isRemainingheight, node, pos, position]);
var isFullHeightInLayout = isRemainingheight && (parent === null || parent === void 0 ? void 0 : parent.type.name) === 'layoutColumn';
return (0, _react2.jsx)("div", {
ref: ref
// eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop
,
className: "drop-target-hover-zone-".concat(position),
"data-testid": "drop-target-zone-".concat(position)
// eslint-disable-next-line @atlaskit/design-system/consistent-css-prop-usage
,
css: [dropZoneStyles, isNestedDropTarget && nestedDropZoneStyle,
// eslint-disable-next-line @atlaskit/design-system/consistent-css-prop-usage
hoverZoneUpperStyle,
// eslint-disable-next-line @atlaskit/design-system/consistent-css-prop-usage
heightStyle, isFullHeightInLayout && fullHeightStyleAdjustZIndexStyle]
});
};
var DropTarget = exports.DropTarget = function DropTarget(props) {
var _api$blockControls;
var api = props.api,
getPos = props.getPos,
prevNode = props.prevNode,
nextNode = props.nextNode,
parentNode = props.parentNode,
formatMessage = props.formatMessage,
anchorRectCache = props.anchorRectCache,
_props$dropTargetStyl = props.dropTargetStyle,
dropTargetStyle = _props$dropTargetStyl === void 0 ? 'default' : _props$dropTargetStyl,
isSameLayout = props.isSameLayout;
var _useState = (0, _react.useState)(false),
_useState2 = (0, _slicedToArray2.default)(_useState, 2),
isDraggedOver = _useState2[0],
setIsDraggedOver = _useState2[1];
var _useSharedPluginState = (0, _hooks.useSharedPluginStateWithSelector)(api, ['width'], function (states) {
var _states$widthState;
return {
lineLength: ((_states$widthState = states.widthState) === null || _states$widthState === void 0 ? void 0 : _states$widthState.lineLength) || DEFAULT_DROP_INDICATOR_WIDTH
};
}),
lineLength = _useSharedPluginState.lineLength;
var isNestedDropTarget = (parentNode === null || parentNode === void 0 ? void 0 : parentNode.type.name) !== 'doc';
var _ref2 = (api === null || api === void 0 || (_api$blockControls = api.blockControls) === null || _api$blockControls === void 0 ? void 0 : _api$blockControls.sharedState.currentState()) || {},
activeNode = _ref2.activeNode;
var onDrop = function onDrop() {
if (!activeNode) {
return;
}
var pos = getPos();
if (activeNode && pos !== undefined) {
var _api$core, _api$blockControls2;
var start = activeNode.pos;
api === null || api === void 0 || (_api$core = api.core) === null || _api$core === void 0 || _api$core.actions.execute(api === null || api === void 0 || (_api$blockControls2 = api.blockControls) === null || _api$blockControls2 === void 0 || (_api$blockControls2 = _api$blockControls2.commands) === null || _api$blockControls2 === void 0 ? void 0 : _api$blockControls2.moveNode(start, pos, undefined, formatMessage));
}
};
var dynamicStyle = (0, _defineProperty2.default)((0, _defineProperty2.default)((0, _defineProperty2.default)({
width: isNestedDropTarget ? 'unset' : '100%'
}, EDITOR_BLOCK_CONTROLS_DROP_INDICATOR_WIDTH, isNestedDropTarget ? '100%' : "".concat(lineLength || DEFAULT_DROP_INDICATOR_WIDTH, "px")), EDITOR_BLOCK_CONTROLS_DROP_TARGET_LEFT_MARGIN, isNestedDropTarget ? (0, _consts.getNestedNodeLeftPaddingMargin)(parentNode === null || parentNode === void 0 ? void 0 : parentNode.type.name) : '0'), EDITOR_BLOCK_CONTROLS_DROP_TARGET_ZINDEX, _constants.layers.navigation());
var isShowInlineDropTarget = (0, _inlineDropTarget.shouldAllowInlineDropTarget)(isNestedDropTarget, nextNode, isSameLayout, activeNode, parentNode);
return (0, _react2.jsx)(_react.Fragment, null, (0, _react2.jsx)(HoverZone
// eslint-disable-next-line @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed)
, {
onDragEnter: function onDragEnter() {
return setIsDraggedOver(true);
}
// eslint-disable-next-line @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed)
,
onDragLeave: function onDragLeave() {
return setIsDraggedOver(false);
},
onDrop: onDrop,
node: prevNode,
pos: getPos(),
editorWidth: lineLength,
anchorRectCache: anchorRectCache,
position: "upper",
isNestedDropTarget: isNestedDropTarget,
dropTargetStyle: dropTargetStyle,
api: api
}), (0, _react2.jsx)("div", {
// eslint-disable-next-line @atlaskit/design-system/consistent-css-prop-usage
css: [styleDropTarget, isNestedDropTarget && nestedDropIndicatorStyle]
// eslint-disable-next-line @atlaskit/ui-styling-standard/enforce-style-prop
,
style: dynamicStyle,
"data-testid": "block-ctrl-drop-target"
}, (0, _react2.jsx)("div", {
css: [styleDropIndicator, isDraggedOver && styleDropIndicatorVisible],
"data-testid": "block-ctrl-drop-indicator"
}, (0, _react2.jsx)(_box.DropIndicator, {
edge: "bottom"
}))), dropTargetStyle !== 'remainingHeight' && (0, _react2.jsx)(HoverZone
// eslint-disable-next-line @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed)
, {
onDragEnter: function onDragEnter() {
return setIsDraggedOver(true);
}
// eslint-disable-next-line @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed)
,
onDragLeave: function onDragLeave() {
return setIsDraggedOver(false);
},
onDrop: onDrop,
node: nextNode,
pos: getPos(),
parent: parentNode,
editorWidth: lineLength,
anchorRectCache: anchorRectCache,
position: "lower",
isNestedDropTarget: isNestedDropTarget,
api: api
}), isShowInlineDropTarget && (0, _react2.jsx)(_react.Fragment, null, (0, _react2.jsx)(_inlineDropTarget2.InlineDropTarget
// Ignored via go/ees005
// eslint-disable-next-line react/jsx-props-no-spreading
, (0, _extends2.default)({}, props, {
position: "left"
})), (0, _react2.jsx)(_inlineDropTarget2.InlineDropTarget
// Ignored via go/ees005
// eslint-disable-next-line react/jsx-props-no-spreading
, (0, _extends2.default)({}, props, {
position: "right"
}))));
};