@codemirror/view 6.1.0 → 6.1.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 +10 -0
- package/dist/index.cjs +66 -10
- package/dist/index.js +66 -10
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
## 6.1.1 (2022-07-25)
|
|
2
|
+
|
|
3
|
+
### Bug fixes
|
|
4
|
+
|
|
5
|
+
Make `highlightSpecialChars` replace directional isolate characters by default.
|
|
6
|
+
|
|
7
|
+
The editor will now try to suppress browsers' native behavior of resetting the selection in the editable content when the editable element is focused (programmatically, with tab, etc).
|
|
8
|
+
|
|
9
|
+
Fix a CSS issue that made it possible, when the gutters were wide enough, for them to overlap with the content.
|
|
10
|
+
|
|
1
11
|
## 6.1.0 (2022-07-19)
|
|
2
12
|
|
|
3
13
|
### New features
|
package/dist/index.cjs
CHANGED
|
@@ -268,6 +268,31 @@ function clearAttributes(node) {
|
|
|
268
268
|
while (node.attributes.length)
|
|
269
269
|
node.removeAttributeNode(node.attributes[0]);
|
|
270
270
|
}
|
|
271
|
+
function atElementStart(doc, selection) {
|
|
272
|
+
let node = selection.focusNode, offset = selection.focusOffset;
|
|
273
|
+
if (!node || selection.anchorNode != node || selection.anchorOffset != offset)
|
|
274
|
+
return false;
|
|
275
|
+
for (;;) {
|
|
276
|
+
if (offset) {
|
|
277
|
+
if (node.nodeType != 1)
|
|
278
|
+
return false;
|
|
279
|
+
let prev = node.childNodes[offset - 1];
|
|
280
|
+
if (prev.contentEditable == "false")
|
|
281
|
+
offset--;
|
|
282
|
+
else {
|
|
283
|
+
node = prev;
|
|
284
|
+
offset = maxOffset(node);
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
else if (node == doc) {
|
|
288
|
+
return true;
|
|
289
|
+
}
|
|
290
|
+
else {
|
|
291
|
+
offset = domIndex(node);
|
|
292
|
+
node = node.parentNode;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
}
|
|
271
296
|
|
|
272
297
|
class DOMPos {
|
|
273
298
|
constructor(node, offset, precise = true) {
|
|
@@ -3289,6 +3314,10 @@ class InputState {
|
|
|
3289
3314
|
constructor(view) {
|
|
3290
3315
|
this.lastKeyCode = 0;
|
|
3291
3316
|
this.lastKeyTime = 0;
|
|
3317
|
+
this.lastTouchTime = 0;
|
|
3318
|
+
this.lastFocusTime = 0;
|
|
3319
|
+
this.lastScrollTop = 0;
|
|
3320
|
+
this.lastScrollLeft = 0;
|
|
3292
3321
|
this.chromeScrollHack = -1;
|
|
3293
3322
|
// On iOS, some keys need to have their default behavior happen
|
|
3294
3323
|
// (after which we retroactively handle them and reset the DOM) to
|
|
@@ -3390,6 +3419,8 @@ class InputState {
|
|
|
3390
3419
|
return false;
|
|
3391
3420
|
}
|
|
3392
3421
|
runScrollHandlers(view, event) {
|
|
3422
|
+
this.lastScrollTop = view.scrollDOM.scrollTop;
|
|
3423
|
+
this.lastScrollLeft = view.scrollDOM.scrollLeft;
|
|
3393
3424
|
for (let set of this.customHandlers) {
|
|
3394
3425
|
let handler = set.handlers.scroll;
|
|
3395
3426
|
if (handler) {
|
|
@@ -3634,9 +3665,8 @@ handlers.keydown = (view, event) => {
|
|
|
3634
3665
|
else if (modifierCodes.indexOf(event.keyCode) < 0)
|
|
3635
3666
|
view.inputState.lastEscPress = 0;
|
|
3636
3667
|
};
|
|
3637
|
-
let lastTouch = 0;
|
|
3638
3668
|
handlers.touchstart = (view, e) => {
|
|
3639
|
-
|
|
3669
|
+
view.inputState.lastTouchTime = Date.now();
|
|
3640
3670
|
view.inputState.setSelectionOrigin("select.pointer");
|
|
3641
3671
|
};
|
|
3642
3672
|
handlers.touchmove = view => {
|
|
@@ -3644,7 +3674,7 @@ handlers.touchmove = view => {
|
|
|
3644
3674
|
};
|
|
3645
3675
|
handlers.mousedown = (view, event) => {
|
|
3646
3676
|
view.observer.flush();
|
|
3647
|
-
if (
|
|
3677
|
+
if (view.inputState.lastTouchTime > Date.now() - 2000 && getClickType(event) == 1)
|
|
3648
3678
|
return; // Ignore touch interaction
|
|
3649
3679
|
let style = null;
|
|
3650
3680
|
for (let makeStyle of view.state.facet(mouseSelectionStyle)) {
|
|
@@ -3898,7 +3928,15 @@ function updateForFocusChange(view) {
|
|
|
3898
3928
|
view.update([]);
|
|
3899
3929
|
}, 10);
|
|
3900
3930
|
}
|
|
3901
|
-
handlers.focus =
|
|
3931
|
+
handlers.focus = view => {
|
|
3932
|
+
view.inputState.lastFocusTime = Date.now();
|
|
3933
|
+
// When focusing reset the scroll position, move it back to where it was
|
|
3934
|
+
if (!view.scrollDOM.scrollTop && (view.inputState.lastScrollTop || view.inputState.lastScrollLeft)) {
|
|
3935
|
+
view.scrollDOM.scrollTop = view.inputState.lastScrollTop;
|
|
3936
|
+
view.scrollDOM.scrollLeft = view.inputState.lastScrollLeft;
|
|
3937
|
+
}
|
|
3938
|
+
updateForFocusChange(view);
|
|
3939
|
+
};
|
|
3902
3940
|
handlers.blur = view => {
|
|
3903
3941
|
view.observer.clearSelectionRange();
|
|
3904
3942
|
updateForFocusChange(view);
|
|
@@ -5269,6 +5307,7 @@ const baseTheme$1 = buildTheme("." + baseThemeID, {
|
|
|
5269
5307
|
"&light .cm-specialChar": { color: "red" },
|
|
5270
5308
|
"&dark .cm-specialChar": { color: "#f78" },
|
|
5271
5309
|
".cm-gutters": {
|
|
5310
|
+
flexShrink: 0,
|
|
5272
5311
|
display: "flex",
|
|
5273
5312
|
height: "100%",
|
|
5274
5313
|
boxSizing: "border-box",
|
|
@@ -5525,15 +5564,28 @@ class DOMObserver {
|
|
|
5525
5564
|
this.flush(false);
|
|
5526
5565
|
}
|
|
5527
5566
|
readSelectionRange() {
|
|
5528
|
-
let {
|
|
5567
|
+
let { view } = this;
|
|
5529
5568
|
// The Selection object is broken in shadow roots in Safari. See
|
|
5530
5569
|
// https://github.com/codemirror/dev/issues/414
|
|
5531
|
-
let range = browser.safari && root.nodeType == 11 && deepActiveElement() == this.
|
|
5532
|
-
safariSelectionRangeHack(this.view) || getSelection(root);
|
|
5570
|
+
let range = browser.safari && view.root.nodeType == 11 && deepActiveElement() == this.dom &&
|
|
5571
|
+
safariSelectionRangeHack(this.view) || getSelection(view.root);
|
|
5533
5572
|
if (!range || this.selectionRange.eq(range))
|
|
5534
5573
|
return false;
|
|
5574
|
+
let local = hasSelection(this.dom, range);
|
|
5575
|
+
// Detect the situation where the browser has, on focus, moved the
|
|
5576
|
+
// selection to the start of the content element. Reset it to the
|
|
5577
|
+
// position from the editor state.
|
|
5578
|
+
if (local && !this.selectionChanged && this.selectionRange.focusNode &&
|
|
5579
|
+
view.inputState.lastFocusTime > Date.now() - 200 &&
|
|
5580
|
+
view.inputState.lastTouchTime < Date.now() - 300 &&
|
|
5581
|
+
atElementStart(this.dom, range)) {
|
|
5582
|
+
view.docView.updateSelection();
|
|
5583
|
+
return false;
|
|
5584
|
+
}
|
|
5535
5585
|
this.selectionRange.setRange(range);
|
|
5536
|
-
|
|
5586
|
+
if (local)
|
|
5587
|
+
this.selectionChanged = true;
|
|
5588
|
+
return true;
|
|
5537
5589
|
}
|
|
5538
5590
|
setSelectionRange(anchor, head) {
|
|
5539
5591
|
this.selectionRange.set(anchor.node, anchor.offset, head.node, head.offset);
|
|
@@ -5620,7 +5672,7 @@ class DOMObserver {
|
|
|
5620
5672
|
this.delayedAndroidKey = null;
|
|
5621
5673
|
this.delayedFlush = -1;
|
|
5622
5674
|
if (!this.flush())
|
|
5623
|
-
dispatchKey(this.
|
|
5675
|
+
dispatchKey(this.dom, key.key, key.keyCode);
|
|
5624
5676
|
});
|
|
5625
5677
|
// Since backspace beforeinput is sometimes signalled spuriously,
|
|
5626
5678
|
// Enter always takes precedence.
|
|
@@ -5674,6 +5726,7 @@ class DOMObserver {
|
|
|
5674
5726
|
let newSel = this.selectionChanged && hasSelection(this.dom, this.selectionRange);
|
|
5675
5727
|
if (from < 0 && !newSel)
|
|
5676
5728
|
return;
|
|
5729
|
+
this.view.inputState.lastFocusTime = 0;
|
|
5677
5730
|
this.selectionChanged = false;
|
|
5678
5731
|
let startState = this.view.state;
|
|
5679
5732
|
let handled = this.onChange(from, to, typeOver);
|
|
@@ -7495,7 +7548,7 @@ class MatchDecorator {
|
|
|
7495
7548
|
}
|
|
7496
7549
|
|
|
7497
7550
|
const UnicodeRegexpSupport = /x/.unicode != null ? "gu" : "g";
|
|
7498
|
-
const Specials = new RegExp("[\u0000-\u0008\u000a-\u001f\u007f-\u009f\u00ad\u061c\u200b\u200e\u200f\u2028\u2029\u202d\u202e\ufeff\ufff9-\ufffc]", UnicodeRegexpSupport);
|
|
7551
|
+
const Specials = new RegExp("[\u0000-\u0008\u000a-\u001f\u007f-\u009f\u00ad\u061c\u200b\u200e\u200f\u2028\u2029\u202d\u202e\u2066\u2067\u2069\ufeff\ufff9-\ufffc]", UnicodeRegexpSupport);
|
|
7499
7552
|
const Names = {
|
|
7500
7553
|
0: "null",
|
|
7501
7554
|
7: "bell",
|
|
@@ -7512,6 +7565,9 @@ const Names = {
|
|
|
7512
7565
|
8232: "line separator",
|
|
7513
7566
|
8237: "left-to-right override",
|
|
7514
7567
|
8238: "right-to-left override",
|
|
7568
|
+
8294: "left-to-right isolate",
|
|
7569
|
+
8295: "right-to-left isolate",
|
|
7570
|
+
8297: "pop directional isolate",
|
|
7515
7571
|
8233: "paragraph separator",
|
|
7516
7572
|
65279: "zero width no-break space",
|
|
7517
7573
|
65532: "object replacement"
|
package/dist/index.js
CHANGED
|
@@ -264,6 +264,31 @@ function clearAttributes(node) {
|
|
|
264
264
|
while (node.attributes.length)
|
|
265
265
|
node.removeAttributeNode(node.attributes[0]);
|
|
266
266
|
}
|
|
267
|
+
function atElementStart(doc, selection) {
|
|
268
|
+
let node = selection.focusNode, offset = selection.focusOffset;
|
|
269
|
+
if (!node || selection.anchorNode != node || selection.anchorOffset != offset)
|
|
270
|
+
return false;
|
|
271
|
+
for (;;) {
|
|
272
|
+
if (offset) {
|
|
273
|
+
if (node.nodeType != 1)
|
|
274
|
+
return false;
|
|
275
|
+
let prev = node.childNodes[offset - 1];
|
|
276
|
+
if (prev.contentEditable == "false")
|
|
277
|
+
offset--;
|
|
278
|
+
else {
|
|
279
|
+
node = prev;
|
|
280
|
+
offset = maxOffset(node);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
else if (node == doc) {
|
|
284
|
+
return true;
|
|
285
|
+
}
|
|
286
|
+
else {
|
|
287
|
+
offset = domIndex(node);
|
|
288
|
+
node = node.parentNode;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
}
|
|
267
292
|
|
|
268
293
|
class DOMPos {
|
|
269
294
|
constructor(node, offset, precise = true) {
|
|
@@ -3283,6 +3308,10 @@ class InputState {
|
|
|
3283
3308
|
constructor(view) {
|
|
3284
3309
|
this.lastKeyCode = 0;
|
|
3285
3310
|
this.lastKeyTime = 0;
|
|
3311
|
+
this.lastTouchTime = 0;
|
|
3312
|
+
this.lastFocusTime = 0;
|
|
3313
|
+
this.lastScrollTop = 0;
|
|
3314
|
+
this.lastScrollLeft = 0;
|
|
3286
3315
|
this.chromeScrollHack = -1;
|
|
3287
3316
|
// On iOS, some keys need to have their default behavior happen
|
|
3288
3317
|
// (after which we retroactively handle them and reset the DOM) to
|
|
@@ -3384,6 +3413,8 @@ class InputState {
|
|
|
3384
3413
|
return false;
|
|
3385
3414
|
}
|
|
3386
3415
|
runScrollHandlers(view, event) {
|
|
3416
|
+
this.lastScrollTop = view.scrollDOM.scrollTop;
|
|
3417
|
+
this.lastScrollLeft = view.scrollDOM.scrollLeft;
|
|
3387
3418
|
for (let set of this.customHandlers) {
|
|
3388
3419
|
let handler = set.handlers.scroll;
|
|
3389
3420
|
if (handler) {
|
|
@@ -3628,9 +3659,8 @@ handlers.keydown = (view, event) => {
|
|
|
3628
3659
|
else if (modifierCodes.indexOf(event.keyCode) < 0)
|
|
3629
3660
|
view.inputState.lastEscPress = 0;
|
|
3630
3661
|
};
|
|
3631
|
-
let lastTouch = 0;
|
|
3632
3662
|
handlers.touchstart = (view, e) => {
|
|
3633
|
-
|
|
3663
|
+
view.inputState.lastTouchTime = Date.now();
|
|
3634
3664
|
view.inputState.setSelectionOrigin("select.pointer");
|
|
3635
3665
|
};
|
|
3636
3666
|
handlers.touchmove = view => {
|
|
@@ -3638,7 +3668,7 @@ handlers.touchmove = view => {
|
|
|
3638
3668
|
};
|
|
3639
3669
|
handlers.mousedown = (view, event) => {
|
|
3640
3670
|
view.observer.flush();
|
|
3641
|
-
if (
|
|
3671
|
+
if (view.inputState.lastTouchTime > Date.now() - 2000 && getClickType(event) == 1)
|
|
3642
3672
|
return; // Ignore touch interaction
|
|
3643
3673
|
let style = null;
|
|
3644
3674
|
for (let makeStyle of view.state.facet(mouseSelectionStyle)) {
|
|
@@ -3892,7 +3922,15 @@ function updateForFocusChange(view) {
|
|
|
3892
3922
|
view.update([]);
|
|
3893
3923
|
}, 10);
|
|
3894
3924
|
}
|
|
3895
|
-
handlers.focus =
|
|
3925
|
+
handlers.focus = view => {
|
|
3926
|
+
view.inputState.lastFocusTime = Date.now();
|
|
3927
|
+
// When focusing reset the scroll position, move it back to where it was
|
|
3928
|
+
if (!view.scrollDOM.scrollTop && (view.inputState.lastScrollTop || view.inputState.lastScrollLeft)) {
|
|
3929
|
+
view.scrollDOM.scrollTop = view.inputState.lastScrollTop;
|
|
3930
|
+
view.scrollDOM.scrollLeft = view.inputState.lastScrollLeft;
|
|
3931
|
+
}
|
|
3932
|
+
updateForFocusChange(view);
|
|
3933
|
+
};
|
|
3896
3934
|
handlers.blur = view => {
|
|
3897
3935
|
view.observer.clearSelectionRange();
|
|
3898
3936
|
updateForFocusChange(view);
|
|
@@ -5262,6 +5300,7 @@ const baseTheme$1 = /*@__PURE__*/buildTheme("." + baseThemeID, {
|
|
|
5262
5300
|
"&light .cm-specialChar": { color: "red" },
|
|
5263
5301
|
"&dark .cm-specialChar": { color: "#f78" },
|
|
5264
5302
|
".cm-gutters": {
|
|
5303
|
+
flexShrink: 0,
|
|
5265
5304
|
display: "flex",
|
|
5266
5305
|
height: "100%",
|
|
5267
5306
|
boxSizing: "border-box",
|
|
@@ -5518,15 +5557,28 @@ class DOMObserver {
|
|
|
5518
5557
|
this.flush(false);
|
|
5519
5558
|
}
|
|
5520
5559
|
readSelectionRange() {
|
|
5521
|
-
let {
|
|
5560
|
+
let { view } = this;
|
|
5522
5561
|
// The Selection object is broken in shadow roots in Safari. See
|
|
5523
5562
|
// https://github.com/codemirror/dev/issues/414
|
|
5524
|
-
let range = browser.safari && root.nodeType == 11 && deepActiveElement() == this.
|
|
5525
|
-
safariSelectionRangeHack(this.view) || getSelection(root);
|
|
5563
|
+
let range = browser.safari && view.root.nodeType == 11 && deepActiveElement() == this.dom &&
|
|
5564
|
+
safariSelectionRangeHack(this.view) || getSelection(view.root);
|
|
5526
5565
|
if (!range || this.selectionRange.eq(range))
|
|
5527
5566
|
return false;
|
|
5567
|
+
let local = hasSelection(this.dom, range);
|
|
5568
|
+
// Detect the situation where the browser has, on focus, moved the
|
|
5569
|
+
// selection to the start of the content element. Reset it to the
|
|
5570
|
+
// position from the editor state.
|
|
5571
|
+
if (local && !this.selectionChanged && this.selectionRange.focusNode &&
|
|
5572
|
+
view.inputState.lastFocusTime > Date.now() - 200 &&
|
|
5573
|
+
view.inputState.lastTouchTime < Date.now() - 300 &&
|
|
5574
|
+
atElementStart(this.dom, range)) {
|
|
5575
|
+
view.docView.updateSelection();
|
|
5576
|
+
return false;
|
|
5577
|
+
}
|
|
5528
5578
|
this.selectionRange.setRange(range);
|
|
5529
|
-
|
|
5579
|
+
if (local)
|
|
5580
|
+
this.selectionChanged = true;
|
|
5581
|
+
return true;
|
|
5530
5582
|
}
|
|
5531
5583
|
setSelectionRange(anchor, head) {
|
|
5532
5584
|
this.selectionRange.set(anchor.node, anchor.offset, head.node, head.offset);
|
|
@@ -5613,7 +5665,7 @@ class DOMObserver {
|
|
|
5613
5665
|
this.delayedAndroidKey = null;
|
|
5614
5666
|
this.delayedFlush = -1;
|
|
5615
5667
|
if (!this.flush())
|
|
5616
|
-
dispatchKey(this.
|
|
5668
|
+
dispatchKey(this.dom, key.key, key.keyCode);
|
|
5617
5669
|
});
|
|
5618
5670
|
// Since backspace beforeinput is sometimes signalled spuriously,
|
|
5619
5671
|
// Enter always takes precedence.
|
|
@@ -5667,6 +5719,7 @@ class DOMObserver {
|
|
|
5667
5719
|
let newSel = this.selectionChanged && hasSelection(this.dom, this.selectionRange);
|
|
5668
5720
|
if (from < 0 && !newSel)
|
|
5669
5721
|
return;
|
|
5722
|
+
this.view.inputState.lastFocusTime = 0;
|
|
5670
5723
|
this.selectionChanged = false;
|
|
5671
5724
|
let startState = this.view.state;
|
|
5672
5725
|
let handled = this.onChange(from, to, typeOver);
|
|
@@ -7488,7 +7541,7 @@ class MatchDecorator {
|
|
|
7488
7541
|
}
|
|
7489
7542
|
|
|
7490
7543
|
const UnicodeRegexpSupport = /x/.unicode != null ? "gu" : "g";
|
|
7491
|
-
const Specials = /*@__PURE__*/new RegExp("[\u0000-\u0008\u000a-\u001f\u007f-\u009f\u00ad\u061c\u200b\u200e\u200f\u2028\u2029\u202d\u202e\ufeff\ufff9-\ufffc]", UnicodeRegexpSupport);
|
|
7544
|
+
const Specials = /*@__PURE__*/new RegExp("[\u0000-\u0008\u000a-\u001f\u007f-\u009f\u00ad\u061c\u200b\u200e\u200f\u2028\u2029\u202d\u202e\u2066\u2067\u2069\ufeff\ufff9-\ufffc]", UnicodeRegexpSupport);
|
|
7492
7545
|
const Names = {
|
|
7493
7546
|
0: "null",
|
|
7494
7547
|
7: "bell",
|
|
@@ -7505,6 +7558,9 @@ const Names = {
|
|
|
7505
7558
|
8232: "line separator",
|
|
7506
7559
|
8237: "left-to-right override",
|
|
7507
7560
|
8238: "right-to-left override",
|
|
7561
|
+
8294: "left-to-right isolate",
|
|
7562
|
+
8295: "right-to-left isolate",
|
|
7563
|
+
8297: "pop directional isolate",
|
|
7508
7564
|
8233: "paragraph separator",
|
|
7509
7565
|
65279: "zero width no-break space",
|
|
7510
7566
|
65532: "object replacement"
|