@atlaskit/editor-plugin-code-block
Version:
Code block plugin for @atlaskit/editor-core
103 lines (101 loc) • 3.63 kB
JavaScript
import { getSelectedNodeOrNodeParentByNodeType } from '@atlaskit/editor-common/copy-button';
import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
import { PluginKey } from '@atlaskit/editor-prosemirror/state';
import { Decoration, DecorationSet } from '@atlaskit/editor-prosemirror/view';
export const copySelectionPluginKey = new PluginKey('codeBlockCopySelectionPlugin');
function getSelectionDecorationStartAndEnd({
state,
transaction
}) {
const codeBlockNode = getSelectedNodeOrNodeParentByNodeType({
nodeType: state.schema.nodes.codeBlock,
selection: transaction.selection
});
if (!codeBlockNode) {
return {
decorationStartAndEnd: undefined,
codeBlockNode: undefined
};
}
const decorationStartAndEnd = [codeBlockNode.start, codeBlockNode.start + codeBlockNode.node.nodeSize];
return {
decorationStartAndEnd,
codeBlockNode: codeBlockNode.node
};
}
export function codeBlockCopySelectionPlugin() {
return new SafePlugin({
key: copySelectionPluginKey,
state: {
init() {
return {
decorationStartAndEnd: undefined
};
},
apply(transaction, currentCodeBlockCopySelectionPluginState, _oldState, newState) {
switch (transaction.getMeta(copySelectionPluginKey)) {
case 'show-selection':
{
return getSelectionDecorationStartAndEnd({
state: newState,
transaction
});
}
case 'remove-selection':
return {
decorationStartAndEnd: undefined
};
default:
// The contents of the code block can change while the selection is being shown
// (either from collab edits -- or from the user continuing to type while hovering
// the mouse over the copy button).
// This ensures the selection is updated in these cases.
if (currentCodeBlockCopySelectionPluginState.decorationStartAndEnd !== undefined) {
return getSelectionDecorationStartAndEnd({
state: newState,
transaction
});
}
return currentCodeBlockCopySelectionPluginState;
}
}
},
props: {
decorations(state) {
if (copySelectionPluginKey.getState(state).decorationStartAndEnd) {
const [start, end] = copySelectionPluginKey.getState(state).decorationStartAndEnd;
return DecorationSet.create(state.doc, [Decoration.inline(start, end, {
class: 'ProseMirror-fake-text-selection'
})]);
}
return DecorationSet.empty;
}
}
});
}
export function provideVisualFeedbackForCopyButton(state, dispatch) {
const tr = state.tr;
tr.setMeta(copySelectionPluginKey, 'show-selection');
// note: dispatch should always be defined when called from the
// floating toolbar. Howver the Command type which the floating toolbar
// uses suggests it's optional.
// Using the type here to protect against future refactors of the
// floating toolbar
if (dispatch) {
dispatch(tr);
}
return true;
}
export function removeVisualFeedbackForCopyButton(state, dispatch) {
const tr = state.tr;
tr.setMeta(copySelectionPluginKey, 'remove-selection');
// note: dispatch should always be defined when called from the
// floating toolbar. Howver the Command type which the floating toolbar
// uses suggests it's optional.
// Using the type here to protect against future refactors of the
// floating toolbar
if (dispatch) {
dispatch(tr);
}
return true;
}