@atlaskit/editor-plugin-code-block
Version:
Code block plugin for @atlaskit/editor-core
173 lines (170 loc) • 9.54 kB
JavaScript
;
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.createPlugin = void 0;
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _browser = require("@atlaskit/editor-common/browser");
var _codeBlock = require("@atlaskit/editor-common/code-block");
var _messages = require("@atlaskit/editor-common/messages");
var _safePlugin = require("@atlaskit/editor-common/safe-plugin");
var _selection = require("@atlaskit/editor-common/selection");
var _transforms = require("@atlaskit/editor-common/transforms");
var _state = require("@atlaskit/editor-prosemirror/state");
var _view = require("@atlaskit/editor-prosemirror/view");
var _expValEquals = require("@atlaskit/tmp-editor-statsig/exp-val-equals");
var _editorCommands = require("../editor-commands");
var _codeBlock2 = require("../nodeviews/code-block");
var _classNames = require("../ui/class-names");
var _actions = require("./actions");
var _decorators = require("./decorators");
var _pluginKey = require("./plugin-key");
var _utils = require("./utils");
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
var createPlugin = exports.createPlugin = function createPlugin(_ref) {
var _ref$useLongPressSele = _ref.useLongPressSelection,
useLongPressSelection = _ref$useLongPressSele === void 0 ? false : _ref$useLongPressSele,
getIntl = _ref.getIntl,
_ref$allowComposition = _ref.allowCompositionInputOverride,
allowCompositionInputOverride = _ref$allowComposition === void 0 ? false : _ref$allowComposition,
api = _ref.api;
var handleDOMEvents = {
click: function click() {
var _api$core, _api$interaction;
// Set hasHadInteraction to true on any click of code blocks, as clicks
// on code blocks to not propagate to editor-level click handlers
api === null || api === void 0 || (_api$core = api.core) === null || _api$core === void 0 || _api$core.actions.execute(api === null || api === void 0 || (_api$interaction = api.interaction) === null || _api$interaction === void 0 ? void 0 : _api$interaction.commands.handleInteraction);
}
};
// ME-1599: Composition on mobile was causing the DOM observer to mutate the code block
// incorrecly and lose content when pressing enter in the middle of a code block line.
if (allowCompositionInputOverride) {
handleDOMEvents.beforeinput = function (view, event) {
var keyEvent = event;
var eventInputType = keyEvent.inputType;
var eventText = keyEvent.data;
var browser = (0, _browser.getBrowserInfo)();
if (browser.ios && event.composed &&
// insertParagraph will be the input type when the enter key is pressed.
eventInputType === 'insertParagraph' && (0, _transforms.findCodeBlock)(view.state, view.state.selection)) {
event.preventDefault();
return true;
} else if (browser.android && event.composed && eventInputType === 'insertCompositionText' && eventText[(eventText === null || eventText === void 0 ? void 0 : eventText.length) - 1] === '\n' && (0, _transforms.findCodeBlock)(view.state, view.state.selection)) {
// Ignored via go/ees005
// eslint-disable-next-line @typescript-eslint/no-explicit-any
var resultingText = event.target.outerText + '\n';
if (resultingText.endsWith(eventText)) {
// End of paragraph
setTimeout(function () {
view.someProp('handleKeyDown', function (f) {
return f(view, new KeyboardEvent('keydown', {
bubbles: true,
cancelable: true,
key: 'Enter',
code: 'Enter'
}));
});
}, 0);
} else {
// Middle of paragraph, end of line
(0, _editorCommands.ignoreFollowingMutations)(view.state, view.dispatch);
}
return true;
}
if (browser.android) {
(0, _editorCommands.resetShouldIgnoreFollowingMutations)(view.state, view.dispatch);
}
return false;
};
}
return new _safePlugin.SafePlugin({
state: {
init: function init(_, state) {
var node = (0, _transforms.findCodeBlock)(state, state.selection);
var initialDecorations =
// Disabled when using advanced code block advanced since it interfers with styling
// Long term we will deprecate the code block plugin and move all the related logic to
// the advanced plugin
// @ts-expect-error Code block advanced cannot depend on code block
(api === null || api === void 0 ? void 0 : api.codeBlockAdvanced) !== undefined && (0, _expValEquals.expValEquals)('platform_editor_code_block_fold_gutter', 'isEnabled', true) ? [] : (0, _decorators.generateInitialDecorations)(state);
return {
pos: node ? node.pos : null,
contentCopied: false,
isNodeSelected: false,
shouldIgnoreFollowingMutations: false,
decorations: _view.DecorationSet.create(state.doc, initialDecorations)
};
},
apply: function apply(tr, pluginState, _oldState, newState) {
var meta = tr.getMeta(_pluginKey.pluginKey);
if ((meta === null || meta === void 0 ? void 0 : meta.type) === _actions.ACTIONS.SET_IS_WRAPPED) {
var node = (0, _transforms.findCodeBlock)(newState, tr.selection);
return _objectSpread(_objectSpread({}, pluginState), {}, {
decorations: (0, _decorators.updateDecorationSetWithWordWrappedDecorator)(pluginState.decorations, tr, node)
});
}
if (tr.docChanged) {
var _node = (0, _transforms.findCodeBlock)(newState, tr.selection);
// Updates mapping position of all existing decorations to new positions
// specifically used for updating word wrap node decorators (does not cover drag & drop, validateWordWrappedDecorators does).
var updatedDecorationSet = pluginState.decorations.map(tr.mapping, tr.doc);
var codeBlockNodes = (0, _utils.getAllChangedCodeBlocksInTransaction)(tr);
if (codeBlockNodes) {
(0, _codeBlock.updateCodeBlockWrappedStateNodeKeys)(codeBlockNodes, _oldState);
// Disabled when using advanced code block for performance reasons
// @ts-expect-error Code block advanced cannot depend on code block
if ((api === null || api === void 0 ? void 0 : api.codeBlockAdvanced) === undefined) {
updatedDecorationSet = (0, _decorators.updateCodeBlockDecorations)(tr, codeBlockNodes, updatedDecorationSet);
}
}
var newPluginState = _objectSpread(_objectSpread({}, pluginState), {}, {
pos: _node ? _node.pos : null,
isNodeSelected: tr.selection instanceof _state.NodeSelection,
decorations: updatedDecorationSet
});
return newPluginState;
}
if (tr.selectionSet) {
var _node2 = (0, _transforms.findCodeBlock)(newState, tr.selection);
var _newPluginState = _objectSpread(_objectSpread({}, pluginState), {}, {
pos: _node2 ? _node2.pos : null,
isNodeSelected: tr.selection instanceof _state.NodeSelection
});
return _newPluginState;
}
if ((meta === null || meta === void 0 ? void 0 : meta.type) === _actions.ACTIONS.SET_COPIED_TO_CLIPBOARD) {
return _objectSpread(_objectSpread({}, pluginState), {}, {
contentCopied: meta.data
});
} else if ((meta === null || meta === void 0 ? void 0 : meta.type) === _actions.ACTIONS.SET_SHOULD_IGNORE_FOLLOWING_MUTATIONS) {
return _objectSpread(_objectSpread({}, pluginState), {}, {
shouldIgnoreFollowingMutations: meta.data
});
}
return pluginState;
}
},
key: _pluginKey.pluginKey,
props: {
decorations: function decorations(state) {
return _pluginKey.pluginKey.getState(state).decorations || _view.DecorationSet.empty;
},
nodeViews: {
codeBlock: function codeBlock(node, view, getPos) {
var _getIntl = getIntl(),
formatMessage = _getIntl.formatMessage;
var formattedAriaLabel = formatMessage(_messages.blockTypeMessages.codeblock);
return (0, _codeBlock2.codeBlockNodeView)(node, view, getPos, formattedAriaLabel, api);
}
},
handleClickOn: (0, _selection.createSelectionClickHandler)(['codeBlock'], function (target) {
return !!(target.classList.contains(_classNames.codeBlockClassNames.lineNumberWidget) || target.classList.contains(_classNames.codeBlockClassNames.gutter));
}, {
useLongPressSelection: useLongPressSelection
}),
handleDOMEvents: handleDOMEvents
}
});
};