@codemirror/view 6.38.5 → 6.38.7
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 +38 -12
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +38 -12
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,19 @@
|
|
|
1
|
+
## 6.38.7 (2025-11-14)
|
|
2
|
+
|
|
3
|
+
### Bug fixes
|
|
4
|
+
|
|
5
|
+
Make detection of transformed tooltip parent elements (forcing absolute positioning) more robust on current browsers.
|
|
6
|
+
|
|
7
|
+
Avoid an issue where on Chrome and Safari, typing over a cross-line selection can replace widgets on the line after the selection with their plain text content.
|
|
8
|
+
|
|
9
|
+
Fix a bug that broke insertion of composed input at multiple cursors when the IME keeps the selection at the start of the composed text.
|
|
10
|
+
|
|
11
|
+
## 6.38.6 (2025-10-13)
|
|
12
|
+
|
|
13
|
+
### Bug fixes
|
|
14
|
+
|
|
15
|
+
Work around a regression in Safari 26 that causes fragments of old selections to remain visible.
|
|
16
|
+
|
|
1
17
|
## 6.38.5 (2025-10-07)
|
|
2
18
|
|
|
3
19
|
### Bug fixes
|
package/dist/index.cjs
CHANGED
|
@@ -3324,6 +3324,13 @@ class DocView extends ContentView {
|
|
|
3324
3324
|
let { offsetWidth, offsetHeight } = this.view.scrollDOM;
|
|
3325
3325
|
scrollRectIntoView(this.view.scrollDOM, targetRect, range.head < range.anchor ? -1 : 1, target.x, target.y, Math.max(Math.min(target.xMargin, offsetWidth), -offsetWidth), Math.max(Math.min(target.yMargin, offsetHeight), -offsetHeight), this.view.textDirection == exports.Direction.LTR);
|
|
3326
3326
|
}
|
|
3327
|
+
lineHasWidget(pos) {
|
|
3328
|
+
let { i } = this.childCursor().findPos(pos);
|
|
3329
|
+
if (i == this.children.length)
|
|
3330
|
+
return false;
|
|
3331
|
+
let scan = (child) => child instanceof WidgetView || child.children.some(scan);
|
|
3332
|
+
return scan(this.children[i]);
|
|
3333
|
+
}
|
|
3327
3334
|
}
|
|
3328
3335
|
function betweenUneditable(pos) {
|
|
3329
3336
|
return pos.node.nodeType == 1 && pos.node.firstChild &&
|
|
@@ -4069,6 +4076,18 @@ function applyDOMChange(view, domChange) {
|
|
|
4069
4076
|
insert: view.state.doc.slice(sel.from, change.from).append(change.insert).append(view.state.doc.slice(change.to, sel.to))
|
|
4070
4077
|
};
|
|
4071
4078
|
}
|
|
4079
|
+
else if (view.state.doc.lineAt(sel.from).to < sel.to && view.docView.lineHasWidget(sel.to) &&
|
|
4080
|
+
view.inputState.insertingTextAt > Date.now() - 50) {
|
|
4081
|
+
// For a cross-line insertion, Chrome and Safari will crudely take
|
|
4082
|
+
// the text of the line after the selection, flattening any
|
|
4083
|
+
// widgets, and move it into the joined line. This tries to detect
|
|
4084
|
+
// such a situation, and replaces the change with a selection
|
|
4085
|
+
// replace of the text provided by the beforeinput event.
|
|
4086
|
+
change = {
|
|
4087
|
+
from: sel.from, to: sel.to,
|
|
4088
|
+
insert: view.state.toText(view.inputState.insertingText)
|
|
4089
|
+
};
|
|
4090
|
+
}
|
|
4072
4091
|
else if (browser.chrome && change && change.from == change.to && change.from == sel.head &&
|
|
4073
4092
|
change.insert.toString() == "\n " && view.lineWrapping) {
|
|
4074
4093
|
// In Chrome, if you insert a space at the start of a wrapped
|
|
@@ -4155,7 +4174,7 @@ function applyDefaultInsert(view, change, newSel) {
|
|
|
4155
4174
|
let mainSel = newSel && newSel.main.to <= changes.newLength ? newSel.main : undefined;
|
|
4156
4175
|
// Try to apply a composition change to all cursors
|
|
4157
4176
|
if (startState.selection.ranges.length > 1 && view.inputState.composing >= 0 &&
|
|
4158
|
-
change.to <= sel.to && change.to >= sel.to - 10) {
|
|
4177
|
+
change.to <= sel.to + 10 && change.to >= sel.to - 10) {
|
|
4159
4178
|
let replaced = view.state.sliceDoc(change.from, change.to);
|
|
4160
4179
|
let compositionRange, composition = newSel && findCompositionNode(view, newSel.main.head);
|
|
4161
4180
|
if (composition) {
|
|
@@ -4302,6 +4321,9 @@ class InputState {
|
|
|
4302
4321
|
// Used to categorize changes as part of a composition, even when
|
|
4303
4322
|
// the mutation events fire shortly after the compositionend event
|
|
4304
4323
|
this.compositionPendingChange = false;
|
|
4324
|
+
// Set by beforeinput, used in DOM change reader
|
|
4325
|
+
this.insertingText = "";
|
|
4326
|
+
this.insertingTextAt = 0;
|
|
4305
4327
|
this.mouseSelection = null;
|
|
4306
4328
|
// When a drag from the editor is active, this points at the range
|
|
4307
4329
|
// being dragged.
|
|
@@ -5056,6 +5078,10 @@ observers.contextmenu = view => {
|
|
|
5056
5078
|
};
|
|
5057
5079
|
handlers.beforeinput = (view, event) => {
|
|
5058
5080
|
var _a, _b;
|
|
5081
|
+
if (event.inputType == "insertText" || event.inputType == "insertCompositionText") {
|
|
5082
|
+
view.inputState.insertingText = event.data;
|
|
5083
|
+
view.inputState.insertingTextAt = Date.now();
|
|
5084
|
+
}
|
|
5059
5085
|
// In EditContext mode, we must handle insertReplacementText events
|
|
5060
5086
|
// directly, to make spell checking corrections work
|
|
5061
5087
|
if (event.inputType == "insertReplacementText" && view.observer.editContext) {
|
|
@@ -8562,7 +8588,7 @@ Facet that works much like
|
|
|
8562
8588
|
[`decorations`](https://codemirror.net/6/docs/ref/#view.EditorView^decorations), but puts its
|
|
8563
8589
|
inputs at the very bottom of the precedence stack, meaning mark
|
|
8564
8590
|
decorations provided here will only be split by other, partially
|
|
8565
|
-
overlapping
|
|
8591
|
+
overlapping `outerDecorations` ranges, and wrap around all
|
|
8566
8592
|
regular decorations. Use this for mark elements that should, as
|
|
8567
8593
|
much as possible, remain in one piece.
|
|
8568
8594
|
*/
|
|
@@ -9130,7 +9156,7 @@ class LayerView {
|
|
|
9130
9156
|
old = next;
|
|
9131
9157
|
}
|
|
9132
9158
|
this.drawn = markers;
|
|
9133
|
-
if (browser.
|
|
9159
|
+
if (browser.safari && browser.safari_version >= 26) // Issue #1600, 1627
|
|
9134
9160
|
this.dom.style.display = this.dom.firstChild ? "" : "none";
|
|
9135
9161
|
}
|
|
9136
9162
|
}
|
|
@@ -10060,18 +10086,18 @@ const tooltipPlugin = ViewPlugin.fromClass(class {
|
|
|
10060
10086
|
let scaleX = 1, scaleY = 1, makeAbsolute = false;
|
|
10061
10087
|
if (this.position == "fixed" && this.manager.tooltipViews.length) {
|
|
10062
10088
|
let { dom } = this.manager.tooltipViews[0];
|
|
10063
|
-
if (browser.
|
|
10064
|
-
//
|
|
10065
|
-
//
|
|
10066
|
-
//
|
|
10067
|
-
makeAbsolute = dom.offsetParent != this.container.ownerDocument.body;
|
|
10068
|
-
}
|
|
10069
|
-
else if (dom.style.top == Outside && dom.style.left == "0px") {
|
|
10070
|
-
// On other browsers, we have to awkwardly try and use other
|
|
10071
|
-
// information to detect a transform.
|
|
10089
|
+
if (browser.safari) {
|
|
10090
|
+
// Safari always sets offsetParent to null, even if a fixed
|
|
10091
|
+
// element is positioned relative to a transformed parent. So
|
|
10092
|
+
// we use this kludge to try and detect this.
|
|
10072
10093
|
let rect = dom.getBoundingClientRect();
|
|
10073
10094
|
makeAbsolute = Math.abs(rect.top + 10000) > 1 || Math.abs(rect.left) > 1;
|
|
10074
10095
|
}
|
|
10096
|
+
else {
|
|
10097
|
+
// More conforming browsers will set offsetParent to the
|
|
10098
|
+
// transformed element.
|
|
10099
|
+
makeAbsolute = !!dom.offsetParent && dom.offsetParent != this.container.ownerDocument.body;
|
|
10100
|
+
}
|
|
10075
10101
|
}
|
|
10076
10102
|
if (makeAbsolute || this.position == "absolute") {
|
|
10077
10103
|
if (this.parent) {
|
package/dist/index.d.cts
CHANGED
|
@@ -1265,7 +1265,7 @@ declare class EditorView {
|
|
|
1265
1265
|
[`decorations`](https://codemirror.net/6/docs/ref/#view.EditorView^decorations), but puts its
|
|
1266
1266
|
inputs at the very bottom of the precedence stack, meaning mark
|
|
1267
1267
|
decorations provided here will only be split by other, partially
|
|
1268
|
-
overlapping
|
|
1268
|
+
overlapping `outerDecorations` ranges, and wrap around all
|
|
1269
1269
|
regular decorations. Use this for mark elements that should, as
|
|
1270
1270
|
much as possible, remain in one piece.
|
|
1271
1271
|
*/
|
|
@@ -2091,8 +2091,8 @@ declare const showPanel: Facet<PanelConstructor | null, readonly (PanelConstruct
|
|
|
2091
2091
|
type DialogConfig = {
|
|
2092
2092
|
/**
|
|
2093
2093
|
A function to render the content of the dialog. The result
|
|
2094
|
-
should contain at least one `<form>` element. Submit handlers
|
|
2095
|
-
handler for the Escape key will be added to the form.
|
|
2094
|
+
should contain at least one `<form>` element. Submit handlers
|
|
2095
|
+
and a handler for the Escape key will be added to the form.
|
|
2096
2096
|
|
|
2097
2097
|
If this is not given, the `label`, `input`, and `submitLabel`
|
|
2098
2098
|
fields will be used to create a simple form for you.
|
package/dist/index.d.ts
CHANGED
|
@@ -1265,7 +1265,7 @@ declare class EditorView {
|
|
|
1265
1265
|
[`decorations`](https://codemirror.net/6/docs/ref/#view.EditorView^decorations), but puts its
|
|
1266
1266
|
inputs at the very bottom of the precedence stack, meaning mark
|
|
1267
1267
|
decorations provided here will only be split by other, partially
|
|
1268
|
-
overlapping
|
|
1268
|
+
overlapping `outerDecorations` ranges, and wrap around all
|
|
1269
1269
|
regular decorations. Use this for mark elements that should, as
|
|
1270
1270
|
much as possible, remain in one piece.
|
|
1271
1271
|
*/
|
|
@@ -2091,8 +2091,8 @@ declare const showPanel: Facet<PanelConstructor | null, readonly (PanelConstruct
|
|
|
2091
2091
|
type DialogConfig = {
|
|
2092
2092
|
/**
|
|
2093
2093
|
A function to render the content of the dialog. The result
|
|
2094
|
-
should contain at least one `<form>` element. Submit handlers
|
|
2095
|
-
handler for the Escape key will be added to the form.
|
|
2094
|
+
should contain at least one `<form>` element. Submit handlers
|
|
2095
|
+
and a handler for the Escape key will be added to the form.
|
|
2096
2096
|
|
|
2097
2097
|
If this is not given, the `label`, `input`, and `submitLabel`
|
|
2098
2098
|
fields will be used to create a simple form for you.
|
package/dist/index.js
CHANGED
|
@@ -3320,6 +3320,13 @@ class DocView extends ContentView {
|
|
|
3320
3320
|
let { offsetWidth, offsetHeight } = this.view.scrollDOM;
|
|
3321
3321
|
scrollRectIntoView(this.view.scrollDOM, targetRect, range.head < range.anchor ? -1 : 1, target.x, target.y, Math.max(Math.min(target.xMargin, offsetWidth), -offsetWidth), Math.max(Math.min(target.yMargin, offsetHeight), -offsetHeight), this.view.textDirection == Direction.LTR);
|
|
3322
3322
|
}
|
|
3323
|
+
lineHasWidget(pos) {
|
|
3324
|
+
let { i } = this.childCursor().findPos(pos);
|
|
3325
|
+
if (i == this.children.length)
|
|
3326
|
+
return false;
|
|
3327
|
+
let scan = (child) => child instanceof WidgetView || child.children.some(scan);
|
|
3328
|
+
return scan(this.children[i]);
|
|
3329
|
+
}
|
|
3323
3330
|
}
|
|
3324
3331
|
function betweenUneditable(pos) {
|
|
3325
3332
|
return pos.node.nodeType == 1 && pos.node.firstChild &&
|
|
@@ -4065,6 +4072,18 @@ function applyDOMChange(view, domChange) {
|
|
|
4065
4072
|
insert: view.state.doc.slice(sel.from, change.from).append(change.insert).append(view.state.doc.slice(change.to, sel.to))
|
|
4066
4073
|
};
|
|
4067
4074
|
}
|
|
4075
|
+
else if (view.state.doc.lineAt(sel.from).to < sel.to && view.docView.lineHasWidget(sel.to) &&
|
|
4076
|
+
view.inputState.insertingTextAt > Date.now() - 50) {
|
|
4077
|
+
// For a cross-line insertion, Chrome and Safari will crudely take
|
|
4078
|
+
// the text of the line after the selection, flattening any
|
|
4079
|
+
// widgets, and move it into the joined line. This tries to detect
|
|
4080
|
+
// such a situation, and replaces the change with a selection
|
|
4081
|
+
// replace of the text provided by the beforeinput event.
|
|
4082
|
+
change = {
|
|
4083
|
+
from: sel.from, to: sel.to,
|
|
4084
|
+
insert: view.state.toText(view.inputState.insertingText)
|
|
4085
|
+
};
|
|
4086
|
+
}
|
|
4068
4087
|
else if (browser.chrome && change && change.from == change.to && change.from == sel.head &&
|
|
4069
4088
|
change.insert.toString() == "\n " && view.lineWrapping) {
|
|
4070
4089
|
// In Chrome, if you insert a space at the start of a wrapped
|
|
@@ -4151,7 +4170,7 @@ function applyDefaultInsert(view, change, newSel) {
|
|
|
4151
4170
|
let mainSel = newSel && newSel.main.to <= changes.newLength ? newSel.main : undefined;
|
|
4152
4171
|
// Try to apply a composition change to all cursors
|
|
4153
4172
|
if (startState.selection.ranges.length > 1 && view.inputState.composing >= 0 &&
|
|
4154
|
-
change.to <= sel.to && change.to >= sel.to - 10) {
|
|
4173
|
+
change.to <= sel.to + 10 && change.to >= sel.to - 10) {
|
|
4155
4174
|
let replaced = view.state.sliceDoc(change.from, change.to);
|
|
4156
4175
|
let compositionRange, composition = newSel && findCompositionNode(view, newSel.main.head);
|
|
4157
4176
|
if (composition) {
|
|
@@ -4298,6 +4317,9 @@ class InputState {
|
|
|
4298
4317
|
// Used to categorize changes as part of a composition, even when
|
|
4299
4318
|
// the mutation events fire shortly after the compositionend event
|
|
4300
4319
|
this.compositionPendingChange = false;
|
|
4320
|
+
// Set by beforeinput, used in DOM change reader
|
|
4321
|
+
this.insertingText = "";
|
|
4322
|
+
this.insertingTextAt = 0;
|
|
4301
4323
|
this.mouseSelection = null;
|
|
4302
4324
|
// When a drag from the editor is active, this points at the range
|
|
4303
4325
|
// being dragged.
|
|
@@ -5052,6 +5074,10 @@ observers.contextmenu = view => {
|
|
|
5052
5074
|
};
|
|
5053
5075
|
handlers.beforeinput = (view, event) => {
|
|
5054
5076
|
var _a, _b;
|
|
5077
|
+
if (event.inputType == "insertText" || event.inputType == "insertCompositionText") {
|
|
5078
|
+
view.inputState.insertingText = event.data;
|
|
5079
|
+
view.inputState.insertingTextAt = Date.now();
|
|
5080
|
+
}
|
|
5055
5081
|
// In EditContext mode, we must handle insertReplacementText events
|
|
5056
5082
|
// directly, to make spell checking corrections work
|
|
5057
5083
|
if (event.inputType == "insertReplacementText" && view.observer.editContext) {
|
|
@@ -8557,7 +8583,7 @@ Facet that works much like
|
|
|
8557
8583
|
[`decorations`](https://codemirror.net/6/docs/ref/#view.EditorView^decorations), but puts its
|
|
8558
8584
|
inputs at the very bottom of the precedence stack, meaning mark
|
|
8559
8585
|
decorations provided here will only be split by other, partially
|
|
8560
|
-
overlapping
|
|
8586
|
+
overlapping `outerDecorations` ranges, and wrap around all
|
|
8561
8587
|
regular decorations. Use this for mark elements that should, as
|
|
8562
8588
|
much as possible, remain in one piece.
|
|
8563
8589
|
*/
|
|
@@ -9125,7 +9151,7 @@ class LayerView {
|
|
|
9125
9151
|
old = next;
|
|
9126
9152
|
}
|
|
9127
9153
|
this.drawn = markers;
|
|
9128
|
-
if (browser.
|
|
9154
|
+
if (browser.safari && browser.safari_version >= 26) // Issue #1600, 1627
|
|
9129
9155
|
this.dom.style.display = this.dom.firstChild ? "" : "none";
|
|
9130
9156
|
}
|
|
9131
9157
|
}
|
|
@@ -10055,18 +10081,18 @@ const tooltipPlugin = /*@__PURE__*/ViewPlugin.fromClass(class {
|
|
|
10055
10081
|
let scaleX = 1, scaleY = 1, makeAbsolute = false;
|
|
10056
10082
|
if (this.position == "fixed" && this.manager.tooltipViews.length) {
|
|
10057
10083
|
let { dom } = this.manager.tooltipViews[0];
|
|
10058
|
-
if (browser.
|
|
10059
|
-
//
|
|
10060
|
-
//
|
|
10061
|
-
//
|
|
10062
|
-
makeAbsolute = dom.offsetParent != this.container.ownerDocument.body;
|
|
10063
|
-
}
|
|
10064
|
-
else if (dom.style.top == Outside && dom.style.left == "0px") {
|
|
10065
|
-
// On other browsers, we have to awkwardly try and use other
|
|
10066
|
-
// information to detect a transform.
|
|
10084
|
+
if (browser.safari) {
|
|
10085
|
+
// Safari always sets offsetParent to null, even if a fixed
|
|
10086
|
+
// element is positioned relative to a transformed parent. So
|
|
10087
|
+
// we use this kludge to try and detect this.
|
|
10067
10088
|
let rect = dom.getBoundingClientRect();
|
|
10068
10089
|
makeAbsolute = Math.abs(rect.top + 10000) > 1 || Math.abs(rect.left) > 1;
|
|
10069
10090
|
}
|
|
10091
|
+
else {
|
|
10092
|
+
// More conforming browsers will set offsetParent to the
|
|
10093
|
+
// transformed element.
|
|
10094
|
+
makeAbsolute = !!dom.offsetParent && dom.offsetParent != this.container.ownerDocument.body;
|
|
10095
|
+
}
|
|
10070
10096
|
}
|
|
10071
10097
|
if (makeAbsolute || this.position == "absolute") {
|
|
10072
10098
|
if (this.parent) {
|