@codemirror/view 6.17.0 → 6.17.1
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 +14 -0
- package/dist/index.cjs +37 -21
- package/dist/index.js +37 -21
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
## 6.17.1 (2023-08-31)
|
|
2
|
+
|
|
3
|
+
### Bug fixes
|
|
4
|
+
|
|
5
|
+
Don't close the hover tooltip when the pointer moves over empty space caused by line breaks within the hovered range.
|
|
6
|
+
|
|
7
|
+
Fix a bug where on Chrome Android, if a virtual keyboard was slow to apply a change, the editor could end up dropping it.
|
|
8
|
+
|
|
9
|
+
Work around an issue where line-wise copy/cut didn't work in Firefox because the browser wasn't firing those events when nothing was selected.
|
|
10
|
+
|
|
11
|
+
Fix a crash triggered by the way some Android IME systems update the DOM.
|
|
12
|
+
|
|
13
|
+
Fix a bug that caused replacing a word by an emoji on Chrome Android to be treated as a backspace press.
|
|
14
|
+
|
|
1
15
|
## 6.17.0 (2023-08-28)
|
|
2
16
|
|
|
3
17
|
### Bug fixes
|
package/dist/index.cjs
CHANGED
|
@@ -3184,7 +3184,7 @@ class BlockGapWidget extends WidgetType {
|
|
|
3184
3184
|
}
|
|
3185
3185
|
get estimatedHeight() { return this.height; }
|
|
3186
3186
|
}
|
|
3187
|
-
function findCompositionNode(view) {
|
|
3187
|
+
function findCompositionNode(view, dLen) {
|
|
3188
3188
|
let sel = view.observer.selectionRange;
|
|
3189
3189
|
let textNode = sel.focusNode && nearbyTextNode(sel.focusNode, sel.focusOffset, 0);
|
|
3190
3190
|
if (!textNode)
|
|
@@ -3196,10 +3196,12 @@ function findCompositionNode(view) {
|
|
|
3196
3196
|
to = from + cView.length;
|
|
3197
3197
|
}
|
|
3198
3198
|
else {
|
|
3199
|
+
let oldLen = Math.max(0, textNode.nodeValue.length - dLen);
|
|
3199
3200
|
up: for (let offset = 0, node = textNode;;) {
|
|
3200
3201
|
for (let sibling = node.previousSibling, cView; sibling; sibling = sibling.previousSibling) {
|
|
3201
3202
|
if (cView = ContentView.get(sibling)) {
|
|
3202
|
-
|
|
3203
|
+
to = cView.posAtEnd + offset;
|
|
3204
|
+
from = Math.max(0, to - oldLen);
|
|
3203
3205
|
break up;
|
|
3204
3206
|
}
|
|
3205
3207
|
let reader = new DOMReader([], view.state);
|
|
@@ -3213,15 +3215,16 @@ function findCompositionNode(view) {
|
|
|
3213
3215
|
return null;
|
|
3214
3216
|
let parentView = ContentView.get(node);
|
|
3215
3217
|
if (parentView) {
|
|
3216
|
-
from =
|
|
3218
|
+
from = parentView.posAtStart + offset;
|
|
3219
|
+
to = from + oldLen;
|
|
3217
3220
|
break;
|
|
3218
3221
|
}
|
|
3219
3222
|
}
|
|
3220
3223
|
}
|
|
3221
|
-
return { from, to, node: textNode };
|
|
3224
|
+
return { from, to: to, node: textNode };
|
|
3222
3225
|
}
|
|
3223
3226
|
function findCompositionRange(view, changes) {
|
|
3224
|
-
let found = findCompositionNode(view);
|
|
3227
|
+
let found = findCompositionNode(view, changes.newLength - changes.length);
|
|
3225
3228
|
if (!found)
|
|
3226
3229
|
return null;
|
|
3227
3230
|
let { from: fromA, to: toA, node: textNode } = found;
|
|
@@ -3785,6 +3788,8 @@ class InputState {
|
|
|
3785
3788
|
// issue where the composition vanishes when you press enter.
|
|
3786
3789
|
if (browser.safari)
|
|
3787
3790
|
view.contentDOM.addEventListener("input", () => null);
|
|
3791
|
+
if (browser.gecko)
|
|
3792
|
+
firefoxCopyCutHack(view.contentDOM.ownerDocument);
|
|
3788
3793
|
}
|
|
3789
3794
|
ensureHandlers(view, plugins) {
|
|
3790
3795
|
var _a;
|
|
@@ -4490,6 +4495,18 @@ handlers.beforeinput = (view, event) => {
|
|
|
4490
4495
|
}
|
|
4491
4496
|
}
|
|
4492
4497
|
};
|
|
4498
|
+
const appliedFirefoxHack = new Set;
|
|
4499
|
+
// In Firefox, when cut/copy handlers are added to the document, that
|
|
4500
|
+
// somehow avoids a bug where those events aren't fired when the
|
|
4501
|
+
// selection is empty. See https://github.com/codemirror/dev/issues/1082
|
|
4502
|
+
// and https://bugzilla.mozilla.org/show_bug.cgi?id=995961
|
|
4503
|
+
function firefoxCopyCutHack(doc) {
|
|
4504
|
+
if (!appliedFirefoxHack.has(doc)) {
|
|
4505
|
+
appliedFirefoxHack.add(doc);
|
|
4506
|
+
doc.addEventListener("copy", () => { });
|
|
4507
|
+
doc.addEventListener("cut", () => { });
|
|
4508
|
+
}
|
|
4509
|
+
}
|
|
4493
4510
|
|
|
4494
4511
|
const wrappingWhiteSpace = ["pre-wrap", "normal", "pre-line", "break-spaces"];
|
|
4495
4512
|
class HeightOracle {
|
|
@@ -6146,7 +6163,7 @@ function applyDOMChange(view, domChange) {
|
|
|
6146
6163
|
change.insert.length == 1 && change.insert.lines == 2 &&
|
|
6147
6164
|
dispatchKey(view.contentDOM, "Enter", 13)) ||
|
|
6148
6165
|
((change.from == sel.from - 1 && change.to == sel.to && change.insert.length == 0 ||
|
|
6149
|
-
lastKey == 8 && change.insert.length < change.to - change.from) &&
|
|
6166
|
+
lastKey == 8 && change.insert.length < change.to - change.from && change.to > sel.head) &&
|
|
6150
6167
|
dispatchKey(view.contentDOM, "Backspace", 8)) ||
|
|
6151
6168
|
(change.from == sel.from && change.to == sel.to + 1 && change.insert.length == 0 &&
|
|
6152
6169
|
dispatchKey(view.contentDOM, "Delete", 46))))
|
|
@@ -6190,7 +6207,8 @@ function applyDefaultInsert(view, change, newSel) {
|
|
|
6190
6207
|
if (startState.selection.ranges.length > 1 && view.inputState.composing >= 0 &&
|
|
6191
6208
|
change.to <= sel.to && change.to >= sel.to - 10) {
|
|
6192
6209
|
let replaced = view.state.sliceDoc(change.from, change.to);
|
|
6193
|
-
let composition = findCompositionNode(view
|
|
6210
|
+
let composition = findCompositionNode(view, change.insert.length - (change.to - change.from)) ||
|
|
6211
|
+
view.state.doc.lineAt(sel.head);
|
|
6194
6212
|
let offset = sel.to - change.to, size = sel.to - sel.from;
|
|
6195
6213
|
tr = startState.changeByRange(range => {
|
|
6196
6214
|
if (range.from == sel.from && range.to == sel.to)
|
|
@@ -7040,6 +7058,11 @@ class EditorView {
|
|
|
7040
7058
|
return;
|
|
7041
7059
|
if (this.measureScheduled > -1)
|
|
7042
7060
|
this.win.cancelAnimationFrame(this.measureScheduled);
|
|
7061
|
+
if (this.observer.delayedAndroidKey) {
|
|
7062
|
+
this.measureScheduled = -1;
|
|
7063
|
+
this.requestMeasure();
|
|
7064
|
+
return;
|
|
7065
|
+
}
|
|
7043
7066
|
this.measureScheduled = 0; // Prevent requestMeasure calls from scheduling another animation frame
|
|
7044
7067
|
if (flush)
|
|
7045
7068
|
this.observer.forceFlush();
|
|
@@ -9370,7 +9393,7 @@ class HoverPlugin {
|
|
|
9370
9393
|
if (tooltip && !isInTooltip(this.lastMove.target) || this.pending) {
|
|
9371
9394
|
let { pos } = tooltip || this.pending, end = (_a = tooltip === null || tooltip === void 0 ? void 0 : tooltip.end) !== null && _a !== void 0 ? _a : pos;
|
|
9372
9395
|
if ((pos == end ? this.view.posAtCoords(this.lastMove) != pos
|
|
9373
|
-
: !isOverRange(this.view, pos, end, event.clientX, event.clientY
|
|
9396
|
+
: !isOverRange(this.view, pos, end, event.clientX, event.clientY))) {
|
|
9374
9397
|
this.view.dispatch({ effects: this.setHover.of(null) });
|
|
9375
9398
|
this.pending = null;
|
|
9376
9399
|
}
|
|
@@ -9395,19 +9418,12 @@ function isInTooltip(elt) {
|
|
|
9395
9418
|
return false;
|
|
9396
9419
|
}
|
|
9397
9420
|
function isOverRange(view, from, to, x, y, margin) {
|
|
9398
|
-
let
|
|
9399
|
-
let
|
|
9400
|
-
|
|
9401
|
-
|
|
9402
|
-
let
|
|
9403
|
-
|
|
9404
|
-
for (let i = 0; i < rects.length; i++) {
|
|
9405
|
-
let rect = rects[i];
|
|
9406
|
-
let dist = Math.max(rect.top - y, y - rect.bottom, rect.left - x, x - rect.right);
|
|
9407
|
-
if (dist <= margin)
|
|
9408
|
-
return true;
|
|
9409
|
-
}
|
|
9410
|
-
return false;
|
|
9421
|
+
let rect = view.scrollDOM.getBoundingClientRect();
|
|
9422
|
+
let docBottom = view.documentTop + view.documentPadding.top + view.contentHeight;
|
|
9423
|
+
if (rect.left > x || rect.right < x || rect.top > y || Math.min(rect.bottom, docBottom) < y)
|
|
9424
|
+
return false;
|
|
9425
|
+
let pos = view.posAtCoords({ x, y }, false);
|
|
9426
|
+
return pos >= from && pos <= to;
|
|
9411
9427
|
}
|
|
9412
9428
|
/**
|
|
9413
9429
|
Set up a hover tooltip, which shows up when the pointer hovers
|
package/dist/index.js
CHANGED
|
@@ -3180,7 +3180,7 @@ class BlockGapWidget extends WidgetType {
|
|
|
3180
3180
|
}
|
|
3181
3181
|
get estimatedHeight() { return this.height; }
|
|
3182
3182
|
}
|
|
3183
|
-
function findCompositionNode(view) {
|
|
3183
|
+
function findCompositionNode(view, dLen) {
|
|
3184
3184
|
let sel = view.observer.selectionRange;
|
|
3185
3185
|
let textNode = sel.focusNode && nearbyTextNode(sel.focusNode, sel.focusOffset, 0);
|
|
3186
3186
|
if (!textNode)
|
|
@@ -3192,10 +3192,12 @@ function findCompositionNode(view) {
|
|
|
3192
3192
|
to = from + cView.length;
|
|
3193
3193
|
}
|
|
3194
3194
|
else {
|
|
3195
|
+
let oldLen = Math.max(0, textNode.nodeValue.length - dLen);
|
|
3195
3196
|
up: for (let offset = 0, node = textNode;;) {
|
|
3196
3197
|
for (let sibling = node.previousSibling, cView; sibling; sibling = sibling.previousSibling) {
|
|
3197
3198
|
if (cView = ContentView.get(sibling)) {
|
|
3198
|
-
|
|
3199
|
+
to = cView.posAtEnd + offset;
|
|
3200
|
+
from = Math.max(0, to - oldLen);
|
|
3199
3201
|
break up;
|
|
3200
3202
|
}
|
|
3201
3203
|
let reader = new DOMReader([], view.state);
|
|
@@ -3209,15 +3211,16 @@ function findCompositionNode(view) {
|
|
|
3209
3211
|
return null;
|
|
3210
3212
|
let parentView = ContentView.get(node);
|
|
3211
3213
|
if (parentView) {
|
|
3212
|
-
from =
|
|
3214
|
+
from = parentView.posAtStart + offset;
|
|
3215
|
+
to = from + oldLen;
|
|
3213
3216
|
break;
|
|
3214
3217
|
}
|
|
3215
3218
|
}
|
|
3216
3219
|
}
|
|
3217
|
-
return { from, to, node: textNode };
|
|
3220
|
+
return { from, to: to, node: textNode };
|
|
3218
3221
|
}
|
|
3219
3222
|
function findCompositionRange(view, changes) {
|
|
3220
|
-
let found = findCompositionNode(view);
|
|
3223
|
+
let found = findCompositionNode(view, changes.newLength - changes.length);
|
|
3221
3224
|
if (!found)
|
|
3222
3225
|
return null;
|
|
3223
3226
|
let { from: fromA, to: toA, node: textNode } = found;
|
|
@@ -3781,6 +3784,8 @@ class InputState {
|
|
|
3781
3784
|
// issue where the composition vanishes when you press enter.
|
|
3782
3785
|
if (browser.safari)
|
|
3783
3786
|
view.contentDOM.addEventListener("input", () => null);
|
|
3787
|
+
if (browser.gecko)
|
|
3788
|
+
firefoxCopyCutHack(view.contentDOM.ownerDocument);
|
|
3784
3789
|
}
|
|
3785
3790
|
ensureHandlers(view, plugins) {
|
|
3786
3791
|
var _a;
|
|
@@ -4486,6 +4491,18 @@ handlers.beforeinput = (view, event) => {
|
|
|
4486
4491
|
}
|
|
4487
4492
|
}
|
|
4488
4493
|
};
|
|
4494
|
+
const appliedFirefoxHack = /*@__PURE__*/new Set;
|
|
4495
|
+
// In Firefox, when cut/copy handlers are added to the document, that
|
|
4496
|
+
// somehow avoids a bug where those events aren't fired when the
|
|
4497
|
+
// selection is empty. See https://github.com/codemirror/dev/issues/1082
|
|
4498
|
+
// and https://bugzilla.mozilla.org/show_bug.cgi?id=995961
|
|
4499
|
+
function firefoxCopyCutHack(doc) {
|
|
4500
|
+
if (!appliedFirefoxHack.has(doc)) {
|
|
4501
|
+
appliedFirefoxHack.add(doc);
|
|
4502
|
+
doc.addEventListener("copy", () => { });
|
|
4503
|
+
doc.addEventListener("cut", () => { });
|
|
4504
|
+
}
|
|
4505
|
+
}
|
|
4489
4506
|
|
|
4490
4507
|
const wrappingWhiteSpace = ["pre-wrap", "normal", "pre-line", "break-spaces"];
|
|
4491
4508
|
class HeightOracle {
|
|
@@ -6141,7 +6158,7 @@ function applyDOMChange(view, domChange) {
|
|
|
6141
6158
|
change.insert.length == 1 && change.insert.lines == 2 &&
|
|
6142
6159
|
dispatchKey(view.contentDOM, "Enter", 13)) ||
|
|
6143
6160
|
((change.from == sel.from - 1 && change.to == sel.to && change.insert.length == 0 ||
|
|
6144
|
-
lastKey == 8 && change.insert.length < change.to - change.from) &&
|
|
6161
|
+
lastKey == 8 && change.insert.length < change.to - change.from && change.to > sel.head) &&
|
|
6145
6162
|
dispatchKey(view.contentDOM, "Backspace", 8)) ||
|
|
6146
6163
|
(change.from == sel.from && change.to == sel.to + 1 && change.insert.length == 0 &&
|
|
6147
6164
|
dispatchKey(view.contentDOM, "Delete", 46))))
|
|
@@ -6185,7 +6202,8 @@ function applyDefaultInsert(view, change, newSel) {
|
|
|
6185
6202
|
if (startState.selection.ranges.length > 1 && view.inputState.composing >= 0 &&
|
|
6186
6203
|
change.to <= sel.to && change.to >= sel.to - 10) {
|
|
6187
6204
|
let replaced = view.state.sliceDoc(change.from, change.to);
|
|
6188
|
-
let composition = findCompositionNode(view
|
|
6205
|
+
let composition = findCompositionNode(view, change.insert.length - (change.to - change.from)) ||
|
|
6206
|
+
view.state.doc.lineAt(sel.head);
|
|
6189
6207
|
let offset = sel.to - change.to, size = sel.to - sel.from;
|
|
6190
6208
|
tr = startState.changeByRange(range => {
|
|
6191
6209
|
if (range.from == sel.from && range.to == sel.to)
|
|
@@ -7035,6 +7053,11 @@ class EditorView {
|
|
|
7035
7053
|
return;
|
|
7036
7054
|
if (this.measureScheduled > -1)
|
|
7037
7055
|
this.win.cancelAnimationFrame(this.measureScheduled);
|
|
7056
|
+
if (this.observer.delayedAndroidKey) {
|
|
7057
|
+
this.measureScheduled = -1;
|
|
7058
|
+
this.requestMeasure();
|
|
7059
|
+
return;
|
|
7060
|
+
}
|
|
7038
7061
|
this.measureScheduled = 0; // Prevent requestMeasure calls from scheduling another animation frame
|
|
7039
7062
|
if (flush)
|
|
7040
7063
|
this.observer.forceFlush();
|
|
@@ -9365,7 +9388,7 @@ class HoverPlugin {
|
|
|
9365
9388
|
if (tooltip && !isInTooltip(this.lastMove.target) || this.pending) {
|
|
9366
9389
|
let { pos } = tooltip || this.pending, end = (_a = tooltip === null || tooltip === void 0 ? void 0 : tooltip.end) !== null && _a !== void 0 ? _a : pos;
|
|
9367
9390
|
if ((pos == end ? this.view.posAtCoords(this.lastMove) != pos
|
|
9368
|
-
: !isOverRange(this.view, pos, end, event.clientX, event.clientY
|
|
9391
|
+
: !isOverRange(this.view, pos, end, event.clientX, event.clientY))) {
|
|
9369
9392
|
this.view.dispatch({ effects: this.setHover.of(null) });
|
|
9370
9393
|
this.pending = null;
|
|
9371
9394
|
}
|
|
@@ -9390,19 +9413,12 @@ function isInTooltip(elt) {
|
|
|
9390
9413
|
return false;
|
|
9391
9414
|
}
|
|
9392
9415
|
function isOverRange(view, from, to, x, y, margin) {
|
|
9393
|
-
let
|
|
9394
|
-
let
|
|
9395
|
-
|
|
9396
|
-
|
|
9397
|
-
let
|
|
9398
|
-
|
|
9399
|
-
for (let i = 0; i < rects.length; i++) {
|
|
9400
|
-
let rect = rects[i];
|
|
9401
|
-
let dist = Math.max(rect.top - y, y - rect.bottom, rect.left - x, x - rect.right);
|
|
9402
|
-
if (dist <= margin)
|
|
9403
|
-
return true;
|
|
9404
|
-
}
|
|
9405
|
-
return false;
|
|
9416
|
+
let rect = view.scrollDOM.getBoundingClientRect();
|
|
9417
|
+
let docBottom = view.documentTop + view.documentPadding.top + view.contentHeight;
|
|
9418
|
+
if (rect.left > x || rect.right < x || rect.top > y || Math.min(rect.bottom, docBottom) < y)
|
|
9419
|
+
return false;
|
|
9420
|
+
let pos = view.posAtCoords({ x, y }, false);
|
|
9421
|
+
return pos >= from && pos <= to;
|
|
9406
9422
|
}
|
|
9407
9423
|
/**
|
|
9408
9424
|
Set up a hover tooltip, which shows up when the pointer hovers
|