@codemirror/view 6.36.1 → 6.36.3
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 +20 -0
- package/README.md +19 -0
- package/dist/index.cjs +34 -16
- package/dist/index.d.cts +4 -3
- package/dist/index.d.ts +4 -3
- package/dist/index.js +34 -16
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,23 @@
|
|
|
1
|
+
## 6.36.3 (2025-02-18)
|
|
2
|
+
|
|
3
|
+
### Bug fixes
|
|
4
|
+
|
|
5
|
+
Make sure event handlers registered with `domEventHandlers` are not called during view updates, to avoid triggering nested update errors.
|
|
6
|
+
|
|
7
|
+
Don't include the window scrollbars in the space available for displaying tooltips.
|
|
8
|
+
|
|
9
|
+
Work around an issue with Chrome's `EditContext` that shows up when using autocompletion while composing with Samsung's virtual Android keyboard.
|
|
10
|
+
|
|
11
|
+
## 6.36.2 (2025-01-09)
|
|
12
|
+
|
|
13
|
+
### Bug fixes
|
|
14
|
+
|
|
15
|
+
Fix an issue where some kinds of relayouts could put the editor in a state where it believed it wasn't in window, preventing relayout, though it in fact was.
|
|
16
|
+
|
|
17
|
+
Make sure macOS double-space-to-period conversions are properly suppressed.
|
|
18
|
+
|
|
19
|
+
Fix an issue where native selection changes, such as mobile spacebar-drag, weren't being picked up in edit context mode.
|
|
20
|
+
|
|
1
21
|
## 6.36.1 (2024-12-19)
|
|
2
22
|
|
|
3
23
|
### Bug fixes
|
package/README.md
CHANGED
|
@@ -16,3 +16,22 @@ We aim to be an inclusive, welcoming community. To make that explicit,
|
|
|
16
16
|
we have a [code of
|
|
17
17
|
conduct](http://contributor-covenant.org/version/1/1/0/) that applies
|
|
18
18
|
to communication around the project.
|
|
19
|
+
|
|
20
|
+
## Usage
|
|
21
|
+
|
|
22
|
+
```javascript
|
|
23
|
+
import {EditorView} from "@codemirror/view"
|
|
24
|
+
import {basicSetup} from "codemirror"
|
|
25
|
+
|
|
26
|
+
const view = new EditorView({
|
|
27
|
+
parent: document.querySelector("#some-node"),
|
|
28
|
+
doc: "Content text",
|
|
29
|
+
extensions: [basicSetup /* ... */]
|
|
30
|
+
})
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Add additional extensions, such as a [language
|
|
34
|
+
mode](https://codemirror.net/#languages), to configure the editor.
|
|
35
|
+
Call
|
|
36
|
+
[`view.dispatch`](https://codemirror.net/docs/ref/#view.EditorView.dispatch)
|
|
37
|
+
to update the editor's state.
|
package/dist/index.cjs
CHANGED
|
@@ -3953,6 +3953,14 @@ function applyDOMChange(view, domChange) {
|
|
|
3953
3953
|
// Heuristic to notice typing over a selected character
|
|
3954
3954
|
change = { from: sel.from, to: sel.to, insert: view.state.doc.slice(sel.from, sel.to) };
|
|
3955
3955
|
}
|
|
3956
|
+
else if ((browser.mac || browser.android) && change && change.from == change.to && change.from == sel.head - 1 &&
|
|
3957
|
+
/^\. ?$/.test(change.insert.toString()) && view.contentDOM.getAttribute("autocorrect") == "off") {
|
|
3958
|
+
// Detect insert-period-on-double-space Mac and Android behavior,
|
|
3959
|
+
// and transform it into a regular space insert.
|
|
3960
|
+
if (newSel && change.insert.length == 2)
|
|
3961
|
+
newSel = state.EditorSelection.single(newSel.main.anchor - 1, newSel.main.head - 1);
|
|
3962
|
+
change = { from: change.from, to: change.to, insert: state.Text.of([change.insert.toString().replace(".", " ")]) };
|
|
3963
|
+
}
|
|
3956
3964
|
else if (change && change.from >= sel.from && change.to <= sel.to &&
|
|
3957
3965
|
(change.from != sel.from || change.to != sel.to) &&
|
|
3958
3966
|
(sel.to - sel.from) - (change.to - change.from) <= 4) {
|
|
@@ -3964,14 +3972,6 @@ function applyDOMChange(view, domChange) {
|
|
|
3964
3972
|
insert: view.state.doc.slice(sel.from, change.from).append(change.insert).append(view.state.doc.slice(change.to, sel.to))
|
|
3965
3973
|
};
|
|
3966
3974
|
}
|
|
3967
|
-
else if ((browser.mac || browser.android) && change && change.from == change.to && change.from == sel.head - 1 &&
|
|
3968
|
-
/^\. ?$/.test(change.insert.toString()) && view.contentDOM.getAttribute("autocorrect") == "off") {
|
|
3969
|
-
// Detect insert-period-on-double-space Mac and Android behavior,
|
|
3970
|
-
// and transform it into a regular space insert.
|
|
3971
|
-
if (newSel && change.insert.length == 2)
|
|
3972
|
-
newSel = state.EditorSelection.single(newSel.main.anchor - 1, newSel.main.head - 1);
|
|
3973
|
-
change = { from: sel.from, to: sel.to, insert: state.Text.of([" "]) };
|
|
3974
|
-
}
|
|
3975
3975
|
else if (browser.chrome && change && change.from == change.to && change.from == sel.head &&
|
|
3976
3976
|
change.insert.toString() == "\n " && view.lineWrapping) {
|
|
3977
3977
|
// In Chrome, if you insert a space at the start of a wrapped
|
|
@@ -4209,7 +4209,10 @@ class InputState {
|
|
|
4209
4209
|
return;
|
|
4210
4210
|
if (event.type == "keydown" && this.keydown(event))
|
|
4211
4211
|
return;
|
|
4212
|
-
this.
|
|
4212
|
+
if (this.view.updateState != 0 /* UpdateState.Idle */)
|
|
4213
|
+
Promise.resolve().then(() => this.runHandlers(event.type, event));
|
|
4214
|
+
else
|
|
4215
|
+
this.runHandlers(event.type, event);
|
|
4213
4216
|
}
|
|
4214
4217
|
runHandlers(type, event) {
|
|
4215
4218
|
let handlers = this.handlers[type];
|
|
@@ -5774,6 +5777,11 @@ function visiblePixelRange(dom, paddingTop) {
|
|
|
5774
5777
|
return { left: left - rect.left, right: Math.max(left, right) - rect.left,
|
|
5775
5778
|
top: top - (rect.top + paddingTop), bottom: Math.max(top, bottom) - (rect.top + paddingTop) };
|
|
5776
5779
|
}
|
|
5780
|
+
function inWindow(elt) {
|
|
5781
|
+
let rect = elt.getBoundingClientRect(), win = elt.ownerDocument.defaultView || window;
|
|
5782
|
+
return rect.left < win.innerWidth && rect.right > 0 &&
|
|
5783
|
+
rect.top < win.innerHeight && rect.bottom > 0;
|
|
5784
|
+
}
|
|
5777
5785
|
function fullPixelRange(dom, paddingTop) {
|
|
5778
5786
|
let rect = dom.getBoundingClientRect();
|
|
5779
5787
|
return { left: 0, right: rect.right - rect.left,
|
|
@@ -5997,7 +6005,7 @@ class ViewState {
|
|
|
5997
6005
|
if (inView)
|
|
5998
6006
|
measureContent = true;
|
|
5999
6007
|
}
|
|
6000
|
-
if (!this.inView && !this.scrollTarget)
|
|
6008
|
+
if (!this.inView && !this.scrollTarget && !inWindow(view.dom))
|
|
6001
6009
|
return 0;
|
|
6002
6010
|
let contentWidth = domRect.width;
|
|
6003
6011
|
if (this.contentDOMWidth != contentWidth || this.editorHeight != view.scrollDOM.clientHeight) {
|
|
@@ -7187,7 +7195,7 @@ class EditContextManager {
|
|
|
7187
7195
|
selectionEnd: this.toContextPos(view.state.selection.main.head)
|
|
7188
7196
|
});
|
|
7189
7197
|
this.handlers.textupdate = e => {
|
|
7190
|
-
let
|
|
7198
|
+
let main = view.state.selection.main, { anchor, head } = main;
|
|
7191
7199
|
let from = this.toEditorPos(e.updateRangeStart), to = this.toEditorPos(e.updateRangeEnd);
|
|
7192
7200
|
if (view.inputState.composing >= 0 && !this.composing)
|
|
7193
7201
|
this.composing = { contextBase: e.updateRangeStart, editorBase: from, drifted: false };
|
|
@@ -7199,8 +7207,15 @@ class EditContextManager {
|
|
|
7199
7207
|
else if (change.to == this.to && anchor > this.to)
|
|
7200
7208
|
change.to = anchor;
|
|
7201
7209
|
// Edit contexts sometimes fire empty changes
|
|
7202
|
-
if (change.from == change.to && !change.insert.length)
|
|
7210
|
+
if (change.from == change.to && !change.insert.length) {
|
|
7211
|
+
let newSel = state.EditorSelection.single(this.toEditorPos(e.selectionStart), this.toEditorPos(e.selectionEnd));
|
|
7212
|
+
if (!newSel.main.eq(main))
|
|
7213
|
+
view.dispatch({ selection: newSel, userEvent: "select" });
|
|
7203
7214
|
return;
|
|
7215
|
+
}
|
|
7216
|
+
if ((browser.mac || browser.android) && change.from == head - 1 &&
|
|
7217
|
+
/^\. ?$/.test(e.text) && view.contentDOM.getAttribute("autocorrect") == "off")
|
|
7218
|
+
change = { from, to, insert: state.Text.of([e.text.replace(".", " ")]) };
|
|
7204
7219
|
this.pendingContextChange = change;
|
|
7205
7220
|
if (!view.state.readOnly) {
|
|
7206
7221
|
let newLen = this.to - this.from + (change.to - change.from + change.insert.length);
|
|
@@ -7301,8 +7316,11 @@ class EditContextManager {
|
|
|
7301
7316
|
return !abort;
|
|
7302
7317
|
}
|
|
7303
7318
|
update(update) {
|
|
7304
|
-
let reverted = this.pendingContextChange;
|
|
7305
|
-
if (this.composing &&
|
|
7319
|
+
let reverted = this.pendingContextChange, startSel = update.startState.selection.main;
|
|
7320
|
+
if (this.composing &&
|
|
7321
|
+
(this.composing.drifted ||
|
|
7322
|
+
(!update.changes.touchesRange(startSel.from, startSel.to) &&
|
|
7323
|
+
update.transactions.some(tr => !tr.isUserEvent("input.type") && tr.changes.touchesRange(this.from, this.to))))) {
|
|
7306
7324
|
this.composing.drifted = true;
|
|
7307
7325
|
this.composing.editorBase = update.changes.mapPos(this.composing.editorBase);
|
|
7308
7326
|
}
|
|
@@ -9788,8 +9806,8 @@ function tooltips(config = {}) {
|
|
|
9788
9806
|
return tooltipConfig.of(config);
|
|
9789
9807
|
}
|
|
9790
9808
|
function windowSpace(view) {
|
|
9791
|
-
let
|
|
9792
|
-
return { top: 0, left: 0, bottom:
|
|
9809
|
+
let docElt = view.dom.ownerDocument.documentElement;
|
|
9810
|
+
return { top: 0, left: 0, bottom: docElt.clientHeight, right: docElt.clientWidth };
|
|
9793
9811
|
}
|
|
9794
9812
|
const tooltipConfig = state.Facet.define({
|
|
9795
9813
|
combine: values => {
|
package/dist/index.d.cts
CHANGED
|
@@ -1839,9 +1839,10 @@ declare function tooltips(config?: {
|
|
|
1839
1839
|
/**
|
|
1840
1840
|
By default, when figuring out whether there is room for a
|
|
1841
1841
|
tooltip at a given position, the extension considers the entire
|
|
1842
|
-
space between 0,0 and
|
|
1843
|
-
|
|
1844
|
-
|
|
1842
|
+
space between 0,0 and
|
|
1843
|
+
`documentElement.clientWidth`/`clientHeight` to be available for
|
|
1844
|
+
showing tooltips. You can provide a function here that returns
|
|
1845
|
+
an alternative rectangle.
|
|
1845
1846
|
*/
|
|
1846
1847
|
tooltipSpace?: (view: EditorView) => Rect;
|
|
1847
1848
|
}): Extension;
|
package/dist/index.d.ts
CHANGED
|
@@ -1839,9 +1839,10 @@ declare function tooltips(config?: {
|
|
|
1839
1839
|
/**
|
|
1840
1840
|
By default, when figuring out whether there is room for a
|
|
1841
1841
|
tooltip at a given position, the extension considers the entire
|
|
1842
|
-
space between 0,0 and
|
|
1843
|
-
|
|
1844
|
-
|
|
1842
|
+
space between 0,0 and
|
|
1843
|
+
`documentElement.clientWidth`/`clientHeight` to be available for
|
|
1844
|
+
showing tooltips. You can provide a function here that returns
|
|
1845
|
+
an alternative rectangle.
|
|
1845
1846
|
*/
|
|
1846
1847
|
tooltipSpace?: (view: EditorView) => Rect;
|
|
1847
1848
|
}): Extension;
|
package/dist/index.js
CHANGED
|
@@ -3949,6 +3949,14 @@ function applyDOMChange(view, domChange) {
|
|
|
3949
3949
|
// Heuristic to notice typing over a selected character
|
|
3950
3950
|
change = { from: sel.from, to: sel.to, insert: view.state.doc.slice(sel.from, sel.to) };
|
|
3951
3951
|
}
|
|
3952
|
+
else if ((browser.mac || browser.android) && change && change.from == change.to && change.from == sel.head - 1 &&
|
|
3953
|
+
/^\. ?$/.test(change.insert.toString()) && view.contentDOM.getAttribute("autocorrect") == "off") {
|
|
3954
|
+
// Detect insert-period-on-double-space Mac and Android behavior,
|
|
3955
|
+
// and transform it into a regular space insert.
|
|
3956
|
+
if (newSel && change.insert.length == 2)
|
|
3957
|
+
newSel = EditorSelection.single(newSel.main.anchor - 1, newSel.main.head - 1);
|
|
3958
|
+
change = { from: change.from, to: change.to, insert: Text.of([change.insert.toString().replace(".", " ")]) };
|
|
3959
|
+
}
|
|
3952
3960
|
else if (change && change.from >= sel.from && change.to <= sel.to &&
|
|
3953
3961
|
(change.from != sel.from || change.to != sel.to) &&
|
|
3954
3962
|
(sel.to - sel.from) - (change.to - change.from) <= 4) {
|
|
@@ -3960,14 +3968,6 @@ function applyDOMChange(view, domChange) {
|
|
|
3960
3968
|
insert: view.state.doc.slice(sel.from, change.from).append(change.insert).append(view.state.doc.slice(change.to, sel.to))
|
|
3961
3969
|
};
|
|
3962
3970
|
}
|
|
3963
|
-
else if ((browser.mac || browser.android) && change && change.from == change.to && change.from == sel.head - 1 &&
|
|
3964
|
-
/^\. ?$/.test(change.insert.toString()) && view.contentDOM.getAttribute("autocorrect") == "off") {
|
|
3965
|
-
// Detect insert-period-on-double-space Mac and Android behavior,
|
|
3966
|
-
// and transform it into a regular space insert.
|
|
3967
|
-
if (newSel && change.insert.length == 2)
|
|
3968
|
-
newSel = EditorSelection.single(newSel.main.anchor - 1, newSel.main.head - 1);
|
|
3969
|
-
change = { from: sel.from, to: sel.to, insert: Text.of([" "]) };
|
|
3970
|
-
}
|
|
3971
3971
|
else if (browser.chrome && change && change.from == change.to && change.from == sel.head &&
|
|
3972
3972
|
change.insert.toString() == "\n " && view.lineWrapping) {
|
|
3973
3973
|
// In Chrome, if you insert a space at the start of a wrapped
|
|
@@ -4205,7 +4205,10 @@ class InputState {
|
|
|
4205
4205
|
return;
|
|
4206
4206
|
if (event.type == "keydown" && this.keydown(event))
|
|
4207
4207
|
return;
|
|
4208
|
-
this.
|
|
4208
|
+
if (this.view.updateState != 0 /* UpdateState.Idle */)
|
|
4209
|
+
Promise.resolve().then(() => this.runHandlers(event.type, event));
|
|
4210
|
+
else
|
|
4211
|
+
this.runHandlers(event.type, event);
|
|
4209
4212
|
}
|
|
4210
4213
|
runHandlers(type, event) {
|
|
4211
4214
|
let handlers = this.handlers[type];
|
|
@@ -5769,6 +5772,11 @@ function visiblePixelRange(dom, paddingTop) {
|
|
|
5769
5772
|
return { left: left - rect.left, right: Math.max(left, right) - rect.left,
|
|
5770
5773
|
top: top - (rect.top + paddingTop), bottom: Math.max(top, bottom) - (rect.top + paddingTop) };
|
|
5771
5774
|
}
|
|
5775
|
+
function inWindow(elt) {
|
|
5776
|
+
let rect = elt.getBoundingClientRect(), win = elt.ownerDocument.defaultView || window;
|
|
5777
|
+
return rect.left < win.innerWidth && rect.right > 0 &&
|
|
5778
|
+
rect.top < win.innerHeight && rect.bottom > 0;
|
|
5779
|
+
}
|
|
5772
5780
|
function fullPixelRange(dom, paddingTop) {
|
|
5773
5781
|
let rect = dom.getBoundingClientRect();
|
|
5774
5782
|
return { left: 0, right: rect.right - rect.left,
|
|
@@ -5992,7 +6000,7 @@ class ViewState {
|
|
|
5992
6000
|
if (inView)
|
|
5993
6001
|
measureContent = true;
|
|
5994
6002
|
}
|
|
5995
|
-
if (!this.inView && !this.scrollTarget)
|
|
6003
|
+
if (!this.inView && !this.scrollTarget && !inWindow(view.dom))
|
|
5996
6004
|
return 0;
|
|
5997
6005
|
let contentWidth = domRect.width;
|
|
5998
6006
|
if (this.contentDOMWidth != contentWidth || this.editorHeight != view.scrollDOM.clientHeight) {
|
|
@@ -7182,7 +7190,7 @@ class EditContextManager {
|
|
|
7182
7190
|
selectionEnd: this.toContextPos(view.state.selection.main.head)
|
|
7183
7191
|
});
|
|
7184
7192
|
this.handlers.textupdate = e => {
|
|
7185
|
-
let
|
|
7193
|
+
let main = view.state.selection.main, { anchor, head } = main;
|
|
7186
7194
|
let from = this.toEditorPos(e.updateRangeStart), to = this.toEditorPos(e.updateRangeEnd);
|
|
7187
7195
|
if (view.inputState.composing >= 0 && !this.composing)
|
|
7188
7196
|
this.composing = { contextBase: e.updateRangeStart, editorBase: from, drifted: false };
|
|
@@ -7194,8 +7202,15 @@ class EditContextManager {
|
|
|
7194
7202
|
else if (change.to == this.to && anchor > this.to)
|
|
7195
7203
|
change.to = anchor;
|
|
7196
7204
|
// Edit contexts sometimes fire empty changes
|
|
7197
|
-
if (change.from == change.to && !change.insert.length)
|
|
7205
|
+
if (change.from == change.to && !change.insert.length) {
|
|
7206
|
+
let newSel = EditorSelection.single(this.toEditorPos(e.selectionStart), this.toEditorPos(e.selectionEnd));
|
|
7207
|
+
if (!newSel.main.eq(main))
|
|
7208
|
+
view.dispatch({ selection: newSel, userEvent: "select" });
|
|
7198
7209
|
return;
|
|
7210
|
+
}
|
|
7211
|
+
if ((browser.mac || browser.android) && change.from == head - 1 &&
|
|
7212
|
+
/^\. ?$/.test(e.text) && view.contentDOM.getAttribute("autocorrect") == "off")
|
|
7213
|
+
change = { from, to, insert: Text.of([e.text.replace(".", " ")]) };
|
|
7199
7214
|
this.pendingContextChange = change;
|
|
7200
7215
|
if (!view.state.readOnly) {
|
|
7201
7216
|
let newLen = this.to - this.from + (change.to - change.from + change.insert.length);
|
|
@@ -7296,8 +7311,11 @@ class EditContextManager {
|
|
|
7296
7311
|
return !abort;
|
|
7297
7312
|
}
|
|
7298
7313
|
update(update) {
|
|
7299
|
-
let reverted = this.pendingContextChange;
|
|
7300
|
-
if (this.composing &&
|
|
7314
|
+
let reverted = this.pendingContextChange, startSel = update.startState.selection.main;
|
|
7315
|
+
if (this.composing &&
|
|
7316
|
+
(this.composing.drifted ||
|
|
7317
|
+
(!update.changes.touchesRange(startSel.from, startSel.to) &&
|
|
7318
|
+
update.transactions.some(tr => !tr.isUserEvent("input.type") && tr.changes.touchesRange(this.from, this.to))))) {
|
|
7301
7319
|
this.composing.drifted = true;
|
|
7302
7320
|
this.composing.editorBase = update.changes.mapPos(this.composing.editorBase);
|
|
7303
7321
|
}
|
|
@@ -9783,8 +9801,8 @@ function tooltips(config = {}) {
|
|
|
9783
9801
|
return tooltipConfig.of(config);
|
|
9784
9802
|
}
|
|
9785
9803
|
function windowSpace(view) {
|
|
9786
|
-
let
|
|
9787
|
-
return { top: 0, left: 0, bottom:
|
|
9804
|
+
let docElt = view.dom.ownerDocument.documentElement;
|
|
9805
|
+
return { top: 0, left: 0, bottom: docElt.clientHeight, right: docElt.clientWidth };
|
|
9788
9806
|
}
|
|
9789
9807
|
const tooltipConfig = /*@__PURE__*/Facet.define({
|
|
9790
9808
|
combine: values => {
|