@atlaskit/editor-plugin-paste-options-toolbar
Version:
Paste options toolbar for @atlaskit/editor-core
106 lines (105 loc) • 5.41 kB
JavaScript
import { pasteOptionsToolbarMessages as messages } from '@atlaskit/editor-common/messages';
import { akEditorFloatingPanelZIndex } from '@atlaskit/editor-shared-styles';
import { changeToMarkdownWithAnalytics, changeToPlainTextWithAnalytics, changeToRichTextWithAnalytics, dropdownClickHandler } from '../editor-commands/commands';
import { PASTE_OPTIONS_TEST_ID, PASTE_TOOLBAR_CLASS, PASTE_TOOLBAR_ITEM_CLASS } from '../pm-plugins/constants';
import { hasLinkMark, hasMediaNode, hasRuleNode, isPastedFromFabricEditor } from '../pm-plugins/util';
import { pasteOptionsPluginKey, ToolbarDropdownOption } from '../types/types';
import EditorPasteIcon from './paste-icon';
export const isToolbarVisible = (state, lastContentPasted) => {
var _$from$parent, _$from$node, _state$schema$nodes$c;
/**
* Conditions for not showing the toolbar:
* 1. Pasting link, media or text containing media(note: markdown link and images are allowed)
* 2. Content is pasted in a nested node(i.e. inside a table, panel etc.).
* (grandParent node should be root doc for showing up the toolbar)
* 3. Cursor is inside the codeblock.
*/
const $from = state.selection.$from;
if (hasRuleNode(lastContentPasted.pastedSlice, state.schema)) {
return false;
}
const parentNodeType = (_$from$parent = $from.parent) === null || _$from$parent === void 0 ? void 0 : _$from$parent.type;
const grandParentNodeType = (_$from$node = $from.node($from.depth - 1)) === null || _$from$node === void 0 ? void 0 : _$from$node.type;
if (grandParentNodeType && grandParentNodeType.name === state.schema.nodes.doc.name && parentNodeType.name !== ((_state$schema$nodes$c = state.schema.nodes.codeBlock) === null || _state$schema$nodes$c === void 0 ? void 0 : _state$schema$nodes$c.name) && !isPastedFromFabricEditor(lastContentPasted.pasteSource) && !hasLinkMark(lastContentPasted.pastedSlice) && !hasMediaNode(lastContentPasted.pastedSlice)) {
return true;
}
return false;
};
export const getToolbarMenuConfig = (pluginState, intl, editorAnalyticsAPI) => {
const options = [{
id: 'editor.paste.richText',
title: intl.formatMessage(messages.richText),
selected: pluginState.selectedOption === ToolbarDropdownOption.RichText,
hidden: pluginState.isPlainText,
onClick: changeToRichTextWithAnalytics(editorAnalyticsAPI)()
}, {
id: 'editor.paste.markdown',
title: intl.formatMessage(messages.markdown),
selected: pluginState.selectedOption === ToolbarDropdownOption.Markdown,
onClick: changeToMarkdownWithAnalytics(editorAnalyticsAPI, pluginState.plaintext.length)()
}, {
id: 'editor.paste.plainText',
title: intl.formatMessage(messages.plainText),
selected: pluginState.selectedOption === ToolbarDropdownOption.PlainText,
onClick: changeToPlainTextWithAnalytics(editorAnalyticsAPI, pluginState.plaintext.length)()
}];
return {
id: PASTE_TOOLBAR_ITEM_CLASS,
icon: EditorPasteIcon,
type: 'dropdown',
testId: PASTE_OPTIONS_TEST_ID,
title: intl.formatMessage(messages.pasteOptions),
options,
onToggle: onToggleHandler
};
};
const onToggleHandler = (state, dispatch) => {
return dropdownClickHandler()(state, dispatch);
};
export const buildToolbar = (state, intl, editorAnalyticsAPI) => {
const {
schema
} = state;
const validNodes = Object.values(schema.nodes);
const pluginState = pasteOptionsPluginKey.getState(state);
const menu = getToolbarMenuConfig(pluginState, intl, editorAnalyticsAPI);
return {
title: intl.formatMessage(messages.pasteOptions),
nodeType: validNodes,
zIndex: akEditorFloatingPanelZIndex,
className: PASTE_TOOLBAR_CLASS,
items: [menu],
align: 'right',
onPositionCalculated
};
};
const onPositionCalculated = (editorView, _nextPos) => {
const {
from
} = editorView.state.selection;
const fromCoords = editorView.coordsAtPos(from);
// Ignored via go/ees005
// eslint-disable-next-line @atlaskit/editor/no-as-casting
const toolbar = document.querySelector(`div[aria-label="${messages.pasteOptions.defaultMessage}"]`);
const offsetParent = (toolbar === null || toolbar === void 0 ? void 0 : toolbar.offsetParent) || editorView.dom;
const offsetParentRect = offsetParent === null || offsetParent === void 0 ? void 0 : offsetParent.getBoundingClientRect();
const offsetTop = (offsetParentRect === null || offsetParentRect === void 0 ? void 0 : offsetParentRect.top) || 0;
const offsetLeft = (offsetParentRect === null || offsetParentRect === void 0 ? void 0 : offsetParentRect.left) || 0;
const offsetScrollTop = (offsetParent === null || offsetParent === void 0 ? void 0 : offsetParent.scrollTop) || 0;
const cursorHeight = getCursorHeight(editorView, from);
return {
top: fromCoords.top - offsetTop + offsetScrollTop + cursorHeight,
left: fromCoords.left - offsetLeft
};
};
const getCursorHeight = (editorView, from) => {
const nodeAtFrom = editorView.domAtPos(from).node;
const nearestNonTextNode = (nodeAtFrom === null || nodeAtFrom === void 0 ? void 0 : nodeAtFrom.nodeType) === Node.TEXT_NODE ?
// Ignored via go/ees005
// eslint-disable-next-line @atlaskit/editor/no-as-casting
nodeAtFrom.parentNode :
// Ignored via go/ees005
// eslint-disable-next-line @atlaskit/editor/no-as-casting
nodeAtFrom;
return parseFloat(window.getComputedStyle(nearestNonTextNode, undefined).lineHeight || '');
};