@atlaskit/editor-plugin-code-block 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +1 -0
- package/LICENSE.md +13 -0
- package/README.md +30 -0
- package/dist/cjs/actions.js +201 -0
- package/dist/cjs/ide-ux/bracket-handling.js +35 -0
- package/dist/cjs/ide-ux/commands.js +115 -0
- package/dist/cjs/ide-ux/line-handling.js +81 -0
- package/dist/cjs/ide-ux/paired-character-handling.js +23 -0
- package/dist/cjs/ide-ux/quote-handling.js +40 -0
- package/dist/cjs/index.js +13 -0
- package/dist/cjs/language-list.js +62 -0
- package/dist/cjs/nodeviews/code-block.js +153 -0
- package/dist/cjs/plugin-key.js +8 -0
- package/dist/cjs/plugin.js +120 -0
- package/dist/cjs/pm-plugins/actions.js +10 -0
- package/dist/cjs/pm-plugins/codeBlockCopySelectionPlugin.js +113 -0
- package/dist/cjs/pm-plugins/ide-ux.js +132 -0
- package/dist/cjs/pm-plugins/input-rule.js +68 -0
- package/dist/cjs/pm-plugins/keymaps.js +66 -0
- package/dist/cjs/pm-plugins/main-state.js +10 -0
- package/dist/cjs/pm-plugins/main.js +114 -0
- package/dist/cjs/refresh-browser-selection.js +29 -0
- package/dist/cjs/toolbar.js +131 -0
- package/dist/cjs/transform-to-code-block.js +84 -0
- package/dist/cjs/types.js +5 -0
- package/dist/cjs/ui/class-names.js +15 -0
- package/dist/cjs/utils.js +28 -0
- package/dist/es2019/actions.js +211 -0
- package/dist/es2019/ide-ux/bracket-handling.js +27 -0
- package/dist/es2019/ide-ux/commands.js +115 -0
- package/dist/es2019/ide-ux/line-handling.js +75 -0
- package/dist/es2019/ide-ux/paired-character-handling.js +12 -0
- package/dist/es2019/ide-ux/quote-handling.js +32 -0
- package/dist/es2019/index.js +1 -0
- package/dist/es2019/language-list.js +51 -0
- package/dist/es2019/nodeviews/code-block.js +126 -0
- package/dist/es2019/plugin-key.js +2 -0
- package/dist/es2019/plugin.js +104 -0
- package/dist/es2019/pm-plugins/actions.js +4 -0
- package/dist/es2019/pm-plugins/codeBlockCopySelectionPlugin.js +101 -0
- package/dist/es2019/pm-plugins/ide-ux.js +135 -0
- package/dist/es2019/pm-plugins/input-rule.js +60 -0
- package/dist/es2019/pm-plugins/keymaps.js +58 -0
- package/dist/es2019/pm-plugins/main-state.js +2 -0
- package/dist/es2019/pm-plugins/main.js +102 -0
- package/dist/es2019/refresh-browser-selection.js +25 -0
- package/dist/es2019/toolbar.js +108 -0
- package/dist/es2019/transform-to-code-block.js +79 -0
- package/dist/es2019/types.js +1 -0
- package/dist/es2019/ui/class-names.js +9 -0
- package/dist/es2019/utils.js +4 -0
- package/dist/esm/actions.js +191 -0
- package/dist/esm/ide-ux/bracket-handling.js +29 -0
- package/dist/esm/ide-ux/commands.js +107 -0
- package/dist/esm/ide-ux/line-handling.js +73 -0
- package/dist/esm/ide-ux/paired-character-handling.js +16 -0
- package/dist/esm/ide-ux/quote-handling.js +34 -0
- package/dist/esm/index.js +1 -0
- package/dist/esm/language-list.js +52 -0
- package/dist/esm/nodeviews/code-block.js +146 -0
- package/dist/esm/plugin-key.js +2 -0
- package/dist/esm/plugin.js +113 -0
- package/dist/esm/pm-plugins/actions.js +4 -0
- package/dist/esm/pm-plugins/codeBlockCopySelectionPlugin.js +103 -0
- package/dist/esm/pm-plugins/ide-ux.js +126 -0
- package/dist/esm/pm-plugins/input-rule.js +62 -0
- package/dist/esm/pm-plugins/keymaps.js +59 -0
- package/dist/esm/pm-plugins/main-state.js +4 -0
- package/dist/esm/pm-plugins/main.js +107 -0
- package/dist/esm/refresh-browser-selection.js +25 -0
- package/dist/esm/toolbar.js +121 -0
- package/dist/esm/transform-to-code-block.js +77 -0
- package/dist/esm/types.js +1 -0
- package/dist/esm/ui/class-names.js +9 -0
- package/dist/esm/utils.js +4 -0
- package/dist/types/actions.d.ts +18 -0
- package/dist/types/ide-ux/bracket-handling.d.ts +12 -0
- package/dist/types/ide-ux/commands.d.ts +7 -0
- package/dist/types/ide-ux/line-handling.d.ts +25 -0
- package/dist/types/ide-ux/paired-character-handling.d.ts +2 -0
- package/dist/types/ide-ux/quote-handling.d.ts +12 -0
- package/dist/types/index.d.ts +3 -0
- package/dist/types/language-list.d.ts +942 -0
- package/dist/types/nodeviews/code-block.d.ts +21 -0
- package/dist/types/plugin-key.d.ts +2 -0
- package/dist/types/plugin.d.ts +19 -0
- package/dist/types/pm-plugins/actions.d.ts +4 -0
- package/dist/types/pm-plugins/codeBlockCopySelectionPlugin.d.ts +11 -0
- package/dist/types/pm-plugins/ide-ux.d.ts +5 -0
- package/dist/types/pm-plugins/input-rule.d.ts +3 -0
- package/dist/types/pm-plugins/keymaps.d.ts +4 -0
- package/dist/types/pm-plugins/main-state.d.ts +8 -0
- package/dist/types/pm-plugins/main.d.ts +10 -0
- package/dist/types/refresh-browser-selection.d.ts +5 -0
- package/dist/types/toolbar.d.ts +14 -0
- package/dist/types/transform-to-code-block.d.ts +3 -0
- package/dist/types/types.d.ts +6 -0
- package/dist/types/ui/class-names.d.ts +8 -0
- package/dist/types/utils.d.ts +4 -0
- package/dist/types-ts4.5/actions.d.ts +18 -0
- package/dist/types-ts4.5/ide-ux/bracket-handling.d.ts +12 -0
- package/dist/types-ts4.5/ide-ux/commands.d.ts +7 -0
- package/dist/types-ts4.5/ide-ux/line-handling.d.ts +25 -0
- package/dist/types-ts4.5/ide-ux/paired-character-handling.d.ts +2 -0
- package/dist/types-ts4.5/ide-ux/quote-handling.d.ts +12 -0
- package/dist/types-ts4.5/index.d.ts +3 -0
- package/dist/types-ts4.5/language-list.d.ts +1641 -0
- package/dist/types-ts4.5/nodeviews/code-block.d.ts +21 -0
- package/dist/types-ts4.5/plugin-key.d.ts +2 -0
- package/dist/types-ts4.5/plugin.d.ts +19 -0
- package/dist/types-ts4.5/pm-plugins/actions.d.ts +4 -0
- package/dist/types-ts4.5/pm-plugins/codeBlockCopySelectionPlugin.d.ts +14 -0
- package/dist/types-ts4.5/pm-plugins/ide-ux.d.ts +5 -0
- package/dist/types-ts4.5/pm-plugins/input-rule.d.ts +3 -0
- package/dist/types-ts4.5/pm-plugins/keymaps.d.ts +4 -0
- package/dist/types-ts4.5/pm-plugins/main-state.d.ts +8 -0
- package/dist/types-ts4.5/pm-plugins/main.d.ts +10 -0
- package/dist/types-ts4.5/refresh-browser-selection.d.ts +5 -0
- package/dist/types-ts4.5/toolbar.d.ts +14 -0
- package/dist/types-ts4.5/transform-to-code-block.d.ts +3 -0
- package/dist/types-ts4.5/types.d.ts +6 -0
- package/dist/types-ts4.5/ui/class-names.d.ts +8 -0
- package/dist/types-ts4.5/utils.d.ts +4 -0
- package/package.json +99 -0
- package/report.api.md +73 -0
- package/tmp/api-report-tmp.d.ts +45 -0
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
2
|
+
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; }
|
|
3
|
+
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) { _defineProperty(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; }
|
|
4
|
+
import React from 'react';
|
|
5
|
+
import { codeBlock } from '@atlaskit/adf-schema';
|
|
6
|
+
import { ACTION, ACTION_SUBJECT, ACTION_SUBJECT_ID, EVENT_TYPE, INPUT_METHOD } from '@atlaskit/editor-common/analytics';
|
|
7
|
+
import { blockTypeMessages } from '@atlaskit/editor-common/messages';
|
|
8
|
+
import { IconCode } from '@atlaskit/editor-common/quick-insert';
|
|
9
|
+
import { createInsertCodeBlockTransaction, insertCodeBlockWithAnalytics } from './actions';
|
|
10
|
+
import { codeBlockCopySelectionPlugin } from './pm-plugins/codeBlockCopySelectionPlugin';
|
|
11
|
+
import ideUX from './pm-plugins/ide-ux';
|
|
12
|
+
import { createCodeBlockInputRule } from './pm-plugins/input-rule';
|
|
13
|
+
import keymap from './pm-plugins/keymaps';
|
|
14
|
+
import { createPlugin } from './pm-plugins/main';
|
|
15
|
+
import refreshBrowserSelectionOnChange from './refresh-browser-selection';
|
|
16
|
+
import { getToolbarConfig } from './toolbar';
|
|
17
|
+
var codeBlockPlugin = function codeBlockPlugin(_ref) {
|
|
18
|
+
var options = _ref.config,
|
|
19
|
+
api = _ref.api;
|
|
20
|
+
return {
|
|
21
|
+
name: 'codeBlock',
|
|
22
|
+
nodes: function nodes() {
|
|
23
|
+
return [{
|
|
24
|
+
name: 'codeBlock',
|
|
25
|
+
node: codeBlock
|
|
26
|
+
}];
|
|
27
|
+
},
|
|
28
|
+
pmPlugins: function pmPlugins() {
|
|
29
|
+
return [{
|
|
30
|
+
name: 'codeBlock',
|
|
31
|
+
plugin: function plugin(_ref2) {
|
|
32
|
+
var _options$appearance;
|
|
33
|
+
var getIntl = _ref2.getIntl;
|
|
34
|
+
return createPlugin(_objectSpread(_objectSpread({}, options), {}, {
|
|
35
|
+
getIntl: getIntl,
|
|
36
|
+
appearance: (_options$appearance = options === null || options === void 0 ? void 0 : options.appearance) !== null && _options$appearance !== void 0 ? _options$appearance : 'comment'
|
|
37
|
+
}));
|
|
38
|
+
}
|
|
39
|
+
}, {
|
|
40
|
+
name: 'codeBlockInputRule',
|
|
41
|
+
plugin: function plugin(_ref3) {
|
|
42
|
+
var _api$analytics;
|
|
43
|
+
var schema = _ref3.schema;
|
|
44
|
+
return createCodeBlockInputRule(schema, api === null || api === void 0 || (_api$analytics = api.analytics) === null || _api$analytics === void 0 ? void 0 : _api$analytics.actions);
|
|
45
|
+
}
|
|
46
|
+
}, {
|
|
47
|
+
name: 'codeBlockIDEKeyBindings',
|
|
48
|
+
plugin: function plugin() {
|
|
49
|
+
return ideUX(api);
|
|
50
|
+
}
|
|
51
|
+
}, {
|
|
52
|
+
name: 'codeBlockKeyMap',
|
|
53
|
+
plugin: function plugin(_ref4) {
|
|
54
|
+
var schema = _ref4.schema;
|
|
55
|
+
return keymap(schema);
|
|
56
|
+
}
|
|
57
|
+
}, {
|
|
58
|
+
name: 'codeBlockCopySelection',
|
|
59
|
+
plugin: function plugin() {
|
|
60
|
+
return codeBlockCopySelectionPlugin();
|
|
61
|
+
}
|
|
62
|
+
}];
|
|
63
|
+
},
|
|
64
|
+
// Workaround for a firefox issue where dom selection is off sync
|
|
65
|
+
// https://product-fabric.atlassian.net/browse/ED-12442
|
|
66
|
+
onEditorViewStateUpdated: function onEditorViewStateUpdated(props) {
|
|
67
|
+
refreshBrowserSelectionOnChange(props.originalTransaction, props.newEditorState);
|
|
68
|
+
},
|
|
69
|
+
actions: {
|
|
70
|
+
/*
|
|
71
|
+
* Function will insert code block at current selection if block is empty or below current selection and set focus on it.
|
|
72
|
+
*/
|
|
73
|
+
insertCodeBlock: function insertCodeBlock(inputMethod) {
|
|
74
|
+
var _api$analytics2;
|
|
75
|
+
return insertCodeBlockWithAnalytics(inputMethod, api === null || api === void 0 || (_api$analytics2 = api.analytics) === null || _api$analytics2 === void 0 ? void 0 : _api$analytics2.actions);
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
pluginsOptions: {
|
|
79
|
+
quickInsert: function quickInsert(_ref5) {
|
|
80
|
+
var formatMessage = _ref5.formatMessage;
|
|
81
|
+
return [{
|
|
82
|
+
id: 'codeblock',
|
|
83
|
+
title: formatMessage(blockTypeMessages.codeblock),
|
|
84
|
+
description: formatMessage(blockTypeMessages.codeblockDescription),
|
|
85
|
+
keywords: ['code block'],
|
|
86
|
+
priority: 700,
|
|
87
|
+
keyshortcut: '```',
|
|
88
|
+
icon: function icon() {
|
|
89
|
+
return /*#__PURE__*/React.createElement(IconCode, null);
|
|
90
|
+
},
|
|
91
|
+
action: function action(_insert, state) {
|
|
92
|
+
var _api$analytics3;
|
|
93
|
+
var tr = createInsertCodeBlockTransaction({
|
|
94
|
+
state: state
|
|
95
|
+
});
|
|
96
|
+
api === null || api === void 0 || (_api$analytics3 = api.analytics) === null || _api$analytics3 === void 0 || _api$analytics3.actions.attachAnalyticsEvent({
|
|
97
|
+
action: ACTION.INSERTED,
|
|
98
|
+
actionSubject: ACTION_SUBJECT.DOCUMENT,
|
|
99
|
+
actionSubjectId: ACTION_SUBJECT_ID.CODE_BLOCK,
|
|
100
|
+
attributes: {
|
|
101
|
+
inputMethod: INPUT_METHOD.QUICK_INSERT
|
|
102
|
+
},
|
|
103
|
+
eventType: EVENT_TYPE.TRACK
|
|
104
|
+
})(tr);
|
|
105
|
+
return tr;
|
|
106
|
+
}
|
|
107
|
+
}];
|
|
108
|
+
},
|
|
109
|
+
floatingToolbar: getToolbarConfig(options === null || options === void 0 ? void 0 : options.allowCopyToClipboard, api)
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
};
|
|
113
|
+
export default codeBlockPlugin;
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
|
|
2
|
+
import { getSelectedNodeOrNodeParentByNodeType } from '@atlaskit/editor-common/copy-button';
|
|
3
|
+
import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
|
|
4
|
+
import { PluginKey } from '@atlaskit/editor-prosemirror/state';
|
|
5
|
+
import { Decoration, DecorationSet } from '@atlaskit/editor-prosemirror/view';
|
|
6
|
+
export var copySelectionPluginKey = new PluginKey('codeBlockCopySelectionPlugin');
|
|
7
|
+
function getSelectionDecorationStartAndEnd(_ref) {
|
|
8
|
+
var state = _ref.state,
|
|
9
|
+
transaction = _ref.transaction;
|
|
10
|
+
var codeBlockNode = getSelectedNodeOrNodeParentByNodeType({
|
|
11
|
+
nodeType: state.schema.nodes.codeBlock,
|
|
12
|
+
selection: transaction.selection
|
|
13
|
+
});
|
|
14
|
+
if (!codeBlockNode) {
|
|
15
|
+
return {
|
|
16
|
+
decorationStartAndEnd: undefined
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
var decorationStartAndEnd = [codeBlockNode.start, codeBlockNode.start + codeBlockNode.node.nodeSize];
|
|
20
|
+
return {
|
|
21
|
+
decorationStartAndEnd: decorationStartAndEnd
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
export function codeBlockCopySelectionPlugin() {
|
|
25
|
+
return new SafePlugin({
|
|
26
|
+
key: copySelectionPluginKey,
|
|
27
|
+
state: {
|
|
28
|
+
init: function init() {
|
|
29
|
+
return {
|
|
30
|
+
decorationStartAndEnd: undefined
|
|
31
|
+
};
|
|
32
|
+
},
|
|
33
|
+
apply: function apply(transaction, currentCodeBlockCopySelectionPluginState, _oldState, newState) {
|
|
34
|
+
switch (transaction.getMeta(copySelectionPluginKey)) {
|
|
35
|
+
case 'show-selection':
|
|
36
|
+
{
|
|
37
|
+
return getSelectionDecorationStartAndEnd({
|
|
38
|
+
state: newState,
|
|
39
|
+
transaction: transaction
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
case 'remove-selection':
|
|
43
|
+
return {
|
|
44
|
+
decorationStartAndEnd: undefined
|
|
45
|
+
};
|
|
46
|
+
default:
|
|
47
|
+
// The contents of the code block can change while the selection is being shown
|
|
48
|
+
// (either from collab edits -- or from the user continuing to type while hovering
|
|
49
|
+
// the mouse over the copy button).
|
|
50
|
+
// This ensures the selection is updated in these cases.
|
|
51
|
+
if (currentCodeBlockCopySelectionPluginState.decorationStartAndEnd !== undefined) {
|
|
52
|
+
return getSelectionDecorationStartAndEnd({
|
|
53
|
+
state: newState,
|
|
54
|
+
transaction: transaction
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
return currentCodeBlockCopySelectionPluginState;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
props: {
|
|
62
|
+
decorations: function decorations(state) {
|
|
63
|
+
if (copySelectionPluginKey.getState(state).decorationStartAndEnd) {
|
|
64
|
+
var _copySelectionPluginK = _slicedToArray(copySelectionPluginKey.getState(state).decorationStartAndEnd, 2),
|
|
65
|
+
_start = _copySelectionPluginK[0],
|
|
66
|
+
_end = _copySelectionPluginK[1];
|
|
67
|
+
return DecorationSet.create(state.doc, [Decoration.inline(_start, _end, {
|
|
68
|
+
class: 'ProseMirror-fake-text-selection'
|
|
69
|
+
})]);
|
|
70
|
+
}
|
|
71
|
+
return DecorationSet.empty;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
export function provideVisualFeedbackForCopyButton(state, dispatch) {
|
|
77
|
+
var tr = state.tr;
|
|
78
|
+
tr.setMeta(copySelectionPluginKey, 'show-selection');
|
|
79
|
+
|
|
80
|
+
// note: dispatch should always be defined when called from the
|
|
81
|
+
// floating toolbar. Howver the Command type which the floating toolbar
|
|
82
|
+
// uses suggests it's optional.
|
|
83
|
+
// Using the type here to protect against future refactors of the
|
|
84
|
+
// floating toolbar
|
|
85
|
+
if (dispatch) {
|
|
86
|
+
dispatch(tr);
|
|
87
|
+
}
|
|
88
|
+
return true;
|
|
89
|
+
}
|
|
90
|
+
export function removeVisualFeedbackForCopyButton(state, dispatch) {
|
|
91
|
+
var tr = state.tr;
|
|
92
|
+
tr.setMeta(copySelectionPluginKey, 'remove-selection');
|
|
93
|
+
|
|
94
|
+
// note: dispatch should always be defined when called from the
|
|
95
|
+
// floating toolbar. Howver the Command type which the floating toolbar
|
|
96
|
+
// uses suggests it's optional.
|
|
97
|
+
// Using the type here to protect against future refactors of the
|
|
98
|
+
// floating toolbar
|
|
99
|
+
if (dispatch) {
|
|
100
|
+
dispatch(tr);
|
|
101
|
+
}
|
|
102
|
+
return true;
|
|
103
|
+
}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
|
|
2
|
+
import { filterCommand as filter } from '@atlaskit/editor-common/utils';
|
|
3
|
+
import { keydownHandler } from '@atlaskit/editor-prosemirror/keymap';
|
|
4
|
+
import { TextSelection } from '@atlaskit/editor-prosemirror/state';
|
|
5
|
+
import { setTextSelection } from '@atlaskit/editor-prosemirror/utils';
|
|
6
|
+
import { getAutoClosingBracketInfo, shouldAutoCloseBracket } from '../ide-ux/bracket-handling';
|
|
7
|
+
import { indent, insertIndent, insertNewlineWithIndent, outdent } from '../ide-ux/commands';
|
|
8
|
+
import { getEndOfCurrentLine, getLineInfo, getStartOfCurrentLine, isCursorInsideCodeBlock, isSelectionEntirelyInsideCodeBlock } from '../ide-ux/line-handling';
|
|
9
|
+
import { isClosingCharacter, isCursorBeforeClosingCharacter } from '../ide-ux/paired-character-handling';
|
|
10
|
+
import { getAutoClosingQuoteInfo, shouldAutoCloseQuote } from '../ide-ux/quote-handling';
|
|
11
|
+
import { getCursor } from '../utils';
|
|
12
|
+
var ideUX = function ideUX(pluginInjectionApi) {
|
|
13
|
+
var _pluginInjectionApi$a;
|
|
14
|
+
var editorAnalyticsAPI = pluginInjectionApi === null || pluginInjectionApi === void 0 || (_pluginInjectionApi$a = pluginInjectionApi.analytics) === null || _pluginInjectionApi$a === void 0 ? void 0 : _pluginInjectionApi$a.actions;
|
|
15
|
+
return new SafePlugin({
|
|
16
|
+
props: {
|
|
17
|
+
handleTextInput: function handleTextInput(view, from, to, text) {
|
|
18
|
+
var _pluginInjectionApi$c;
|
|
19
|
+
var state = view.state,
|
|
20
|
+
dispatch = view.dispatch;
|
|
21
|
+
var compositionPluginState = pluginInjectionApi === null || pluginInjectionApi === void 0 || (_pluginInjectionApi$c = pluginInjectionApi.composition) === null || _pluginInjectionApi$c === void 0 ? void 0 : _pluginInjectionApi$c.sharedState.currentState();
|
|
22
|
+
if (isCursorInsideCodeBlock(state) && !(compositionPluginState !== null && compositionPluginState !== void 0 && compositionPluginState.isComposing)) {
|
|
23
|
+
var beforeText = getStartOfCurrentLine(state).text;
|
|
24
|
+
var afterText = getEndOfCurrentLine(state).text;
|
|
25
|
+
|
|
26
|
+
// If text is a closing bracket/quote and we've already inserted it, move the selection after
|
|
27
|
+
if (isCursorBeforeClosingCharacter(afterText) && isClosingCharacter(text) && afterText.startsWith(text)) {
|
|
28
|
+
dispatch(setTextSelection(to + text.length)(state.tr));
|
|
29
|
+
return true;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Automatically add right-hand side bracket when user types the left bracket
|
|
33
|
+
if (shouldAutoCloseBracket(beforeText, afterText)) {
|
|
34
|
+
var _getAutoClosingBracke = getAutoClosingBracketInfo(beforeText + text, afterText),
|
|
35
|
+
left = _getAutoClosingBracke.left,
|
|
36
|
+
right = _getAutoClosingBracke.right;
|
|
37
|
+
if (left && right) {
|
|
38
|
+
var bracketPair = state.schema.text(text + right);
|
|
39
|
+
var tr = state.tr.replaceWith(from, to, bracketPair);
|
|
40
|
+
dispatch(setTextSelection(from + text.length)(tr));
|
|
41
|
+
return true;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Automatically add closing quote when user types a starting quote
|
|
46
|
+
if (shouldAutoCloseQuote(beforeText, afterText)) {
|
|
47
|
+
var _getAutoClosingQuoteI = getAutoClosingQuoteInfo(beforeText + text, afterText),
|
|
48
|
+
leftQuote = _getAutoClosingQuoteI.left,
|
|
49
|
+
rightQuote = _getAutoClosingQuoteI.right;
|
|
50
|
+
if (leftQuote && rightQuote) {
|
|
51
|
+
var quotePair = state.schema.text(text + rightQuote);
|
|
52
|
+
var _tr = state.tr.replaceWith(from, to, quotePair);
|
|
53
|
+
dispatch(setTextSelection(from + text.length)(_tr));
|
|
54
|
+
return true;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return false;
|
|
59
|
+
},
|
|
60
|
+
handleKeyDown: keydownHandler({
|
|
61
|
+
Backspace: function Backspace(state, dispatch) {
|
|
62
|
+
if (isCursorInsideCodeBlock(state)) {
|
|
63
|
+
var $cursor = getCursor(state.selection);
|
|
64
|
+
var beforeText = getStartOfCurrentLine(state).text;
|
|
65
|
+
var afterText = getEndOfCurrentLine(state).text;
|
|
66
|
+
var _getAutoClosingBracke2 = getAutoClosingBracketInfo(beforeText, afterText),
|
|
67
|
+
leftBracket = _getAutoClosingBracke2.left,
|
|
68
|
+
rightBracket = _getAutoClosingBracke2.right,
|
|
69
|
+
hasTrailingMatchingBracket = _getAutoClosingBracke2.hasTrailingMatchingBracket;
|
|
70
|
+
if (leftBracket && rightBracket && hasTrailingMatchingBracket && dispatch) {
|
|
71
|
+
dispatch(state.tr.delete($cursor.pos - leftBracket.length, $cursor.pos + rightBracket.length));
|
|
72
|
+
return true;
|
|
73
|
+
}
|
|
74
|
+
var _getAutoClosingQuoteI2 = getAutoClosingQuoteInfo(beforeText, afterText),
|
|
75
|
+
leftQuote = _getAutoClosingQuoteI2.left,
|
|
76
|
+
rightQuote = _getAutoClosingQuoteI2.right,
|
|
77
|
+
hasTrailingMatchingQuote = _getAutoClosingQuoteI2.hasTrailingMatchingQuote;
|
|
78
|
+
if (leftQuote && rightQuote && hasTrailingMatchingQuote && dispatch) {
|
|
79
|
+
dispatch(state.tr.delete($cursor.pos - leftQuote.length, $cursor.pos + rightQuote.length));
|
|
80
|
+
return true;
|
|
81
|
+
}
|
|
82
|
+
var _getLineInfo = getLineInfo(beforeText),
|
|
83
|
+
_getLineInfo$indentTo = _getLineInfo.indentToken,
|
|
84
|
+
size = _getLineInfo$indentTo.size,
|
|
85
|
+
token = _getLineInfo$indentTo.token,
|
|
86
|
+
indentText = _getLineInfo.indentText;
|
|
87
|
+
if (beforeText === indentText) {
|
|
88
|
+
if (indentText.endsWith(token.repeat(size)) && dispatch) {
|
|
89
|
+
dispatch(state.tr.delete($cursor.pos - (size - indentText.length % size || size), $cursor.pos));
|
|
90
|
+
return true;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return false;
|
|
95
|
+
},
|
|
96
|
+
Enter: filter(isSelectionEntirelyInsideCodeBlock, insertNewlineWithIndent),
|
|
97
|
+
'Mod-]': filter(isSelectionEntirelyInsideCodeBlock, indent(editorAnalyticsAPI)),
|
|
98
|
+
'Mod-[': filter(isSelectionEntirelyInsideCodeBlock, outdent(editorAnalyticsAPI)),
|
|
99
|
+
Tab: filter(isSelectionEntirelyInsideCodeBlock, function (state, dispatch) {
|
|
100
|
+
if (!dispatch) {
|
|
101
|
+
return false;
|
|
102
|
+
}
|
|
103
|
+
if (isCursorInsideCodeBlock(state)) {
|
|
104
|
+
return insertIndent(state, dispatch);
|
|
105
|
+
}
|
|
106
|
+
return indent(editorAnalyticsAPI)(state, dispatch);
|
|
107
|
+
}),
|
|
108
|
+
'Shift-Tab': filter(isSelectionEntirelyInsideCodeBlock, outdent(editorAnalyticsAPI)),
|
|
109
|
+
'Mod-a': function ModA(state, dispatch) {
|
|
110
|
+
if (isSelectionEntirelyInsideCodeBlock(state)) {
|
|
111
|
+
var _state$selection = state.selection,
|
|
112
|
+
$from = _state$selection.$from,
|
|
113
|
+
$to = _state$selection.$to;
|
|
114
|
+
var isFullCodeBlockSelection = $from.parentOffset === 0 && $to.parentOffset === $to.parent.nodeSize - 2;
|
|
115
|
+
if (!isFullCodeBlockSelection && dispatch) {
|
|
116
|
+
dispatch(state.tr.setSelection(TextSelection.create(state.doc, $from.start(), $to.end())));
|
|
117
|
+
return true;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return false;
|
|
121
|
+
}
|
|
122
|
+
})
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
};
|
|
126
|
+
export default ideUX;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { ACTION, ACTION_SUBJECT, ACTION_SUBJECT_ID, EVENT_TYPE, INPUT_METHOD } from '@atlaskit/editor-common/analytics';
|
|
2
|
+
import { insertBlock } from '@atlaskit/editor-common/commands';
|
|
3
|
+
import { inputRuleWithAnalytics } from '@atlaskit/editor-common/utils';
|
|
4
|
+
import { safeInsert } from '@atlaskit/editor-prosemirror/utils';
|
|
5
|
+
import { createPlugin, createRule, leafNodeReplacementCharacter } from '@atlaskit/prosemirror-input-rules';
|
|
6
|
+
import { isConvertableToCodeBlock, transformToCodeBlockAction } from '../transform-to-code-block';
|
|
7
|
+
export function createCodeBlockInputRule(schema, editorAnalyticsAPI) {
|
|
8
|
+
var rules = getCodeBlockRules(editorAnalyticsAPI, schema);
|
|
9
|
+
return createPlugin('code-block-input-rule', rules, {
|
|
10
|
+
isBlockNodeRule: true
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Get all code block input rules
|
|
16
|
+
*
|
|
17
|
+
* @param {Schema} schema
|
|
18
|
+
* @returns {InputRuleWithHandler[]}
|
|
19
|
+
*/
|
|
20
|
+
function getCodeBlockRules(editorAnalyticsAPI, schema) {
|
|
21
|
+
var ruleAnalytics = inputRuleWithAnalytics({
|
|
22
|
+
action: ACTION.INSERTED,
|
|
23
|
+
actionSubject: ACTION_SUBJECT.DOCUMENT,
|
|
24
|
+
actionSubjectId: ACTION_SUBJECT_ID.CODE_BLOCK,
|
|
25
|
+
attributes: {
|
|
26
|
+
inputMethod: INPUT_METHOD.FORMATTING
|
|
27
|
+
},
|
|
28
|
+
eventType: EVENT_TYPE.TRACK
|
|
29
|
+
}, editorAnalyticsAPI);
|
|
30
|
+
var validMatchLength = function validMatchLength(match) {
|
|
31
|
+
return match.length > 0 && match[0].length === 3;
|
|
32
|
+
};
|
|
33
|
+
var threeTildeRule = createRule(/(?!\s)(`{3,})$/, function (state, match, start, end) {
|
|
34
|
+
if (!validMatchLength(match)) {
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
var attributes = {};
|
|
38
|
+
if (match[4]) {
|
|
39
|
+
attributes.language = match[4];
|
|
40
|
+
}
|
|
41
|
+
if (isConvertableToCodeBlock(state)) {
|
|
42
|
+
return transformToCodeBlockAction(state, start, attributes);
|
|
43
|
+
}
|
|
44
|
+
var tr = state.tr;
|
|
45
|
+
tr.delete(start, end);
|
|
46
|
+
var codeBlock = tr.doc.type.schema.nodes.codeBlock.createChecked();
|
|
47
|
+
safeInsert(codeBlock)(tr);
|
|
48
|
+
return tr;
|
|
49
|
+
});
|
|
50
|
+
var leftNodeReplacementThreeTildeRule = createRule(new RegExp("((".concat(leafNodeReplacementCharacter, "`{3,})|^\\s(`{3,}))(\\S*)$")), function (state, match, start, end) {
|
|
51
|
+
if (!validMatchLength(match)) {
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
var attributes = {};
|
|
55
|
+
if (match[4]) {
|
|
56
|
+
attributes.language = match[4];
|
|
57
|
+
}
|
|
58
|
+
var inlineStart = Math.max(match.index + state.selection.$from.start(), 1);
|
|
59
|
+
return insertBlock(state, schema.nodes.codeBlock, inlineStart, end, attributes);
|
|
60
|
+
});
|
|
61
|
+
return [ruleAnalytics(threeTildeRule), ruleAnalytics(leftNodeReplacementThreeTildeRule)];
|
|
62
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { isEmptyNode } from '@atlaskit/editor-common/utils';
|
|
2
|
+
import { keymap } from '@atlaskit/editor-prosemirror/keymap';
|
|
3
|
+
import { Selection } from '@atlaskit/editor-prosemirror/state';
|
|
4
|
+
import { findParentNodeOfTypeClosestToPos, hasParentNodeOfType } from '@atlaskit/editor-prosemirror/utils';
|
|
5
|
+
import { getCursor } from '../utils';
|
|
6
|
+
var deleteCurrentItem = function deleteCurrentItem($from) {
|
|
7
|
+
return function (tr) {
|
|
8
|
+
return tr.delete($from.before($from.depth), $from.after($from.depth));
|
|
9
|
+
};
|
|
10
|
+
};
|
|
11
|
+
var setTextSelection = function setTextSelection(pos) {
|
|
12
|
+
return function (tr) {
|
|
13
|
+
var newSelection = Selection.findFrom(tr.doc.resolve(pos), -1, true);
|
|
14
|
+
if (newSelection) {
|
|
15
|
+
tr.setSelection(newSelection);
|
|
16
|
+
}
|
|
17
|
+
return tr;
|
|
18
|
+
};
|
|
19
|
+
};
|
|
20
|
+
export function keymapPlugin(schema) {
|
|
21
|
+
return keymap({
|
|
22
|
+
Backspace: function Backspace(state, dispatch) {
|
|
23
|
+
var $cursor = getCursor(state.selection);
|
|
24
|
+
var _state$schema$nodes = state.schema.nodes,
|
|
25
|
+
paragraph = _state$schema$nodes.paragraph,
|
|
26
|
+
codeBlock = _state$schema$nodes.codeBlock,
|
|
27
|
+
listItem = _state$schema$nodes.listItem,
|
|
28
|
+
table = _state$schema$nodes.table,
|
|
29
|
+
layoutColumn = _state$schema$nodes.layoutColumn;
|
|
30
|
+
if (!$cursor || $cursor.parent.type !== codeBlock || !dispatch) {
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
if ($cursor.pos === 1 || hasParentNodeOfType(listItem)(state.selection) && $cursor.parentOffset === 0) {
|
|
34
|
+
var node = findParentNodeOfTypeClosestToPos($cursor, codeBlock);
|
|
35
|
+
if (!node) {
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
dispatch(state.tr.setNodeMarkup(node.pos, node.node.type, node.node.attrs, []).setBlockType($cursor.pos, $cursor.pos, paragraph));
|
|
39
|
+
return true;
|
|
40
|
+
}
|
|
41
|
+
if ($cursor.node && isEmptyNode(schema)($cursor.node()) && (hasParentNodeOfType(layoutColumn)(state.selection) || hasParentNodeOfType(table)(state.selection))) {
|
|
42
|
+
var tr = state.tr;
|
|
43
|
+
var insertPos = $cursor.pos;
|
|
44
|
+
deleteCurrentItem($cursor)(tr);
|
|
45
|
+
setTextSelection(insertPos)(tr);
|
|
46
|
+
dispatch(tr.scrollIntoView());
|
|
47
|
+
return true;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Handle not nested empty code block
|
|
51
|
+
if (isEmptyNode(schema)($cursor.node())) {
|
|
52
|
+
dispatch(deleteCurrentItem($cursor)(state === null || state === void 0 ? void 0 : state.tr));
|
|
53
|
+
return true;
|
|
54
|
+
}
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
export default keymapPlugin;
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
2
|
+
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; }
|
|
3
|
+
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) { _defineProperty(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; }
|
|
4
|
+
import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
|
|
5
|
+
import { createSelectionClickHandler } from '@atlaskit/editor-common/selection';
|
|
6
|
+
import { browser } from '@atlaskit/editor-common/utils';
|
|
7
|
+
import { NodeSelection } from '@atlaskit/editor-prosemirror/state';
|
|
8
|
+
import { ignoreFollowingMutations, resetShouldIgnoreFollowingMutations } from '../actions';
|
|
9
|
+
import { codeBlockNodeView } from '../nodeviews/code-block';
|
|
10
|
+
import { pluginKey } from '../plugin-key';
|
|
11
|
+
import { codeBlockClassNames } from '../ui/class-names';
|
|
12
|
+
import { findCodeBlock } from '../utils';
|
|
13
|
+
import { ACTIONS } from './actions';
|
|
14
|
+
export var createPlugin = function createPlugin(_ref) {
|
|
15
|
+
var _ref$useLongPressSele = _ref.useLongPressSelection,
|
|
16
|
+
useLongPressSelection = _ref$useLongPressSele === void 0 ? false : _ref$useLongPressSele,
|
|
17
|
+
getIntl = _ref.getIntl,
|
|
18
|
+
appearance = _ref.appearance,
|
|
19
|
+
_ref$allowComposition = _ref.allowCompositionInputOverride,
|
|
20
|
+
allowCompositionInputOverride = _ref$allowComposition === void 0 ? false : _ref$allowComposition;
|
|
21
|
+
var handleDOMEvents = {};
|
|
22
|
+
|
|
23
|
+
// ME-1599: Composition on mobile was causing the DOM observer to mutate the code block
|
|
24
|
+
// incorrecly and lose content when pressing enter in the middle of a code block line.
|
|
25
|
+
if (allowCompositionInputOverride) {
|
|
26
|
+
handleDOMEvents.beforeinput = function (view, event) {
|
|
27
|
+
var keyEvent = event;
|
|
28
|
+
var eventInputType = keyEvent.inputType;
|
|
29
|
+
var eventText = keyEvent.data;
|
|
30
|
+
if (browser.ios && event.composed &&
|
|
31
|
+
// insertParagraph will be the input type when the enter key is pressed.
|
|
32
|
+
eventInputType === 'insertParagraph' && findCodeBlock(view.state, view.state.selection)) {
|
|
33
|
+
event.preventDefault();
|
|
34
|
+
return true;
|
|
35
|
+
} else if (browser.android && event.composed && eventInputType === 'insertCompositionText' && eventText[(eventText === null || eventText === void 0 ? void 0 : eventText.length) - 1] === '\n' && findCodeBlock(view.state, view.state.selection)) {
|
|
36
|
+
var resultingText = event.target.outerText + '\n';
|
|
37
|
+
if (resultingText.endsWith(eventText)) {
|
|
38
|
+
// End of paragraph
|
|
39
|
+
setTimeout(function () {
|
|
40
|
+
view.someProp('handleKeyDown', function (f) {
|
|
41
|
+
return f(view, new KeyboardEvent('keydown', {
|
|
42
|
+
bubbles: true,
|
|
43
|
+
cancelable: true,
|
|
44
|
+
key: 'Enter',
|
|
45
|
+
code: 'Enter'
|
|
46
|
+
}));
|
|
47
|
+
});
|
|
48
|
+
}, 0);
|
|
49
|
+
} else {
|
|
50
|
+
// Middle of paragraph, end of line
|
|
51
|
+
ignoreFollowingMutations(view.state, view.dispatch);
|
|
52
|
+
}
|
|
53
|
+
return true;
|
|
54
|
+
}
|
|
55
|
+
if (browser.android) {
|
|
56
|
+
resetShouldIgnoreFollowingMutations(view.state, view.dispatch);
|
|
57
|
+
}
|
|
58
|
+
return false;
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
return new SafePlugin({
|
|
62
|
+
state: {
|
|
63
|
+
init: function init(_, state) {
|
|
64
|
+
var node = findCodeBlock(state, state.selection);
|
|
65
|
+
return {
|
|
66
|
+
pos: node ? node.pos : null,
|
|
67
|
+
contentCopied: false,
|
|
68
|
+
isNodeSelected: false,
|
|
69
|
+
shouldIgnoreFollowingMutations: false
|
|
70
|
+
};
|
|
71
|
+
},
|
|
72
|
+
apply: function apply(tr, pluginState, _oldState, newState) {
|
|
73
|
+
if (tr.docChanged || tr.selectionSet) {
|
|
74
|
+
var node = findCodeBlock(newState, tr.selection);
|
|
75
|
+
var newPluginState = _objectSpread(_objectSpread({}, pluginState), {}, {
|
|
76
|
+
pos: node ? node.pos : null,
|
|
77
|
+
isNodeSelected: tr.selection instanceof NodeSelection
|
|
78
|
+
});
|
|
79
|
+
return newPluginState;
|
|
80
|
+
}
|
|
81
|
+
var meta = tr.getMeta(pluginKey);
|
|
82
|
+
if ((meta === null || meta === void 0 ? void 0 : meta.type) === ACTIONS.SET_COPIED_TO_CLIPBOARD) {
|
|
83
|
+
return _objectSpread(_objectSpread({}, pluginState), {}, {
|
|
84
|
+
contentCopied: meta.data
|
|
85
|
+
});
|
|
86
|
+
} else if ((meta === null || meta === void 0 ? void 0 : meta.type) === ACTIONS.SET_SHOULD_IGNORE_FOLLOWING_MUTATIONS) {
|
|
87
|
+
return _objectSpread(_objectSpread({}, pluginState), {}, {
|
|
88
|
+
shouldIgnoreFollowingMutations: meta.data
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
return pluginState;
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
key: pluginKey,
|
|
95
|
+
props: {
|
|
96
|
+
nodeViews: {
|
|
97
|
+
codeBlock: codeBlockNodeView
|
|
98
|
+
},
|
|
99
|
+
handleClickOn: createSelectionClickHandler(['codeBlock'], function (target) {
|
|
100
|
+
return !!(target.closest(".".concat(codeBlockClassNames.gutter)) || target.classList.contains(codeBlockClassNames.content));
|
|
101
|
+
}, {
|
|
102
|
+
useLongPressSelection: useLongPressSelection
|
|
103
|
+
}),
|
|
104
|
+
handleDOMEvents: handleDOMEvents
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { browser } from '@atlaskit/editor-common/utils';
|
|
2
|
+
import { pluginKey } from './plugin-key';
|
|
3
|
+
|
|
4
|
+
// Workaround for a firefox issue where dom selection is off sync
|
|
5
|
+
// https://product-fabric.atlassian.net/browse/ED-12442
|
|
6
|
+
var refreshBrowserSelection = function refreshBrowserSelection() {
|
|
7
|
+
var domSelection = window.getSelection();
|
|
8
|
+
if (domSelection) {
|
|
9
|
+
var domRange = domSelection && domSelection.rangeCount === 1 && domSelection.getRangeAt(0).cloneRange();
|
|
10
|
+
if (domRange) {
|
|
11
|
+
domSelection.removeAllRanges();
|
|
12
|
+
domSelection.addRange(domRange);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
var refreshBrowserSelectionOnChange = function refreshBrowserSelectionOnChange(transaction, editorState) {
|
|
17
|
+
var _pluginKey$getState;
|
|
18
|
+
if (browser.gecko && transaction.docChanged &&
|
|
19
|
+
// codeblockState.pos should be set if current selection is in a codeblock.
|
|
20
|
+
typeof ((_pluginKey$getState = pluginKey.getState(editorState)) === null || _pluginKey$getState === void 0 ? void 0 : _pluginKey$getState.pos) === 'number') {
|
|
21
|
+
refreshBrowserSelection();
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
export default refreshBrowserSelectionOnChange;
|
|
25
|
+
export { refreshBrowserSelection };
|