UNPKG

@atlaskit/editor-plugin-code-block

Version:

Code block plugin for @atlaskit/editor-core

128 lines (125 loc) 7.1 kB
import { SafePlugin } from '@atlaskit/editor-common/safe-plugin'; import { filterCommand as filter } from '@atlaskit/editor-common/utils'; import { keydownHandler } from '@atlaskit/editor-prosemirror/keymap'; import { TextSelection } from '@atlaskit/editor-prosemirror/state'; import { setTextSelection } from '@atlaskit/editor-prosemirror/utils'; import { getAutoClosingBracketInfo, shouldAutoCloseBracket } from './ide-ux/bracket-handling'; import { indent, insertIndent, insertNewlineWithIndent, outdent } from './ide-ux/commands'; import { getEndOfCurrentLine, getLineInfo, getStartOfCurrentLine, isCursorInsideCodeBlock, isSelectionEntirelyInsideCodeBlock } from './ide-ux/line-handling'; import { isClosingCharacter, isCursorBeforeClosingCharacter } from './ide-ux/paired-character-handling'; import { getAutoClosingQuoteInfo, shouldAutoCloseQuote } from './ide-ux/quote-handling'; import { getCursor } from './utils'; var ideUX = function ideUX(pluginInjectionApi) { var _pluginInjectionApi$a; var editorAnalyticsAPI = pluginInjectionApi === null || pluginInjectionApi === void 0 || (_pluginInjectionApi$a = pluginInjectionApi.analytics) === null || _pluginInjectionApi$a === void 0 ? void 0 : _pluginInjectionApi$a.actions; return new SafePlugin({ props: { handleTextInput: function handleTextInput(view, from, to, text) { var _pluginInjectionApi$c; var state = view.state, dispatch = view.dispatch; var compositionPluginState = pluginInjectionApi === null || pluginInjectionApi === void 0 || (_pluginInjectionApi$c = pluginInjectionApi.composition) === null || _pluginInjectionApi$c === void 0 ? void 0 : _pluginInjectionApi$c.sharedState.currentState(); if (isCursorInsideCodeBlock(state) && !(compositionPluginState !== null && compositionPluginState !== void 0 && compositionPluginState.isComposing)) { var beforeText = getStartOfCurrentLine(state).text; var afterText = getEndOfCurrentLine(state).text; // If text is a closing bracket/quote and we've already inserted it, move the selection after if (isCursorBeforeClosingCharacter(afterText) && isClosingCharacter(text) && afterText.startsWith(text)) { dispatch(setTextSelection(to + text.length)(state.tr)); return true; } // Automatically add right-hand side bracket when user types the left bracket if (shouldAutoCloseBracket(beforeText, afterText)) { var _getAutoClosingBracke = getAutoClosingBracketInfo(beforeText + text, afterText), left = _getAutoClosingBracke.left, right = _getAutoClosingBracke.right; if (left && right) { var bracketPair = state.schema.text(text + right); var tr = state.tr.replaceWith(from, to, bracketPair); dispatch(setTextSelection(from + text.length)(tr)); return true; } } // Automatically add closing quote when user types a starting quote if (shouldAutoCloseQuote(beforeText, afterText)) { var _getAutoClosingQuoteI = getAutoClosingQuoteInfo(beforeText + text, afterText), leftQuote = _getAutoClosingQuoteI.left, rightQuote = _getAutoClosingQuoteI.right; if (leftQuote && rightQuote) { var quotePair = state.schema.text(text + rightQuote); var _tr = state.tr.replaceWith(from, to, quotePair); dispatch(setTextSelection(from + text.length)(_tr)); return true; } } } return false; }, handleKeyDown: keydownHandler({ Backspace: function Backspace(state, dispatch) { if (isCursorInsideCodeBlock(state)) { // Ignored via go/ees005 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion var $cursor = getCursor(state.selection); var beforeText = getStartOfCurrentLine(state).text; var afterText = getEndOfCurrentLine(state).text; var _getAutoClosingBracke2 = getAutoClosingBracketInfo(beforeText, afterText), leftBracket = _getAutoClosingBracke2.left, rightBracket = _getAutoClosingBracke2.right, hasTrailingMatchingBracket = _getAutoClosingBracke2.hasTrailingMatchingBracket; if (leftBracket && rightBracket && hasTrailingMatchingBracket && dispatch) { dispatch(state.tr.delete($cursor.pos - leftBracket.length, $cursor.pos + rightBracket.length)); return true; } var _getAutoClosingQuoteI2 = getAutoClosingQuoteInfo(beforeText, afterText), leftQuote = _getAutoClosingQuoteI2.left, rightQuote = _getAutoClosingQuoteI2.right, hasTrailingMatchingQuote = _getAutoClosingQuoteI2.hasTrailingMatchingQuote; if (leftQuote && rightQuote && hasTrailingMatchingQuote && dispatch) { dispatch(state.tr.delete($cursor.pos - leftQuote.length, $cursor.pos + rightQuote.length)); return true; } var _getLineInfo = getLineInfo(beforeText), _getLineInfo$indentTo = _getLineInfo.indentToken, size = _getLineInfo$indentTo.size, token = _getLineInfo$indentTo.token, indentText = _getLineInfo.indentText; if (beforeText === indentText) { if (indentText.endsWith(token.repeat(size)) && dispatch) { dispatch(state.tr.delete($cursor.pos - (size - indentText.length % size || size), $cursor.pos)); return true; } } } return false; }, Enter: filter(isSelectionEntirelyInsideCodeBlock, insertNewlineWithIndent), 'Mod-]': filter(isSelectionEntirelyInsideCodeBlock, indent(editorAnalyticsAPI)), 'Mod-[': filter(isSelectionEntirelyInsideCodeBlock, outdent(editorAnalyticsAPI)), Tab: filter(isSelectionEntirelyInsideCodeBlock, function (state, dispatch) { if (!dispatch) { return false; } if (isCursorInsideCodeBlock(state)) { return insertIndent(state, dispatch); } return indent(editorAnalyticsAPI)(state, dispatch); }), 'Shift-Tab': filter(isSelectionEntirelyInsideCodeBlock, outdent(editorAnalyticsAPI)), 'Mod-a': function ModA(state, dispatch) { if (isSelectionEntirelyInsideCodeBlock(state)) { var _state$selection = state.selection, $from = _state$selection.$from, $to = _state$selection.$to; var isFullCodeBlockSelection = $from.parentOffset === 0 && $to.parentOffset === $to.parent.nodeSize - 2; if (!isFullCodeBlockSelection && dispatch) { dispatch(state.tr.setSelection(TextSelection.create(state.doc, $from.start(), $to.end()))); return true; } } return false; } }) } }); }; export default ideUX;