@atlaskit/editor-plugin-code-block-advanced 2.1.2 → 2.1.4
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 +16 -0
- package/dist/cjs/nodeviews/codeBlockAdvanced.js +17 -0
- package/dist/cjs/pm-plugins/main.js +14 -0
- package/dist/cjs/pm-plugins/shiftArrowKeyWorkaround.js +55 -0
- package/dist/es2019/nodeviews/codeBlockAdvanced.js +13 -0
- package/dist/es2019/pm-plugins/main.js +14 -0
- package/dist/es2019/pm-plugins/shiftArrowKeyWorkaround.js +61 -0
- package/dist/esm/nodeviews/codeBlockAdvanced.js +17 -0
- package/dist/esm/pm-plugins/main.js +14 -0
- package/dist/esm/pm-plugins/shiftArrowKeyWorkaround.js +49 -0
- package/dist/types/nodeviews/codeBlockAdvanced.d.ts +1 -0
- package/dist/types/pm-plugins/shiftArrowKeyWorkaround.d.ts +3 -0
- package/dist/types-ts4.5/nodeviews/codeBlockAdvanced.d.ts +1 -0
- package/dist/types-ts4.5/pm-plugins/shiftArrowKeyWorkaround.d.ts +3 -0
- package/package.json +7 -7
- package/src/nodeviews/codeBlockAdvanced.ts +14 -0
- package/src/pm-plugins/main.ts +17 -0
- package/src/pm-plugins/shiftArrowKeyWorkaround.ts +58 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# @atlaskit/editor-plugin-code-block-advanced
|
|
2
2
|
|
|
3
|
+
## 2.1.4
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#136263](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/pull-requests/136263)
|
|
8
|
+
[`602e9a7824b0c`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/602e9a7824b0c) -
|
|
9
|
+
Fix editor crashing with advanced code blocks due to infinite codemirror loop with decorations
|
|
10
|
+
when changing breakout.
|
|
11
|
+
- Updated dependencies
|
|
12
|
+
|
|
13
|
+
## 2.1.3
|
|
14
|
+
|
|
15
|
+
### Patch Changes
|
|
16
|
+
|
|
17
|
+
- Updated dependencies
|
|
18
|
+
|
|
3
19
|
## 2.1.2
|
|
4
20
|
|
|
5
21
|
### Patch Changes
|
|
@@ -15,6 +15,7 @@ var _state = require("@codemirror/state");
|
|
|
15
15
|
var _view = require("@codemirror/view");
|
|
16
16
|
var _codeBlock = require("@atlaskit/editor-common/code-block");
|
|
17
17
|
var _state2 = require("@atlaskit/editor-prosemirror/state");
|
|
18
|
+
var _view2 = require("@atlaskit/editor-prosemirror/view");
|
|
18
19
|
var _syntaxHighlightingTheme = require("../ui/syntaxHighlightingTheme");
|
|
19
20
|
var _theme = require("../ui/theme");
|
|
20
21
|
var _syncCMWithPM = require("./codemirrorSync/syncCMWithPM");
|
|
@@ -91,6 +92,10 @@ var CodeBlockAdvancedNodeView = /*#__PURE__*/function () {
|
|
|
91
92
|
key: "destroy",
|
|
92
93
|
value: function destroy() {
|
|
93
94
|
var _this$cleanupDisabled;
|
|
95
|
+
// ED-27428: CodeMirror gets into an infinite loop as it detects mutations on removed
|
|
96
|
+
// decorations. When we change the breakout we destroy the node and cleanup these decorations from
|
|
97
|
+
// codemirror
|
|
98
|
+
this.clearProseMirrorDecorations();
|
|
94
99
|
(_this$cleanupDisabled = this.cleanupDisabledState) === null || _this$cleanupDisabled === void 0 || _this$cleanupDisabled.call(this);
|
|
95
100
|
}
|
|
96
101
|
}, {
|
|
@@ -202,6 +207,18 @@ var CodeBlockAdvancedNodeView = /*#__PURE__*/function () {
|
|
|
202
207
|
});
|
|
203
208
|
this.updating = false;
|
|
204
209
|
}
|
|
210
|
+
}, {
|
|
211
|
+
key: "clearProseMirrorDecorations",
|
|
212
|
+
value: function clearProseMirrorDecorations() {
|
|
213
|
+
this.updating = true;
|
|
214
|
+
var computedFacet = this.pmFacet.compute([], function () {
|
|
215
|
+
return _view2.DecorationSet.empty;
|
|
216
|
+
});
|
|
217
|
+
this.cm.dispatch({
|
|
218
|
+
effects: this.pmDecorationsCompartment.reconfigure(computedFacet)
|
|
219
|
+
});
|
|
220
|
+
this.updating = false;
|
|
221
|
+
}
|
|
205
222
|
}, {
|
|
206
223
|
key: "stopEvent",
|
|
207
224
|
value: function stopEvent(e) {
|
|
@@ -6,11 +6,25 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
6
6
|
exports.createPlugin = void 0;
|
|
7
7
|
var _safePlugin = require("@atlaskit/editor-common/safe-plugin");
|
|
8
8
|
var _lazyCodeBlockAdvanced = require("../nodeviews/lazyCodeBlockAdvanced");
|
|
9
|
+
var _shiftArrowKeyWorkaround = require("./shiftArrowKeyWorkaround");
|
|
9
10
|
var createPlugin = exports.createPlugin = function createPlugin(props) {
|
|
10
11
|
return new _safePlugin.SafePlugin({
|
|
11
12
|
props: {
|
|
12
13
|
nodeViews: {
|
|
13
14
|
codeBlock: (0, _lazyCodeBlockAdvanced.lazyCodeBlockView)(props)
|
|
15
|
+
},
|
|
16
|
+
// Custom selection behaviour to fix issues with codeblocks with Shift + Arrow{Up || Down}
|
|
17
|
+
// These issues are also present in the prosemirror codemirror example and @marijnh suggests to
|
|
18
|
+
// use custom event handlers: https://github.com/ProseMirror/website/issues/83
|
|
19
|
+
handleKeyDown: function handleKeyDown(view, event) {
|
|
20
|
+
if (!(event instanceof KeyboardEvent)) {
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
if (event.key === 'ArrowUp' && event.shiftKey) {
|
|
24
|
+
return (0, _shiftArrowKeyWorkaround.shiftArrowUpWorkaround)(view, event);
|
|
25
|
+
} else if (event.key === 'ArrowDown' && event.shiftKey) {
|
|
26
|
+
return (0, _shiftArrowKeyWorkaround.shiftArrowDownWorkaround)(view, event);
|
|
27
|
+
}
|
|
14
28
|
}
|
|
15
29
|
}
|
|
16
30
|
});
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.shiftArrowUpWorkaround = exports.shiftArrowDownWorkaround = void 0;
|
|
7
|
+
var _state = require("@atlaskit/editor-prosemirror/state");
|
|
8
|
+
var shiftArrowUpWorkaround = exports.shiftArrowUpWorkaround = function shiftArrowUpWorkaround(view, event) {
|
|
9
|
+
var _doc$resolve$nodeBefo;
|
|
10
|
+
var _view$state = view.state,
|
|
11
|
+
doc = _view$state.doc,
|
|
12
|
+
_view$state$selection = _view$state.selection,
|
|
13
|
+
$head = _view$state$selection.$head,
|
|
14
|
+
$anchor = _view$state$selection.$anchor,
|
|
15
|
+
tr = _view$state.tr,
|
|
16
|
+
codeBlock = _view$state.schema.nodes.codeBlock;
|
|
17
|
+
|
|
18
|
+
// Position we want to check (directly after our current position)
|
|
19
|
+
var pos = Math.max($head.pos - 1, 1);
|
|
20
|
+
var isNodeBefore = ((_doc$resolve$nodeBefo = doc.resolve(pos).nodeBefore) === null || _doc$resolve$nodeBefo === void 0 ? void 0 : _doc$resolve$nodeBefo.type) === codeBlock;
|
|
21
|
+
var maybeProblematicNode = isNodeBefore ? doc.resolve(pos).nodeBefore : doc.resolve(pos).node();
|
|
22
|
+
if ((maybeProblematicNode === null || maybeProblematicNode === void 0 ? void 0 : maybeProblematicNode.type) === codeBlock) {
|
|
23
|
+
var nodeSize = maybeProblematicNode.nodeSize;
|
|
24
|
+
var startPos = isNodeBefore ? pos : $head.pos;
|
|
25
|
+
tr.setSelection(_state.TextSelection.create(doc, $anchor.pos, Math.max(startPos - nodeSize, 0)));
|
|
26
|
+
view.dispatch(tr);
|
|
27
|
+
event.preventDefault();
|
|
28
|
+
return true;
|
|
29
|
+
}
|
|
30
|
+
return false;
|
|
31
|
+
};
|
|
32
|
+
var shiftArrowDownWorkaround = exports.shiftArrowDownWorkaround = function shiftArrowDownWorkaround(view, event) {
|
|
33
|
+
var _doc$resolve$nodeAfte;
|
|
34
|
+
var _view$state2 = view.state,
|
|
35
|
+
doc = _view$state2.doc,
|
|
36
|
+
_view$state2$selectio = _view$state2.selection,
|
|
37
|
+
$head = _view$state2$selectio.$head,
|
|
38
|
+
$anchor = _view$state2$selectio.$anchor,
|
|
39
|
+
tr = _view$state2.tr,
|
|
40
|
+
codeBlock = _view$state2.schema.nodes.codeBlock;
|
|
41
|
+
|
|
42
|
+
// Position we want to check (directly after our current position)
|
|
43
|
+
var pos = $head.pos + 1;
|
|
44
|
+
var isNodeAfter = ((_doc$resolve$nodeAfte = doc.resolve(pos).nodeAfter) === null || _doc$resolve$nodeAfte === void 0 ? void 0 : _doc$resolve$nodeAfte.type) === codeBlock;
|
|
45
|
+
var maybeProblematicNode = isNodeAfter ? doc.resolve(pos).nodeAfter : doc.resolve(pos).node();
|
|
46
|
+
if ((maybeProblematicNode === null || maybeProblematicNode === void 0 ? void 0 : maybeProblematicNode.type) === codeBlock) {
|
|
47
|
+
var nodeSize = maybeProblematicNode.nodeSize;
|
|
48
|
+
var startPos = isNodeAfter ? pos : $head.pos;
|
|
49
|
+
tr.setSelection(_state.TextSelection.create(doc, $anchor.pos, Math.min(startPos + nodeSize, doc.content.size)));
|
|
50
|
+
view.dispatch(tr);
|
|
51
|
+
event.preventDefault();
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
return false;
|
|
55
|
+
};
|
|
@@ -5,6 +5,7 @@ import { Compartment, EditorSelection, Facet } from '@codemirror/state';
|
|
|
5
5
|
import { EditorView as CodeMirror, lineNumbers, gutters } from '@codemirror/view';
|
|
6
6
|
import { isCodeBlockWordWrapEnabled } from '@atlaskit/editor-common/code-block';
|
|
7
7
|
import { NodeSelection } from '@atlaskit/editor-prosemirror/state';
|
|
8
|
+
import { DecorationSet } from '@atlaskit/editor-prosemirror/view';
|
|
8
9
|
import { highlightStyle } from '../ui/syntaxHighlightingTheme';
|
|
9
10
|
import { cmTheme } from '../ui/theme';
|
|
10
11
|
import { syncCMWithPM } from './codemirrorSync/syncCMWithPM';
|
|
@@ -69,6 +70,10 @@ class CodeBlockAdvancedNodeView {
|
|
|
69
70
|
}
|
|
70
71
|
destroy() {
|
|
71
72
|
var _this$cleanupDisabled;
|
|
73
|
+
// ED-27428: CodeMirror gets into an infinite loop as it detects mutations on removed
|
|
74
|
+
// decorations. When we change the breakout we destroy the node and cleanup these decorations from
|
|
75
|
+
// codemirror
|
|
76
|
+
this.clearProseMirrorDecorations();
|
|
72
77
|
(_this$cleanupDisabled = this.cleanupDisabledState) === null || _this$cleanupDisabled === void 0 ? void 0 : _this$cleanupDisabled.call(this);
|
|
73
78
|
}
|
|
74
79
|
forwardUpdate(update) {
|
|
@@ -161,6 +166,14 @@ class CodeBlockAdvancedNodeView {
|
|
|
161
166
|
});
|
|
162
167
|
this.updating = false;
|
|
163
168
|
}
|
|
169
|
+
clearProseMirrorDecorations() {
|
|
170
|
+
this.updating = true;
|
|
171
|
+
const computedFacet = this.pmFacet.compute([], () => DecorationSet.empty);
|
|
172
|
+
this.cm.dispatch({
|
|
173
|
+
effects: this.pmDecorationsCompartment.reconfigure(computedFacet)
|
|
174
|
+
});
|
|
175
|
+
this.updating = false;
|
|
176
|
+
}
|
|
164
177
|
stopEvent(e) {
|
|
165
178
|
var _this$getPos5;
|
|
166
179
|
if (e instanceof MouseEvent && e.type === 'mousedown') {
|
|
@@ -1,10 +1,24 @@
|
|
|
1
1
|
import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
|
|
2
2
|
import { lazyCodeBlockView } from '../nodeviews/lazyCodeBlockAdvanced';
|
|
3
|
+
import { shiftArrowDownWorkaround, shiftArrowUpWorkaround } from './shiftArrowKeyWorkaround';
|
|
3
4
|
export const createPlugin = props => {
|
|
4
5
|
return new SafePlugin({
|
|
5
6
|
props: {
|
|
6
7
|
nodeViews: {
|
|
7
8
|
codeBlock: lazyCodeBlockView(props)
|
|
9
|
+
},
|
|
10
|
+
// Custom selection behaviour to fix issues with codeblocks with Shift + Arrow{Up || Down}
|
|
11
|
+
// These issues are also present in the prosemirror codemirror example and @marijnh suggests to
|
|
12
|
+
// use custom event handlers: https://github.com/ProseMirror/website/issues/83
|
|
13
|
+
handleKeyDown(view, event) {
|
|
14
|
+
if (!(event instanceof KeyboardEvent)) {
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
if (event.key === 'ArrowUp' && event.shiftKey) {
|
|
18
|
+
return shiftArrowUpWorkaround(view, event);
|
|
19
|
+
} else if (event.key === 'ArrowDown' && event.shiftKey) {
|
|
20
|
+
return shiftArrowDownWorkaround(view, event);
|
|
21
|
+
}
|
|
8
22
|
}
|
|
9
23
|
}
|
|
10
24
|
});
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { TextSelection } from '@atlaskit/editor-prosemirror/state';
|
|
2
|
+
export const shiftArrowUpWorkaround = (view, event) => {
|
|
3
|
+
var _doc$resolve$nodeBefo;
|
|
4
|
+
const {
|
|
5
|
+
doc,
|
|
6
|
+
selection: {
|
|
7
|
+
$head,
|
|
8
|
+
$anchor
|
|
9
|
+
},
|
|
10
|
+
tr,
|
|
11
|
+
schema: {
|
|
12
|
+
nodes: {
|
|
13
|
+
codeBlock
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
} = view.state;
|
|
17
|
+
|
|
18
|
+
// Position we want to check (directly after our current position)
|
|
19
|
+
const pos = Math.max($head.pos - 1, 1);
|
|
20
|
+
const isNodeBefore = ((_doc$resolve$nodeBefo = doc.resolve(pos).nodeBefore) === null || _doc$resolve$nodeBefo === void 0 ? void 0 : _doc$resolve$nodeBefo.type) === codeBlock;
|
|
21
|
+
const maybeProblematicNode = isNodeBefore ? doc.resolve(pos).nodeBefore : doc.resolve(pos).node();
|
|
22
|
+
if ((maybeProblematicNode === null || maybeProblematicNode === void 0 ? void 0 : maybeProblematicNode.type) === codeBlock) {
|
|
23
|
+
const nodeSize = maybeProblematicNode.nodeSize;
|
|
24
|
+
const startPos = isNodeBefore ? pos : $head.pos;
|
|
25
|
+
tr.setSelection(TextSelection.create(doc, $anchor.pos, Math.max(startPos - nodeSize, 0)));
|
|
26
|
+
view.dispatch(tr);
|
|
27
|
+
event.preventDefault();
|
|
28
|
+
return true;
|
|
29
|
+
}
|
|
30
|
+
return false;
|
|
31
|
+
};
|
|
32
|
+
export const shiftArrowDownWorkaround = (view, event) => {
|
|
33
|
+
var _doc$resolve$nodeAfte;
|
|
34
|
+
const {
|
|
35
|
+
doc,
|
|
36
|
+
selection: {
|
|
37
|
+
$head,
|
|
38
|
+
$anchor
|
|
39
|
+
},
|
|
40
|
+
tr,
|
|
41
|
+
schema: {
|
|
42
|
+
nodes: {
|
|
43
|
+
codeBlock
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
} = view.state;
|
|
47
|
+
|
|
48
|
+
// Position we want to check (directly after our current position)
|
|
49
|
+
const pos = $head.pos + 1;
|
|
50
|
+
const isNodeAfter = ((_doc$resolve$nodeAfte = doc.resolve(pos).nodeAfter) === null || _doc$resolve$nodeAfte === void 0 ? void 0 : _doc$resolve$nodeAfte.type) === codeBlock;
|
|
51
|
+
const maybeProblematicNode = isNodeAfter ? doc.resolve(pos).nodeAfter : doc.resolve(pos).node();
|
|
52
|
+
if ((maybeProblematicNode === null || maybeProblematicNode === void 0 ? void 0 : maybeProblematicNode.type) === codeBlock) {
|
|
53
|
+
const nodeSize = maybeProblematicNode.nodeSize;
|
|
54
|
+
const startPos = isNodeAfter ? pos : $head.pos;
|
|
55
|
+
tr.setSelection(TextSelection.create(doc, $anchor.pos, Math.min(startPos + nodeSize, doc.content.size)));
|
|
56
|
+
view.dispatch(tr);
|
|
57
|
+
event.preventDefault();
|
|
58
|
+
return true;
|
|
59
|
+
}
|
|
60
|
+
return false;
|
|
61
|
+
};
|
|
@@ -8,6 +8,7 @@ import { Compartment, EditorSelection, Facet } from '@codemirror/state';
|
|
|
8
8
|
import { EditorView as CodeMirror, lineNumbers, gutters } from '@codemirror/view';
|
|
9
9
|
import { isCodeBlockWordWrapEnabled } from '@atlaskit/editor-common/code-block';
|
|
10
10
|
import { NodeSelection } from '@atlaskit/editor-prosemirror/state';
|
|
11
|
+
import { DecorationSet } from '@atlaskit/editor-prosemirror/view';
|
|
11
12
|
import { highlightStyle } from '../ui/syntaxHighlightingTheme';
|
|
12
13
|
import { cmTheme } from '../ui/theme';
|
|
13
14
|
import { syncCMWithPM } from './codemirrorSync/syncCMWithPM';
|
|
@@ -84,6 +85,10 @@ var CodeBlockAdvancedNodeView = /*#__PURE__*/function () {
|
|
|
84
85
|
key: "destroy",
|
|
85
86
|
value: function destroy() {
|
|
86
87
|
var _this$cleanupDisabled;
|
|
88
|
+
// ED-27428: CodeMirror gets into an infinite loop as it detects mutations on removed
|
|
89
|
+
// decorations. When we change the breakout we destroy the node and cleanup these decorations from
|
|
90
|
+
// codemirror
|
|
91
|
+
this.clearProseMirrorDecorations();
|
|
87
92
|
(_this$cleanupDisabled = this.cleanupDisabledState) === null || _this$cleanupDisabled === void 0 || _this$cleanupDisabled.call(this);
|
|
88
93
|
}
|
|
89
94
|
}, {
|
|
@@ -195,6 +200,18 @@ var CodeBlockAdvancedNodeView = /*#__PURE__*/function () {
|
|
|
195
200
|
});
|
|
196
201
|
this.updating = false;
|
|
197
202
|
}
|
|
203
|
+
}, {
|
|
204
|
+
key: "clearProseMirrorDecorations",
|
|
205
|
+
value: function clearProseMirrorDecorations() {
|
|
206
|
+
this.updating = true;
|
|
207
|
+
var computedFacet = this.pmFacet.compute([], function () {
|
|
208
|
+
return DecorationSet.empty;
|
|
209
|
+
});
|
|
210
|
+
this.cm.dispatch({
|
|
211
|
+
effects: this.pmDecorationsCompartment.reconfigure(computedFacet)
|
|
212
|
+
});
|
|
213
|
+
this.updating = false;
|
|
214
|
+
}
|
|
198
215
|
}, {
|
|
199
216
|
key: "stopEvent",
|
|
200
217
|
value: function stopEvent(e) {
|
|
@@ -1,10 +1,24 @@
|
|
|
1
1
|
import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
|
|
2
2
|
import { lazyCodeBlockView } from '../nodeviews/lazyCodeBlockAdvanced';
|
|
3
|
+
import { shiftArrowDownWorkaround, shiftArrowUpWorkaround } from './shiftArrowKeyWorkaround';
|
|
3
4
|
export var createPlugin = function createPlugin(props) {
|
|
4
5
|
return new SafePlugin({
|
|
5
6
|
props: {
|
|
6
7
|
nodeViews: {
|
|
7
8
|
codeBlock: lazyCodeBlockView(props)
|
|
9
|
+
},
|
|
10
|
+
// Custom selection behaviour to fix issues with codeblocks with Shift + Arrow{Up || Down}
|
|
11
|
+
// These issues are also present in the prosemirror codemirror example and @marijnh suggests to
|
|
12
|
+
// use custom event handlers: https://github.com/ProseMirror/website/issues/83
|
|
13
|
+
handleKeyDown: function handleKeyDown(view, event) {
|
|
14
|
+
if (!(event instanceof KeyboardEvent)) {
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
if (event.key === 'ArrowUp' && event.shiftKey) {
|
|
18
|
+
return shiftArrowUpWorkaround(view, event);
|
|
19
|
+
} else if (event.key === 'ArrowDown' && event.shiftKey) {
|
|
20
|
+
return shiftArrowDownWorkaround(view, event);
|
|
21
|
+
}
|
|
8
22
|
}
|
|
9
23
|
}
|
|
10
24
|
});
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { TextSelection } from '@atlaskit/editor-prosemirror/state';
|
|
2
|
+
export var shiftArrowUpWorkaround = function shiftArrowUpWorkaround(view, event) {
|
|
3
|
+
var _doc$resolve$nodeBefo;
|
|
4
|
+
var _view$state = view.state,
|
|
5
|
+
doc = _view$state.doc,
|
|
6
|
+
_view$state$selection = _view$state.selection,
|
|
7
|
+
$head = _view$state$selection.$head,
|
|
8
|
+
$anchor = _view$state$selection.$anchor,
|
|
9
|
+
tr = _view$state.tr,
|
|
10
|
+
codeBlock = _view$state.schema.nodes.codeBlock;
|
|
11
|
+
|
|
12
|
+
// Position we want to check (directly after our current position)
|
|
13
|
+
var pos = Math.max($head.pos - 1, 1);
|
|
14
|
+
var isNodeBefore = ((_doc$resolve$nodeBefo = doc.resolve(pos).nodeBefore) === null || _doc$resolve$nodeBefo === void 0 ? void 0 : _doc$resolve$nodeBefo.type) === codeBlock;
|
|
15
|
+
var maybeProblematicNode = isNodeBefore ? doc.resolve(pos).nodeBefore : doc.resolve(pos).node();
|
|
16
|
+
if ((maybeProblematicNode === null || maybeProblematicNode === void 0 ? void 0 : maybeProblematicNode.type) === codeBlock) {
|
|
17
|
+
var nodeSize = maybeProblematicNode.nodeSize;
|
|
18
|
+
var startPos = isNodeBefore ? pos : $head.pos;
|
|
19
|
+
tr.setSelection(TextSelection.create(doc, $anchor.pos, Math.max(startPos - nodeSize, 0)));
|
|
20
|
+
view.dispatch(tr);
|
|
21
|
+
event.preventDefault();
|
|
22
|
+
return true;
|
|
23
|
+
}
|
|
24
|
+
return false;
|
|
25
|
+
};
|
|
26
|
+
export var shiftArrowDownWorkaround = function shiftArrowDownWorkaround(view, event) {
|
|
27
|
+
var _doc$resolve$nodeAfte;
|
|
28
|
+
var _view$state2 = view.state,
|
|
29
|
+
doc = _view$state2.doc,
|
|
30
|
+
_view$state2$selectio = _view$state2.selection,
|
|
31
|
+
$head = _view$state2$selectio.$head,
|
|
32
|
+
$anchor = _view$state2$selectio.$anchor,
|
|
33
|
+
tr = _view$state2.tr,
|
|
34
|
+
codeBlock = _view$state2.schema.nodes.codeBlock;
|
|
35
|
+
|
|
36
|
+
// Position we want to check (directly after our current position)
|
|
37
|
+
var pos = $head.pos + 1;
|
|
38
|
+
var isNodeAfter = ((_doc$resolve$nodeAfte = doc.resolve(pos).nodeAfter) === null || _doc$resolve$nodeAfte === void 0 ? void 0 : _doc$resolve$nodeAfte.type) === codeBlock;
|
|
39
|
+
var maybeProblematicNode = isNodeAfter ? doc.resolve(pos).nodeAfter : doc.resolve(pos).node();
|
|
40
|
+
if ((maybeProblematicNode === null || maybeProblematicNode === void 0 ? void 0 : maybeProblematicNode.type) === codeBlock) {
|
|
41
|
+
var nodeSize = maybeProblematicNode.nodeSize;
|
|
42
|
+
var startPos = isNodeAfter ? pos : $head.pos;
|
|
43
|
+
tr.setSelection(TextSelection.create(doc, $anchor.pos, Math.min(startPos + nodeSize, doc.content.size)));
|
|
44
|
+
view.dispatch(tr);
|
|
45
|
+
event.preventDefault();
|
|
46
|
+
return true;
|
|
47
|
+
}
|
|
48
|
+
return false;
|
|
49
|
+
};
|
|
@@ -40,6 +40,7 @@ declare class CodeBlockAdvancedNodeView implements NodeView {
|
|
|
40
40
|
* This then gets translated to codemirror decorations in `prosemirrorDecorationPlugin`
|
|
41
41
|
*/
|
|
42
42
|
private updateProseMirrorDecorations;
|
|
43
|
+
private clearProseMirrorDecorations;
|
|
43
44
|
stopEvent(e: Event): boolean;
|
|
44
45
|
}
|
|
45
46
|
export declare const getCodeBlockAdvancedNodeView: (props: ConfigProps) => (node: PMNode, view: EditorView, getPos: getPosHandler) => CodeBlockAdvancedNodeView;
|
|
@@ -40,6 +40,7 @@ declare class CodeBlockAdvancedNodeView implements NodeView {
|
|
|
40
40
|
* This then gets translated to codemirror decorations in `prosemirrorDecorationPlugin`
|
|
41
41
|
*/
|
|
42
42
|
private updateProseMirrorDecorations;
|
|
43
|
+
private clearProseMirrorDecorations;
|
|
43
44
|
stopEvent(e: Event): boolean;
|
|
44
45
|
}
|
|
45
46
|
export declare const getCodeBlockAdvancedNodeView: (props: ConfigProps) => (node: PMNode, view: EditorView, getPos: getPosHandler) => CodeBlockAdvancedNodeView;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atlaskit/editor-plugin-code-block-advanced",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.4",
|
|
4
4
|
"description": "CodeBlockAdvanced plugin for @atlaskit/editor-core",
|
|
5
5
|
"author": "Atlassian Pty Ltd",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -33,14 +33,14 @@
|
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
35
|
"@atlaskit/adf-schema": "^47.6.0",
|
|
36
|
-
"@atlaskit/editor-common": "^
|
|
37
|
-
"@atlaskit/editor-plugin-code-block": "^4.
|
|
36
|
+
"@atlaskit/editor-common": "^102.18.0",
|
|
37
|
+
"@atlaskit/editor-plugin-code-block": "^4.2.0",
|
|
38
38
|
"@atlaskit/editor-plugin-editor-disabled": "^2.0.0",
|
|
39
39
|
"@atlaskit/editor-plugin-find-replace": "^2.0.0",
|
|
40
|
-
"@atlaskit/editor-plugin-selection": "^2.
|
|
41
|
-
"@atlaskit/editor-plugin-selection-marker": "^2.
|
|
40
|
+
"@atlaskit/editor-plugin-selection": "^2.1.0",
|
|
41
|
+
"@atlaskit/editor-plugin-selection-marker": "^2.1.0",
|
|
42
42
|
"@atlaskit/editor-prosemirror": "7.0.0",
|
|
43
|
-
"@atlaskit/tokens": "^4.
|
|
43
|
+
"@atlaskit/tokens": "^4.6.0",
|
|
44
44
|
"@babel/runtime": "^7.0.0",
|
|
45
45
|
"@codemirror/autocomplete": "6.18.4",
|
|
46
46
|
"@codemirror/commands": "6.7.1",
|
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
"react": "^18.2.0"
|
|
57
57
|
},
|
|
58
58
|
"devDependencies": {
|
|
59
|
-
"@atlaskit/code": "^16.
|
|
59
|
+
"@atlaskit/code": "^16.2.0",
|
|
60
60
|
"typescript": "~5.4.2"
|
|
61
61
|
},
|
|
62
62
|
"techstack": {
|
|
@@ -19,6 +19,7 @@ import type {
|
|
|
19
19
|
EditorView,
|
|
20
20
|
NodeView,
|
|
21
21
|
} from '@atlaskit/editor-prosemirror/view';
|
|
22
|
+
import { DecorationSet } from '@atlaskit/editor-prosemirror/view';
|
|
22
23
|
|
|
23
24
|
import type { CodeBlockAdvancedPlugin } from '../codeBlockAdvancedPluginType';
|
|
24
25
|
import { highlightStyle } from '../ui/syntaxHighlightingTheme';
|
|
@@ -113,6 +114,10 @@ class CodeBlockAdvancedNodeView implements NodeView {
|
|
|
113
114
|
}
|
|
114
115
|
|
|
115
116
|
destroy() {
|
|
117
|
+
// ED-27428: CodeMirror gets into an infinite loop as it detects mutations on removed
|
|
118
|
+
// decorations. When we change the breakout we destroy the node and cleanup these decorations from
|
|
119
|
+
// codemirror
|
|
120
|
+
this.clearProseMirrorDecorations();
|
|
116
121
|
this.cleanupDisabledState?.();
|
|
117
122
|
}
|
|
118
123
|
|
|
@@ -214,6 +219,15 @@ class CodeBlockAdvancedNodeView implements NodeView {
|
|
|
214
219
|
this.updating = false;
|
|
215
220
|
}
|
|
216
221
|
|
|
222
|
+
private clearProseMirrorDecorations() {
|
|
223
|
+
this.updating = true;
|
|
224
|
+
const computedFacet = this.pmFacet.compute([], () => DecorationSet.empty);
|
|
225
|
+
this.cm.dispatch({
|
|
226
|
+
effects: this.pmDecorationsCompartment.reconfigure(computedFacet),
|
|
227
|
+
});
|
|
228
|
+
this.updating = false;
|
|
229
|
+
}
|
|
230
|
+
|
|
217
231
|
stopEvent(e: Event) {
|
|
218
232
|
if (e instanceof MouseEvent && e.type === 'mousedown') {
|
|
219
233
|
// !Warning: Side effect!
|
package/src/pm-plugins/main.ts
CHANGED
|
@@ -2,10 +2,13 @@ import type { Extension } from '@codemirror/state';
|
|
|
2
2
|
|
|
3
3
|
import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
|
|
4
4
|
import type { ExtractInjectionAPI } from '@atlaskit/editor-common/types';
|
|
5
|
+
import type { EditorView } from '@atlaskit/editor-prosemirror/view';
|
|
5
6
|
|
|
6
7
|
import type { CodeBlockAdvancedPlugin } from '../codeBlockAdvancedPluginType';
|
|
7
8
|
import { lazyCodeBlockView } from '../nodeviews/lazyCodeBlockAdvanced';
|
|
8
9
|
|
|
10
|
+
import { shiftArrowDownWorkaround, shiftArrowUpWorkaround } from './shiftArrowKeyWorkaround';
|
|
11
|
+
|
|
9
12
|
interface Props {
|
|
10
13
|
api: ExtractInjectionAPI<CodeBlockAdvancedPlugin> | undefined;
|
|
11
14
|
extensions: Extension[];
|
|
@@ -17,6 +20,20 @@ export const createPlugin = (props: Props) => {
|
|
|
17
20
|
nodeViews: {
|
|
18
21
|
codeBlock: lazyCodeBlockView(props),
|
|
19
22
|
},
|
|
23
|
+
// Custom selection behaviour to fix issues with codeblocks with Shift + Arrow{Up || Down}
|
|
24
|
+
// These issues are also present in the prosemirror codemirror example and @marijnh suggests to
|
|
25
|
+
// use custom event handlers: https://github.com/ProseMirror/website/issues/83
|
|
26
|
+
handleKeyDown(view: EditorView, event: KeyboardEvent) {
|
|
27
|
+
if (!(event instanceof KeyboardEvent)) {
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (event.key === 'ArrowUp' && event.shiftKey) {
|
|
32
|
+
return shiftArrowUpWorkaround(view, event);
|
|
33
|
+
} else if (event.key === 'ArrowDown' && event.shiftKey) {
|
|
34
|
+
return shiftArrowDownWorkaround(view, event);
|
|
35
|
+
}
|
|
36
|
+
},
|
|
20
37
|
},
|
|
21
38
|
});
|
|
22
39
|
};
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { TextSelection } from '@atlaskit/editor-prosemirror/state';
|
|
2
|
+
import type { EditorView } from '@atlaskit/editor-prosemirror/view';
|
|
3
|
+
|
|
4
|
+
export const shiftArrowUpWorkaround = (view: EditorView, event: KeyboardEvent) => {
|
|
5
|
+
const {
|
|
6
|
+
doc,
|
|
7
|
+
selection: { $head, $anchor },
|
|
8
|
+
tr,
|
|
9
|
+
schema: {
|
|
10
|
+
nodes: { codeBlock },
|
|
11
|
+
},
|
|
12
|
+
} = view.state;
|
|
13
|
+
|
|
14
|
+
// Position we want to check (directly after our current position)
|
|
15
|
+
const pos = Math.max($head.pos - 1, 1);
|
|
16
|
+
const isNodeBefore = doc.resolve(pos).nodeBefore?.type === codeBlock;
|
|
17
|
+
const maybeProblematicNode = isNodeBefore ? doc.resolve(pos).nodeBefore : doc.resolve(pos).node();
|
|
18
|
+
|
|
19
|
+
if (maybeProblematicNode?.type === codeBlock) {
|
|
20
|
+
const nodeSize = maybeProblematicNode.nodeSize;
|
|
21
|
+
const startPos = isNodeBefore ? pos : $head.pos;
|
|
22
|
+
|
|
23
|
+
tr.setSelection(TextSelection.create(doc, $anchor.pos, Math.max(startPos - nodeSize, 0)));
|
|
24
|
+
view.dispatch(tr);
|
|
25
|
+
event.preventDefault();
|
|
26
|
+
return true;
|
|
27
|
+
}
|
|
28
|
+
return false;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export const shiftArrowDownWorkaround = (view: EditorView, event: KeyboardEvent) => {
|
|
32
|
+
const {
|
|
33
|
+
doc,
|
|
34
|
+
selection: { $head, $anchor },
|
|
35
|
+
tr,
|
|
36
|
+
schema: {
|
|
37
|
+
nodes: { codeBlock },
|
|
38
|
+
},
|
|
39
|
+
} = view.state;
|
|
40
|
+
|
|
41
|
+
// Position we want to check (directly after our current position)
|
|
42
|
+
const pos = $head.pos + 1;
|
|
43
|
+
const isNodeAfter = doc.resolve(pos).nodeAfter?.type === codeBlock;
|
|
44
|
+
const maybeProblematicNode = isNodeAfter ? doc.resolve(pos).nodeAfter : doc.resolve(pos).node();
|
|
45
|
+
|
|
46
|
+
if (maybeProblematicNode?.type === codeBlock) {
|
|
47
|
+
const nodeSize = maybeProblematicNode.nodeSize;
|
|
48
|
+
const startPos = isNodeAfter ? pos : $head.pos;
|
|
49
|
+
|
|
50
|
+
tr.setSelection(
|
|
51
|
+
TextSelection.create(doc, $anchor.pos, Math.min(startPos + nodeSize, doc.content.size)),
|
|
52
|
+
);
|
|
53
|
+
view.dispatch(tr);
|
|
54
|
+
event.preventDefault();
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
57
|
+
return false;
|
|
58
|
+
};
|