@atlaskit/editor-plugin-block-controls
Version:
Block controls plugin for @atlaskit/editor-core
250 lines (247 loc) • 12.1 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.DropTargetLayoutNativeAnchorSupport = exports.DropTargetLayout = void 0;
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 _editorSharedStyles = require("@atlaskit/editor-shared-styles");
var _box = require("@atlaskit/pragmatic-drag-and-drop-react-drop-indicator/box");
var _adapter = require("@atlaskit/pragmatic-drag-and-drop/element/adapter");
var _expValEquals = require("@atlaskit/tmp-editor-statsig/exp-val-equals");
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 _updateSelection = require("../pm-plugins/utils/update-selection");
var _domAttrName = require("./utils/dom-attr-name");
/**
* @jsxRuntime classic
* @jsx jsx
*/
// eslint-disable-next-line @atlaskit/ui-styling-standard/use-compiled, @typescript-eslint/consistent-type-imports
// 8px gap + 16px on left and right
var DROP_TARGET_LAYOUT_DROP_ZONE_WIDTH = 40;
var dropTargetLayoutStyle = (0, _react2.css)({
height: '100%',
width: "".concat(DROP_TARGET_LAYOUT_DROP_ZONE_WIDTH, "px"),
transform: 'translateX(-50%)',
zIndex: 120,
position: 'relative',
display: 'flex',
justifyContent: 'center'
});
var dropTargetLayoutHintStyle = (0, _react2.css)({
height: '100%',
position: 'relative',
borderRight: "var(--ds-border-width, 1px)".concat(" dashed ", "var(--ds-border-focused, #4688EC)"),
width: 0
});
var DropTargetLayout = exports.DropTargetLayout = function DropTargetLayout(props) {
var _ref$current, _api$blockControls;
var api = props.api,
getPos = props.getPos,
parent = props.parent,
anchorRectCache = props.anchorRectCache;
var ref = (0, _react.useRef)(null);
var _useState = (0, _react.useState)(false),
_useState2 = (0, _slicedToArray2.default)(_useState, 2),
isDraggedOver = _useState2[0],
setIsDraggedOver = _useState2[1];
var anchorName = (0, _decorationsCommon.getNodeAnchor)(parent);
var nextNodeAnchorName = (_ref$current = ref.current) === null || _ref$current === void 0 || (_ref$current = _ref$current.parentElement) === null || _ref$current === void 0 || (_ref$current = _ref$current.nextElementSibling) === null || _ref$current === void 0 ? void 0 : _ref$current.getAttribute((0, _domAttrName.getAnchorAttrName)());
var height = '100%';
if (nextNodeAnchorName) {
if ((0, _anchorUtils.isAnchorSupported)()) {
height = "anchor-size(".concat(nextNodeAnchorName, " height)");
} else if (anchorRectCache) {
var layoutColumnRect = anchorRectCache.getRect(nextNodeAnchorName);
height = "".concat((layoutColumnRect === null || layoutColumnRect === void 0 ? void 0 : layoutColumnRect.height) || 0, "px");
}
}
var dropTargetStackLayoutHintStyle = (0, _react2.css)((0, _defineProperty2.default)({}, "@container layout-area (max-width:".concat(_editorSharedStyles.layoutBreakpointWidth.MEDIUM - 1, "px)"), {
// eslint-disable-next-line @atlaskit/ui-styling-standard/no-unsafe-values
height: height,
marginTop: "var(--ds-space-050, 4px)"
}));
var _useActiveAnchorTrack = (0, _activeAnchorTracker.useActiveAnchorTracker)(anchorName),
_useActiveAnchorTrack2 = (0, _slicedToArray2.default)(_useActiveAnchorTrack, 1),
isActiveAnchor = _useActiveAnchorTrack2[0];
var _ref = (api === null || api === void 0 || (_api$blockControls = api.blockControls) === null || _api$blockControls === void 0 ? void 0 : _api$blockControls.sharedState.currentState()) || {},
activeNode = _ref.activeNode;
var onDrop = (0, _react.useCallback)(function () {
if (!activeNode) {
return;
}
var to = getPos();
var mappedTo;
if (to !== undefined) {
var _api$core, _api$core2;
var from = activeNode.pos;
api === null || api === void 0 || (_api$core = api.core) === null || _api$core === void 0 || _api$core.actions.execute(function (_ref2) {
var _api$blockControls2;
var tr = _ref2.tr;
api === null || api === void 0 || (_api$blockControls2 = api.blockControls) === null || _api$blockControls2 === void 0 || (_api$blockControls2 = _api$blockControls2.commands) === null || _api$blockControls2 === void 0 || _api$blockControls2.moveToLayout(from, to)({
tr: tr
});
var insertColumnStep = (0, _updateSelection.getInsertLayoutStep)(tr);
mappedTo = insertColumnStep === null || insertColumnStep === void 0 ? void 0 : insertColumnStep.from;
return tr;
});
api === null || api === void 0 || (_api$core2 = api.core) === null || _api$core2 === void 0 || _api$core2.actions.execute(function (_ref3) {
var tr = _ref3.tr;
if (mappedTo !== undefined) {
(0, _updateSelection.updateSelection)(tr, mappedTo);
}
return tr;
});
}
}, [api, getPos, activeNode]);
(0, _react.useEffect)(function () {
if (ref.current) {
return (0, _adapter.dropTargetForElements)({
element: ref.current,
onDragEnter: function onDragEnter() {
setIsDraggedOver(true);
},
onDragLeave: function onDragLeave() {
setIsDraggedOver(false);
},
onDrop: onDrop
});
}
}, [onDrop]);
if ((activeNode === null || activeNode === void 0 ? void 0 : activeNode.nodeType) === 'layoutSection') {
return null;
}
return (0, _react2.jsx)("div", {
ref: ref
// eslint-disable-next-line @atlaskit/design-system/consistent-css-prop-usage
,
css: [dropTargetLayoutStyle, dropTargetStackLayoutHintStyle],
"data-testid": "block-ctrl-drop-indicator"
}, isDraggedOver ? (0, _react2.jsx)(_box.DropIndicator, {
edge: "right",
gap: "-".concat(DROP_TARGET_LAYOUT_DROP_ZONE_WIDTH, "px")
}) : (isActiveAnchor || (0, _expValEquals.expValEquals)('platform_editor_native_anchor_with_dnd', 'isEnabled', true)) && (0, _react2.jsx)("div", {
"data-testid": "block-ctrl-drop-hint",
css: dropTargetLayoutHintStyle
}));
};
var DropTargetLayoutNativeAnchorSupport = exports.DropTargetLayoutNativeAnchorSupport = function DropTargetLayoutNativeAnchorSupport(props) {
var _api$blockControls3;
var api = props.api,
getPos = props.getPos,
parent = props.parent,
anchorRectCache = props.anchorRectCache;
var ref = (0, _react.useRef)(null);
var _useState3 = (0, _react.useState)(false),
_useState4 = (0, _slicedToArray2.default)(_useState3, 2),
isDraggedOver = _useState4[0],
setIsDraggedOver = _useState4[1];
var anchorName = (0, _decorationsCommon.getNodeAnchor)(parent);
var _useState5 = (0, _react.useState)(null),
_useState6 = (0, _slicedToArray2.default)(_useState5, 2),
nextNodeAnchorName = _useState6[0],
setNextNodeAnchorName = _useState6[1];
var readNextNodeAnchor = (0, _react.useCallback)(function () {
var _ref$current2, _nextElementSibling$g;
var nextElementSibling = (_ref$current2 = ref.current) === null || _ref$current2 === void 0 || (_ref$current2 = _ref$current2.parentElement) === null || _ref$current2 === void 0 ? void 0 : _ref$current2.nextElementSibling;
var attrName = (0, _domAttrName.getAnchorAttrName)();
var nextAnchorName = (_nextElementSibling$g = nextElementSibling === null || nextElementSibling === void 0 ? void 0 : nextElementSibling.getAttribute(attrName)) !== null && _nextElementSibling$g !== void 0 ? _nextElementSibling$g : null;
setNextNodeAnchorName(function (prev) {
return prev === nextAnchorName ? prev : nextAnchorName;
});
}, []);
var height = (0, _react.useMemo)(function () {
if (nextNodeAnchorName) {
if ((0, _anchorUtils.isAnchorSupported)()) {
return "anchor-size(".concat(nextNodeAnchorName, " height)");
} else if (anchorRectCache) {
var layoutColumnRect = anchorRectCache.getRect(nextNodeAnchorName);
return "".concat((layoutColumnRect === null || layoutColumnRect === void 0 ? void 0 : layoutColumnRect.height) || 0, "px");
}
}
// Stacked mode fallback: minimal height to avoid oversized hint on first render
return '0px';
}, [nextNodeAnchorName, anchorRectCache]);
(0, _react.useLayoutEffect)(function () {
var raf = requestAnimationFrame(function () {
readNextNodeAnchor();
});
return function () {
return cancelAnimationFrame(raf);
};
}, [readNextNodeAnchor]);
var dropTargetStackLayoutHintStyle = (0, _react2.css)((0, _defineProperty2.default)({}, "@container layout-area (max-width:".concat(_editorSharedStyles.layoutBreakpointWidth.MEDIUM - 1, "px)"), {
// eslint-disable-next-line @atlaskit/ui-styling-standard/no-unsafe-values
height: height,
marginTop: "var(--ds-space-050, 4px)"
}));
var _useActiveAnchorTrack3 = (0, _activeAnchorTracker.useActiveAnchorTracker)(anchorName),
_useActiveAnchorTrack4 = (0, _slicedToArray2.default)(_useActiveAnchorTrack3, 1),
isActiveAnchor = _useActiveAnchorTrack4[0];
var _ref4 = (api === null || api === void 0 || (_api$blockControls3 = api.blockControls) === null || _api$blockControls3 === void 0 ? void 0 : _api$blockControls3.sharedState.currentState()) || {},
activeNode = _ref4.activeNode;
var onDrop = (0, _react.useCallback)(function () {
if (!activeNode) {
return;
}
var to = getPos();
var mappedTo;
if (to !== undefined) {
var _api$core3, _api$core4;
var from = activeNode.pos;
api === null || api === void 0 || (_api$core3 = api.core) === null || _api$core3 === void 0 || _api$core3.actions.execute(function (_ref5) {
var _api$blockControls4;
var tr = _ref5.tr;
api === null || api === void 0 || (_api$blockControls4 = api.blockControls) === null || _api$blockControls4 === void 0 || (_api$blockControls4 = _api$blockControls4.commands) === null || _api$blockControls4 === void 0 || _api$blockControls4.moveToLayout(from, to)({
tr: tr
});
var insertColumnStep = (0, _updateSelection.getInsertLayoutStep)(tr);
mappedTo = insertColumnStep === null || insertColumnStep === void 0 ? void 0 : insertColumnStep.from;
return tr;
});
api === null || api === void 0 || (_api$core4 = api.core) === null || _api$core4 === void 0 || _api$core4.actions.execute(function (_ref6) {
var tr = _ref6.tr;
if (mappedTo !== undefined) {
(0, _updateSelection.updateSelection)(tr, mappedTo);
}
return tr;
});
}
}, [api, getPos, activeNode]);
(0, _react.useEffect)(function () {
if (ref.current) {
return (0, _adapter.dropTargetForElements)({
element: ref.current,
onDragEnter: function onDragEnter() {
setIsDraggedOver(true);
readNextNodeAnchor();
},
onDragLeave: function onDragLeave() {
setIsDraggedOver(false);
},
onDrop: onDrop
});
}
}, [onDrop, readNextNodeAnchor]);
if ((activeNode === null || activeNode === void 0 ? void 0 : activeNode.nodeType) === 'layoutSection') {
return null;
}
return (0, _react2.jsx)("div", {
ref: ref
// eslint-disable-next-line @atlaskit/design-system/consistent-css-prop-usage
,
css: [dropTargetLayoutStyle, dropTargetStackLayoutHintStyle],
"data-testid": "block-ctrl-drop-indicator"
}, isDraggedOver ? (0, _react2.jsx)(_box.DropIndicator, {
edge: "right",
gap: "-".concat(DROP_TARGET_LAYOUT_DROP_ZONE_WIDTH, "px")
}) : (isActiveAnchor || (0, _expValEquals.expValEquals)('platform_editor_native_anchor_with_dnd', 'isEnabled', true)) && (0, _react2.jsx)("div", {
"data-testid": "block-ctrl-drop-hint",
css: dropTargetLayoutHintStyle
}));
};