@codemirror/view 6.39.10 → 6.39.12
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/index.cjs +23 -13
- package/dist/index.js +23 -13
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,19 @@
|
|
|
1
|
+
## 6.39.12 (2026-01-30)
|
|
2
|
+
|
|
3
|
+
### Bug fixes
|
|
4
|
+
|
|
5
|
+
Fix a bug where the visual selection drawn by `drawSelection` could fail to update properly in some circumstances.
|
|
6
|
+
|
|
7
|
+
Fix a bug where PageUp/PageDown near the edge of the viewport might completely skip to the start/end of the document.
|
|
8
|
+
|
|
9
|
+
Fix a regression that caused mark decorations to be split on text node chunk boundaries again.
|
|
10
|
+
|
|
11
|
+
## 6.39.11 (2026-01-14)
|
|
12
|
+
|
|
13
|
+
### Bug fixes
|
|
14
|
+
|
|
15
|
+
Avoid handling copy events for parent editors.
|
|
16
|
+
|
|
1
17
|
## 6.39.10 (2026-01-13)
|
|
2
18
|
|
|
3
19
|
### Bug fixes
|
package/dist/index.cjs
CHANGED
|
@@ -2266,7 +2266,7 @@ class TileBuilder {
|
|
|
2266
2266
|
this.flushBuffer();
|
|
2267
2267
|
let parent = this.ensureMarks(marks, openStart);
|
|
2268
2268
|
let prev = parent.lastChild;
|
|
2269
|
-
if (prev && prev.isText() && !(prev.flags & 8 /* TileFlag.Composition */)) {
|
|
2269
|
+
if (prev && prev.isText() && !(prev.flags & 8 /* TileFlag.Composition */) && prev.length + text.length < 512 /* C.Chunk */) {
|
|
2270
2270
|
this.cache.reused.set(prev, 2 /* Reused.DOM */);
|
|
2271
2271
|
let tile = parent.children[parent.children.length - 1] = new TextTile(prev.dom, prev.text + text);
|
|
2272
2272
|
tile.parent = parent;
|
|
@@ -2760,7 +2760,7 @@ class TileUpdate {
|
|
|
2760
2760
|
}
|
|
2761
2761
|
else {
|
|
2762
2762
|
b.ensureLine(pendingLineAttrs);
|
|
2763
|
-
b.addText(chars, active, openStart);
|
|
2763
|
+
b.addText(chars, active, pos == from ? openStart : active.length);
|
|
2764
2764
|
pos += chars.length;
|
|
2765
2765
|
}
|
|
2766
2766
|
pendingLineAttrs = null;
|
|
@@ -3674,11 +3674,8 @@ function moveVertically(view, start, forward, distance) {
|
|
|
3674
3674
|
}
|
|
3675
3675
|
let resolvedGoal = rect.left + goal;
|
|
3676
3676
|
let dist = distance !== null && distance !== void 0 ? distance : (view.viewState.heightOracle.textHeight >> 1);
|
|
3677
|
-
|
|
3678
|
-
|
|
3679
|
-
let pos = posAtCoords(view, { x: resolvedGoal, y: curY }, false, dir);
|
|
3680
|
-
return state.EditorSelection.cursor(pos.pos, pos.assoc, undefined, goal);
|
|
3681
|
-
}
|
|
3677
|
+
let pos = posAtCoords(view, { x: resolvedGoal, y: startY + dist * dir }, false, dir);
|
|
3678
|
+
return state.EditorSelection.cursor(pos.pos, pos.assoc, undefined, goal);
|
|
3682
3679
|
}
|
|
3683
3680
|
function skipAtomicRanges(atoms, pos, bias) {
|
|
3684
3681
|
for (;;) {
|
|
@@ -3744,7 +3741,9 @@ function posAtCoords(view, coords, precise, scanY) {
|
|
|
3744
3741
|
if (scanY == null)
|
|
3745
3742
|
break;
|
|
3746
3743
|
if (block.type == exports.BlockType.Text) {
|
|
3747
|
-
|
|
3744
|
+
if (scanY < 0 ? block.to < view.viewport.from : block.from > view.viewport.to)
|
|
3745
|
+
break;
|
|
3746
|
+
// Check whether we aren't landing on the top/bottom padding of the line
|
|
3748
3747
|
let rect = view.docView.coordsAt(scanY < 0 ? block.from : block.to, scanY);
|
|
3749
3748
|
if (rect && (scanY < 0 ? rect.top <= yOffset + docTop : rect.bottom >= yOffset + docTop))
|
|
3750
3749
|
break;
|
|
@@ -4088,7 +4087,7 @@ function applyDOMChange(view, domChange) {
|
|
|
4088
4087
|
insert: state.Text.of(domChange.text.slice(diff.from, diff.toB).split(LineBreakPlaceholder)) };
|
|
4089
4088
|
}
|
|
4090
4089
|
}
|
|
4091
|
-
else if (newSel && (!view.hasFocus && view.state.facet(editable) || newSel
|
|
4090
|
+
else if (newSel && (!view.hasFocus && view.state.facet(editable) || sameSelPos(newSel, sel))) {
|
|
4092
4091
|
newSel = null;
|
|
4093
4092
|
}
|
|
4094
4093
|
if (!change && !newSel)
|
|
@@ -4140,7 +4139,7 @@ function applyDOMChange(view, domChange) {
|
|
|
4140
4139
|
if (change) {
|
|
4141
4140
|
return applyDOMChangeInner(view, change, newSel, lastKey);
|
|
4142
4141
|
}
|
|
4143
|
-
else if (newSel && !newSel
|
|
4142
|
+
else if (newSel && !sameSelPos(newSel, sel)) {
|
|
4144
4143
|
let scrollIntoView = false, userEvent = "select";
|
|
4145
4144
|
if (view.inputState.lastSelectionTime > Date.now() - 50) {
|
|
4146
4145
|
if (view.inputState.lastSelectionOrigin == "select")
|
|
@@ -4311,6 +4310,9 @@ function selectionFromPoints(points, base) {
|
|
|
4311
4310
|
let anchor = points[0].pos, head = points.length == 2 ? points[1].pos : anchor;
|
|
4312
4311
|
return anchor > -1 && head > -1 ? state.EditorSelection.single(anchor + base, head + base) : null;
|
|
4313
4312
|
}
|
|
4313
|
+
function sameSelPos(selection, range) {
|
|
4314
|
+
return range.head == selection.main.head && range.anchor == selection.main.anchor;
|
|
4315
|
+
}
|
|
4314
4316
|
|
|
4315
4317
|
class InputState {
|
|
4316
4318
|
setSelectionOrigin(origin) {
|
|
@@ -4993,6 +4995,14 @@ function copiedRange(state) {
|
|
|
4993
4995
|
}
|
|
4994
4996
|
let lastLinewiseCopy = null;
|
|
4995
4997
|
handlers.copy = handlers.cut = (view, event) => {
|
|
4998
|
+
// If the DOM selection is outside this editor, don't intercept.
|
|
4999
|
+
// This happens when a parent editor (like ProseMirror) selects content that
|
|
5000
|
+
// spans multiple elements including this CodeMirror. The copy event may
|
|
5001
|
+
// bubble through CodeMirror (e.g. when CodeMirror is the first or the last
|
|
5002
|
+
// element in the selection), but we should let the parent handle it.
|
|
5003
|
+
let domSel = getSelection(view.root);
|
|
5004
|
+
if (domSel && !hasSelection(view.contentDOM, domSel))
|
|
5005
|
+
return false;
|
|
4996
5006
|
let { text, ranges, linewise } = copiedRange(view.state);
|
|
4997
5007
|
if (!text && !linewise)
|
|
4998
5008
|
return false;
|
|
@@ -7226,7 +7236,7 @@ class DOMObserver {
|
|
|
7226
7236
|
let handled = applyDOMChange(this.view, domChange);
|
|
7227
7237
|
// The view wasn't updated but DOM/selection changes were seen. Reset the view.
|
|
7228
7238
|
if (this.view.state == startState &&
|
|
7229
|
-
(domChange.domChanged || domChange.newSel && !
|
|
7239
|
+
(domChange.domChanged || domChange.newSel && !sameSelPos(this.view.state.selection, domChange.newSel.main)))
|
|
7230
7240
|
this.view.update([]);
|
|
7231
7241
|
return handled;
|
|
7232
7242
|
}
|
|
@@ -7390,7 +7400,7 @@ class EditContextManager {
|
|
|
7390
7400
|
// Edit contexts sometimes fire empty changes
|
|
7391
7401
|
if (!diff) {
|
|
7392
7402
|
let newSel = state.EditorSelection.single(this.toEditorPos(e.selectionStart), this.toEditorPos(e.selectionEnd));
|
|
7393
|
-
if (!newSel
|
|
7403
|
+
if (!sameSelPos(newSel, main))
|
|
7394
7404
|
view.dispatch({ selection: newSel, userEvent: "select" });
|
|
7395
7405
|
return;
|
|
7396
7406
|
}
|
|
@@ -9090,7 +9100,7 @@ function rectanglesForRange(view, className, range) {
|
|
|
9090
9100
|
return pieces(top).concat(between).concat(pieces(bottom));
|
|
9091
9101
|
}
|
|
9092
9102
|
function piece(left, top, right, bottom) {
|
|
9093
|
-
return new RectangleMarker(className, left - base.left, top - base.top, right - left, bottom - top);
|
|
9103
|
+
return new RectangleMarker(className, left - base.left, top - base.top, Math.max(0, right - left), bottom - top);
|
|
9094
9104
|
}
|
|
9095
9105
|
function pieces({ top, bottom, horizontal }) {
|
|
9096
9106
|
let pieces = [];
|
package/dist/index.js
CHANGED
|
@@ -2262,7 +2262,7 @@ class TileBuilder {
|
|
|
2262
2262
|
this.flushBuffer();
|
|
2263
2263
|
let parent = this.ensureMarks(marks, openStart);
|
|
2264
2264
|
let prev = parent.lastChild;
|
|
2265
|
-
if (prev && prev.isText() && !(prev.flags & 8 /* TileFlag.Composition */)) {
|
|
2265
|
+
if (prev && prev.isText() && !(prev.flags & 8 /* TileFlag.Composition */) && prev.length + text.length < 512 /* C.Chunk */) {
|
|
2266
2266
|
this.cache.reused.set(prev, 2 /* Reused.DOM */);
|
|
2267
2267
|
let tile = parent.children[parent.children.length - 1] = new TextTile(prev.dom, prev.text + text);
|
|
2268
2268
|
tile.parent = parent;
|
|
@@ -2756,7 +2756,7 @@ class TileUpdate {
|
|
|
2756
2756
|
}
|
|
2757
2757
|
else {
|
|
2758
2758
|
b.ensureLine(pendingLineAttrs);
|
|
2759
|
-
b.addText(chars, active, openStart);
|
|
2759
|
+
b.addText(chars, active, pos == from ? openStart : active.length);
|
|
2760
2760
|
pos += chars.length;
|
|
2761
2761
|
}
|
|
2762
2762
|
pendingLineAttrs = null;
|
|
@@ -3670,11 +3670,8 @@ function moveVertically(view, start, forward, distance) {
|
|
|
3670
3670
|
}
|
|
3671
3671
|
let resolvedGoal = rect.left + goal;
|
|
3672
3672
|
let dist = distance !== null && distance !== void 0 ? distance : (view.viewState.heightOracle.textHeight >> 1);
|
|
3673
|
-
|
|
3674
|
-
|
|
3675
|
-
let pos = posAtCoords(view, { x: resolvedGoal, y: curY }, false, dir);
|
|
3676
|
-
return EditorSelection.cursor(pos.pos, pos.assoc, undefined, goal);
|
|
3677
|
-
}
|
|
3673
|
+
let pos = posAtCoords(view, { x: resolvedGoal, y: startY + dist * dir }, false, dir);
|
|
3674
|
+
return EditorSelection.cursor(pos.pos, pos.assoc, undefined, goal);
|
|
3678
3675
|
}
|
|
3679
3676
|
function skipAtomicRanges(atoms, pos, bias) {
|
|
3680
3677
|
for (;;) {
|
|
@@ -3740,7 +3737,9 @@ function posAtCoords(view, coords, precise, scanY) {
|
|
|
3740
3737
|
if (scanY == null)
|
|
3741
3738
|
break;
|
|
3742
3739
|
if (block.type == BlockType.Text) {
|
|
3743
|
-
|
|
3740
|
+
if (scanY < 0 ? block.to < view.viewport.from : block.from > view.viewport.to)
|
|
3741
|
+
break;
|
|
3742
|
+
// Check whether we aren't landing on the top/bottom padding of the line
|
|
3744
3743
|
let rect = view.docView.coordsAt(scanY < 0 ? block.from : block.to, scanY);
|
|
3745
3744
|
if (rect && (scanY < 0 ? rect.top <= yOffset + docTop : rect.bottom >= yOffset + docTop))
|
|
3746
3745
|
break;
|
|
@@ -4084,7 +4083,7 @@ function applyDOMChange(view, domChange) {
|
|
|
4084
4083
|
insert: Text.of(domChange.text.slice(diff.from, diff.toB).split(LineBreakPlaceholder)) };
|
|
4085
4084
|
}
|
|
4086
4085
|
}
|
|
4087
|
-
else if (newSel && (!view.hasFocus && view.state.facet(editable) || newSel
|
|
4086
|
+
else if (newSel && (!view.hasFocus && view.state.facet(editable) || sameSelPos(newSel, sel))) {
|
|
4088
4087
|
newSel = null;
|
|
4089
4088
|
}
|
|
4090
4089
|
if (!change && !newSel)
|
|
@@ -4136,7 +4135,7 @@ function applyDOMChange(view, domChange) {
|
|
|
4136
4135
|
if (change) {
|
|
4137
4136
|
return applyDOMChangeInner(view, change, newSel, lastKey);
|
|
4138
4137
|
}
|
|
4139
|
-
else if (newSel && !newSel
|
|
4138
|
+
else if (newSel && !sameSelPos(newSel, sel)) {
|
|
4140
4139
|
let scrollIntoView = false, userEvent = "select";
|
|
4141
4140
|
if (view.inputState.lastSelectionTime > Date.now() - 50) {
|
|
4142
4141
|
if (view.inputState.lastSelectionOrigin == "select")
|
|
@@ -4307,6 +4306,9 @@ function selectionFromPoints(points, base) {
|
|
|
4307
4306
|
let anchor = points[0].pos, head = points.length == 2 ? points[1].pos : anchor;
|
|
4308
4307
|
return anchor > -1 && head > -1 ? EditorSelection.single(anchor + base, head + base) : null;
|
|
4309
4308
|
}
|
|
4309
|
+
function sameSelPos(selection, range) {
|
|
4310
|
+
return range.head == selection.main.head && range.anchor == selection.main.anchor;
|
|
4311
|
+
}
|
|
4310
4312
|
|
|
4311
4313
|
class InputState {
|
|
4312
4314
|
setSelectionOrigin(origin) {
|
|
@@ -4989,6 +4991,14 @@ function copiedRange(state) {
|
|
|
4989
4991
|
}
|
|
4990
4992
|
let lastLinewiseCopy = null;
|
|
4991
4993
|
handlers.copy = handlers.cut = (view, event) => {
|
|
4994
|
+
// If the DOM selection is outside this editor, don't intercept.
|
|
4995
|
+
// This happens when a parent editor (like ProseMirror) selects content that
|
|
4996
|
+
// spans multiple elements including this CodeMirror. The copy event may
|
|
4997
|
+
// bubble through CodeMirror (e.g. when CodeMirror is the first or the last
|
|
4998
|
+
// element in the selection), but we should let the parent handle it.
|
|
4999
|
+
let domSel = getSelection(view.root);
|
|
5000
|
+
if (domSel && !hasSelection(view.contentDOM, domSel))
|
|
5001
|
+
return false;
|
|
4992
5002
|
let { text, ranges, linewise } = copiedRange(view.state);
|
|
4993
5003
|
if (!text && !linewise)
|
|
4994
5004
|
return false;
|
|
@@ -7221,7 +7231,7 @@ class DOMObserver {
|
|
|
7221
7231
|
let handled = applyDOMChange(this.view, domChange);
|
|
7222
7232
|
// The view wasn't updated but DOM/selection changes were seen. Reset the view.
|
|
7223
7233
|
if (this.view.state == startState &&
|
|
7224
|
-
(domChange.domChanged || domChange.newSel && !
|
|
7234
|
+
(domChange.domChanged || domChange.newSel && !sameSelPos(this.view.state.selection, domChange.newSel.main)))
|
|
7225
7235
|
this.view.update([]);
|
|
7226
7236
|
return handled;
|
|
7227
7237
|
}
|
|
@@ -7385,7 +7395,7 @@ class EditContextManager {
|
|
|
7385
7395
|
// Edit contexts sometimes fire empty changes
|
|
7386
7396
|
if (!diff) {
|
|
7387
7397
|
let newSel = EditorSelection.single(this.toEditorPos(e.selectionStart), this.toEditorPos(e.selectionEnd));
|
|
7388
|
-
if (!newSel
|
|
7398
|
+
if (!sameSelPos(newSel, main))
|
|
7389
7399
|
view.dispatch({ selection: newSel, userEvent: "select" });
|
|
7390
7400
|
return;
|
|
7391
7401
|
}
|
|
@@ -9085,7 +9095,7 @@ function rectanglesForRange(view, className, range) {
|
|
|
9085
9095
|
return pieces(top).concat(between).concat(pieces(bottom));
|
|
9086
9096
|
}
|
|
9087
9097
|
function piece(left, top, right, bottom) {
|
|
9088
|
-
return new RectangleMarker(className, left - base.left, top - base.top, right - left, bottom - top);
|
|
9098
|
+
return new RectangleMarker(className, left - base.left, top - base.top, Math.max(0, right - left), bottom - top);
|
|
9089
9099
|
}
|
|
9090
9100
|
function pieces({ top, bottom, horizontal }) {
|
|
9091
9101
|
let pieces = [];
|