@atlaskit/editor-plugin-block-controls
Version:
Block controls plugin for @atlaskit/editor-core
160 lines (156 loc) • 6.89 kB
JavaScript
import _defineProperty from "@babel/runtime/helpers/defineProperty";
import { createElement } from 'react';
import { bind } from 'bind-event-listener';
import ReactDOM from 'react-dom';
// eslint-disable-next-line @atlaskit/platform/prefer-crypto-random-uuid -- Use crypto.randomUUID instead
import uuid from 'uuid';
import { Decoration } from '@atlaskit/editor-prosemirror/view';
import { fg } from '@atlaskit/platform-feature-flags';
import { expValEquals } from '@atlaskit/tmp-editor-statsig/exp-val-equals';
import { editorExperiment } from '@atlaskit/tmp-editor-statsig/experiments';
import { DragHandle, DragHandleWithVisibility } from '../ui/drag-handle';
import { TYPE_HANDLE_DEC, TYPE_NODE_DEC, unmountDecorations } from './decorations-common';
import { getActiveBlockMarks, getMatchingBlockMarks } from './utils/marks';
export var emptyParagraphNodeDecorations = function emptyParagraphNodeDecorations() {
var anchorName = "--node-anchor-paragraph-0";
var style = "anchor-name: ".concat(anchorName, "; margin-top: 0px;");
return Decoration.node(0, 2, _defineProperty({
style: style
}, 'data-drag-handler-anchor-name', anchorName), {
type: TYPE_NODE_DEC
});
};
export var findHandleDec = function findHandleDec(decorations, from, to) {
return decorations.find(from, to, function (spec) {
return spec.type === TYPE_HANDLE_DEC;
});
};
export var dragHandleDecoration = function dragHandleDecoration(_ref) {
var api = _ref.api,
formatMessage = _ref.formatMessage,
pos = _ref.pos,
anchorName = _ref.anchorName,
nodeType = _ref.nodeType,
nodeViewPortalProviderAPI = _ref.nodeViewPortalProviderAPI,
handleOptions = _ref.handleOptions,
anchorRectCache = _ref.anchorRectCache,
editorState = _ref.editorState;
unmountDecorations(nodeViewPortalProviderAPI, 'data-blocks-drag-handle-container', 'data-blocks-drag-handle-key');
var unbind;
// eslint-disable-next-line @atlaskit/platform/prefer-crypto-random-uuid -- Use crypto.randomUUID instead
var key = uuid();
var widgetSpec = editorExperiment('platform_editor_breakout_resizing', true) ? {
side: -1,
type: TYPE_HANDLE_DEC,
// eslint-disable-next-line @atlaskit/platform/prefer-crypto-random-uuid -- Use crypto.randomUUID instead
testid: "".concat(TYPE_HANDLE_DEC, "-").concat(uuid()),
/**
* sigh - `marks` influences the position that the widget is drawn (as described on the `side` property).
* Exclude 'breakout' on purpose, so the widgets render at the top of the document to avoid z-index issues
* Other block marks must be added, otherwise PM will split the DOM elements causing mutations and re-draws
*/
marks: expValEquals('platform_editor_small_font_size', 'isEnabled', true) ? getMatchingBlockMarks(editorState, pos, [editorState.schema.marks.alignment, editorState.schema.marks.fontSize]) : expValEquals('platform_editor_clean_up_widget_mark_logic', 'isEnabled', true) ? [] : getActiveBlockMarks(editorState, pos),
destroy: function destroy(node) {
unbind && unbind();
}
} : {
side: -1,
type: TYPE_HANDLE_DEC,
// eslint-disable-next-line @atlaskit/platform/prefer-crypto-random-uuid -- Use crypto.randomUUID instead
testid: "".concat(TYPE_HANDLE_DEC, "-").concat(uuid()),
marks: expValEquals('platform_editor_small_font_size', 'isEnabled', true) ? getMatchingBlockMarks(editorState, pos, [editorState.schema.marks.alignment, editorState.schema.marks.fontSize]) : expValEquals('platform_editor_clean_up_widget_mark_logic', 'isEnabled', true) ? [] : expValEquals('platform_editor_native_anchor_with_dnd', 'isEnabled', true) ? getActiveBlockMarks(editorState, pos) : undefined,
destroy: function destroy(node) {
unbind && unbind();
}
};
return Decoration.widget(pos, function (view, getPosUnsafe) {
var element = document.createElement('span');
// inline decoration causes focus issues when refocusing Editor into first line
element.style.display = 'block';
if (fg('confluence_remix_button_right_side_block_fg')) {
element.setAttribute('data-blocks-decorator-widget', 'true');
}
element.setAttribute('data-testid', 'block-ctrl-decorator-widget');
element.setAttribute('data-blocks-drag-handle-container', 'true');
element.setAttribute('data-blocks-drag-handle-key', key);
var isTopLevelNode = true;
var getPos = function getPos() {
try {
return getPosUnsafe();
} catch (_unused) {
// Ignore errors from getPosUnsafe
return undefined;
}
};
var newPos = getPos();
if (typeof newPos === 'number') {
var $pos = view.state.doc.resolve(newPos);
isTopLevelNode = ($pos === null || $pos === void 0 ? void 0 : $pos.parent.type.name) === 'doc';
}
/*
* We disable mouseover event to fix flickering issue on hover
* However, the tooltip for nested drag handle is no long working.
*/
if (newPos === undefined || !isTopLevelNode) {
if (fg('platform_editor_fix_widget_destroy')) {
element.onmouseover = function (e) {
e.stopPropagation();
};
} else {
unbind = bind(element, {
type: 'mouseover',
listener: function listener(e) {
e.stopPropagation();
}
});
}
}
// There are times when global clear: "both" styles are applied to this decoration causing jumpiness
// due to margins applied to other nodes eg. Headings
element.style.clear = 'unset';
// temporarily re-instating ReactDOM.render to fix drag handle focus issue, fix to
// follow via ED-26546
// previous under platform_editor_react18_plugin_portalprovider
// nodeViewPortalProviderAPI.render(
// () =>
// createElement(DragHandle, {
// view,
// api,
// formatMessage,
// getPos,
// anchorName,
// nodeType,
// handleOptions,
// isTopLevelNode,
// }),
// element,
// key,
// );
if (editorExperiment('platform_editor_controls', 'variant1')) {
ReactDOM.render( /*#__PURE__*/createElement(DragHandleWithVisibility, {
view: view,
api: api,
formatMessage: formatMessage,
getPos: getPos,
anchorName: anchorName,
nodeType: nodeType,
handleOptions: handleOptions,
isTopLevelNode: isTopLevelNode,
anchorRectCache: anchorRectCache
}), element);
} else {
ReactDOM.render( /*#__PURE__*/createElement(DragHandle, {
view: view,
api: api,
formatMessage: formatMessage,
getPos: getPos,
anchorName: anchorName,
nodeType: nodeType,
handleOptions: handleOptions,
isTopLevelNode: isTopLevelNode,
anchorRectCache: anchorRectCache
}), element);
}
return element;
}, widgetSpec);
};