UNPKG

@atlaskit/editor-plugin-block-controls

Version:

Block controls plugin for @atlaskit/editor-core

243 lines (241 loc) 11.1 kB
import _defineProperty from "@babel/runtime/helpers/defineProperty"; import _slicedToArray from "@babel/runtime/helpers/slicedToArray"; /** * @jsxRuntime classic * @jsx jsx */ import { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react'; // eslint-disable-next-line @atlaskit/ui-styling-standard/use-compiled, @typescript-eslint/consistent-type-imports import { css, jsx } from '@emotion/react'; import { layoutBreakpointWidth } from '@atlaskit/editor-shared-styles'; import { DropIndicator } from '@atlaskit/pragmatic-drag-and-drop-react-drop-indicator/box'; import { dropTargetForElements } from '@atlaskit/pragmatic-drag-and-drop/element/adapter'; import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals'; import { getNodeAnchor } from '../pm-plugins/decorations-common'; import { useActiveAnchorTracker } from '../pm-plugins/utils/active-anchor-tracker'; import { isAnchorSupported } from '../pm-plugins/utils/anchor-utils'; import { getInsertLayoutStep, updateSelection } from '../pm-plugins/utils/update-selection'; import { getAnchorAttrName } from './utils/dom-attr-name'; // 8px gap + 16px on left and right var DROP_TARGET_LAYOUT_DROP_ZONE_WIDTH = 40; var dropTargetLayoutStyle = 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 = css({ height: '100%', position: 'relative', borderRight: "var(--ds-border-width, 1px)".concat(" dashed ", "var(--ds-border-focused, #4688EC)"), width: 0 }); export var DropTargetLayout = function DropTargetLayout(props) { var _ref$current, _api$blockControls; var api = props.api, getPos = props.getPos, parent = props.parent, anchorRectCache = props.anchorRectCache; var ref = useRef(null); var _useState = useState(false), _useState2 = _slicedToArray(_useState, 2), isDraggedOver = _useState2[0], setIsDraggedOver = _useState2[1]; var anchorName = 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(getAnchorAttrName()); var height = '100%'; if (nextNodeAnchorName) { if (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 = css(_defineProperty({}, "@container layout-area (max-width:".concat(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 = useActiveAnchorTracker(anchorName), _useActiveAnchorTrack2 = _slicedToArray(_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 = 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 = 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) { updateSelection(tr, mappedTo); } return tr; }); } }, [api, getPos, activeNode]); useEffect(function () { if (ref.current) { return 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 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 ? jsx(DropIndicator, { edge: "right", gap: "-".concat(DROP_TARGET_LAYOUT_DROP_ZONE_WIDTH, "px") }) : (isActiveAnchor || expValEquals('platform_editor_native_anchor_with_dnd', 'isEnabled', true)) && jsx("div", { "data-testid": "block-ctrl-drop-hint", css: dropTargetLayoutHintStyle })); }; export var DropTargetLayoutNativeAnchorSupport = function DropTargetLayoutNativeAnchorSupport(props) { var _api$blockControls3; var api = props.api, getPos = props.getPos, parent = props.parent, anchorRectCache = props.anchorRectCache; var ref = useRef(null); var _useState3 = useState(false), _useState4 = _slicedToArray(_useState3, 2), isDraggedOver = _useState4[0], setIsDraggedOver = _useState4[1]; var anchorName = getNodeAnchor(parent); var _useState5 = useState(null), _useState6 = _slicedToArray(_useState5, 2), nextNodeAnchorName = _useState6[0], setNextNodeAnchorName = _useState6[1]; var readNextNodeAnchor = 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 = 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 = useMemo(function () { if (nextNodeAnchorName) { if (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]); useLayoutEffect(function () { var raf = requestAnimationFrame(function () { readNextNodeAnchor(); }); return function () { return cancelAnimationFrame(raf); }; }, [readNextNodeAnchor]); var dropTargetStackLayoutHintStyle = css(_defineProperty({}, "@container layout-area (max-width:".concat(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 = useActiveAnchorTracker(anchorName), _useActiveAnchorTrack4 = _slicedToArray(_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 = 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 = 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) { updateSelection(tr, mappedTo); } return tr; }); } }, [api, getPos, activeNode]); useEffect(function () { if (ref.current) { return 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 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 ? jsx(DropIndicator, { edge: "right", gap: "-".concat(DROP_TARGET_LAYOUT_DROP_ZONE_WIDTH, "px") }) : (isActiveAnchor || expValEquals('platform_editor_native_anchor_with_dnd', 'isEnabled', true)) && jsx("div", { "data-testid": "block-ctrl-drop-hint", css: dropTargetLayoutHintStyle })); };