@codemirror/view 6.21.4 → 6.22.0
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 +79 -17
- package/dist/index.d.cts +35 -2
- package/dist/index.d.ts +35 -2
- package/dist/index.js +80 -18
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,19 @@
|
|
|
1
|
+
## 6.22.0 (2023-11-03)
|
|
2
|
+
|
|
3
|
+
### Bug fixes
|
|
4
|
+
|
|
5
|
+
Exceptions raised by update listeners are now routed to the configured exception sink, if any.
|
|
6
|
+
|
|
7
|
+
Fix an issue where passing large scroll margins to `scrollIntoView` would cause the measure loop to fail to terminate.
|
|
8
|
+
|
|
9
|
+
Widgets that are draggable (and allow drag events through in their `ignoreEvent` implementation) can now use the editor's built-in drag/drop behavior.
|
|
10
|
+
|
|
11
|
+
### New features
|
|
12
|
+
|
|
13
|
+
The new `scrollTo` option to `EditorView` allows an initial scroll position to be provided.
|
|
14
|
+
|
|
15
|
+
The new `EditorView.scrollSnapshot` method returns an effect that can be used to reset to a previous scroll position.
|
|
16
|
+
|
|
1
17
|
## 6.21.4 (2023-10-24)
|
|
2
18
|
|
|
3
19
|
### Bug fixes
|
package/dist/index.cjs
CHANGED
|
@@ -1788,15 +1788,28 @@ const nativeSelectionHidden = state.Facet.define({
|
|
|
1788
1788
|
combine: values => values.some(x => x)
|
|
1789
1789
|
});
|
|
1790
1790
|
class ScrollTarget {
|
|
1791
|
-
constructor(range, y = "nearest", x = "nearest", yMargin = 5, xMargin = 5
|
|
1791
|
+
constructor(range, y = "nearest", x = "nearest", yMargin = 5, xMargin = 5,
|
|
1792
|
+
// This data structure is abused to also store precise scroll
|
|
1793
|
+
// snapshots, instead of a `scrollIntoView` request. When this
|
|
1794
|
+
// flag is `true`, `range` points at a position in the reference
|
|
1795
|
+
// line, `yMargin` holds the difference between the top of that
|
|
1796
|
+
// line and the top of the editor, and `xMargin` holds the
|
|
1797
|
+
// editor's `scrollLeft`.
|
|
1798
|
+
isSnapshot = false) {
|
|
1792
1799
|
this.range = range;
|
|
1793
1800
|
this.y = y;
|
|
1794
1801
|
this.x = x;
|
|
1795
1802
|
this.yMargin = yMargin;
|
|
1796
1803
|
this.xMargin = xMargin;
|
|
1804
|
+
this.isSnapshot = isSnapshot;
|
|
1797
1805
|
}
|
|
1798
1806
|
map(changes) {
|
|
1799
|
-
return changes.empty ? this :
|
|
1807
|
+
return changes.empty ? this :
|
|
1808
|
+
new ScrollTarget(this.range.map(changes), this.y, this.x, this.yMargin, this.xMargin, this.isSnapshot);
|
|
1809
|
+
}
|
|
1810
|
+
clip(state$1) {
|
|
1811
|
+
return this.range.to <= state$1.doc.length ? this :
|
|
1812
|
+
new ScrollTarget(state.EditorSelection.cursor(state$1.doc.length), this.y, this.x, this.yMargin, this.xMargin, this.isSnapshot);
|
|
1800
1813
|
}
|
|
1801
1814
|
}
|
|
1802
1815
|
const scrollIntoView = state.StateEffect.define({ map: (t, ch) => t.map(ch) });
|
|
@@ -3090,6 +3103,12 @@ class DocView extends ContentView {
|
|
|
3090
3103
|
];
|
|
3091
3104
|
}
|
|
3092
3105
|
scrollIntoView(target) {
|
|
3106
|
+
if (target.isSnapshot) {
|
|
3107
|
+
let ref = this.view.viewState.lineBlockAt(target.range.head);
|
|
3108
|
+
this.view.scrollDOM.scrollTop = ref.top - target.yMargin;
|
|
3109
|
+
this.view.scrollDOM.scrollLeft = target.xMargin;
|
|
3110
|
+
return;
|
|
3111
|
+
}
|
|
3093
3112
|
let { range } = target;
|
|
3094
3113
|
let rect = this.coordsAt(range.head, range.empty ? range.assoc : range.head > range.anchor ? -1 : 1), other;
|
|
3095
3114
|
if (!rect)
|
|
@@ -3102,7 +3121,8 @@ class DocView extends ContentView {
|
|
|
3102
3121
|
left: rect.left - margins.left, top: rect.top - margins.top,
|
|
3103
3122
|
right: rect.right + margins.right, bottom: rect.bottom + margins.bottom
|
|
3104
3123
|
};
|
|
3105
|
-
|
|
3124
|
+
let { offsetWidth, offsetHeight } = this.view.scrollDOM;
|
|
3125
|
+
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);
|
|
3106
3126
|
}
|
|
3107
3127
|
}
|
|
3108
3128
|
function betweenUneditable(pos) {
|
|
@@ -3639,6 +3659,9 @@ class InputState {
|
|
|
3639
3659
|
// the mutation events fire shortly after the compositionend event
|
|
3640
3660
|
this.compositionPendingChange = false;
|
|
3641
3661
|
this.mouseSelection = null;
|
|
3662
|
+
// When a drag from the editor is active, this points at the range
|
|
3663
|
+
// being dragged.
|
|
3664
|
+
this.draggedContent = null;
|
|
3642
3665
|
this.handleEvent = this.handleEvent.bind(this);
|
|
3643
3666
|
this.notifiedFocused = view.hasFocus;
|
|
3644
3667
|
// On Safari adding an input event handler somehow prevents an
|
|
@@ -3755,6 +3778,8 @@ class InputState {
|
|
|
3755
3778
|
update(update) {
|
|
3756
3779
|
if (this.mouseSelection)
|
|
3757
3780
|
this.mouseSelection.update(update);
|
|
3781
|
+
if (this.draggedContent && update.docChanged)
|
|
3782
|
+
this.draggedContent = this.draggedContent.map(update.changes);
|
|
3758
3783
|
if (update.transactions.length)
|
|
3759
3784
|
this.lastKeyCode = this.lastSelectionTime = 0;
|
|
3760
3785
|
}
|
|
@@ -3872,7 +3897,7 @@ class MouseSelection {
|
|
|
3872
3897
|
let doc = this.view.contentDOM.ownerDocument;
|
|
3873
3898
|
doc.removeEventListener("mousemove", this.move);
|
|
3874
3899
|
doc.removeEventListener("mouseup", this.up);
|
|
3875
|
-
this.view.inputState.mouseSelection = null;
|
|
3900
|
+
this.view.inputState.mouseSelection = this.view.inputState.draggedContent = null;
|
|
3876
3901
|
}
|
|
3877
3902
|
setScrollSpeed(sx, sy) {
|
|
3878
3903
|
this.scrollSpeed = { x: sx, y: sy };
|
|
@@ -3930,8 +3955,6 @@ class MouseSelection {
|
|
|
3930
3955
|
this.mustSelect = false;
|
|
3931
3956
|
}
|
|
3932
3957
|
update(update) {
|
|
3933
|
-
if (update.docChanged && this.dragging)
|
|
3934
|
-
this.dragging = this.dragging.map(update.changes);
|
|
3935
3958
|
if (this.style.update(update))
|
|
3936
3959
|
setTimeout(() => this.select(this.lastEvent), 20);
|
|
3937
3960
|
}
|
|
@@ -4159,23 +4182,36 @@ function removeRangeAround(sel, pos) {
|
|
|
4159
4182
|
return null;
|
|
4160
4183
|
}
|
|
4161
4184
|
handlers.dragstart = (view, event) => {
|
|
4162
|
-
let { selection: { main } } = view.state;
|
|
4163
|
-
|
|
4164
|
-
|
|
4165
|
-
|
|
4185
|
+
let { selection: { main: range } } = view.state;
|
|
4186
|
+
if (event.target.draggable) {
|
|
4187
|
+
let cView = view.docView.nearest(event.target);
|
|
4188
|
+
if (cView && cView.isWidget) {
|
|
4189
|
+
let from = cView.posAtStart, to = from + cView.length;
|
|
4190
|
+
if (from >= range.to || to <= range.from)
|
|
4191
|
+
range = state.EditorSelection.range(from, to);
|
|
4192
|
+
}
|
|
4193
|
+
}
|
|
4194
|
+
let { inputState } = view;
|
|
4195
|
+
if (inputState.mouseSelection)
|
|
4196
|
+
inputState.mouseSelection.dragging = true;
|
|
4197
|
+
inputState.draggedContent = range;
|
|
4166
4198
|
if (event.dataTransfer) {
|
|
4167
|
-
event.dataTransfer.setData("Text", view.state.sliceDoc(
|
|
4199
|
+
event.dataTransfer.setData("Text", view.state.sliceDoc(range.from, range.to));
|
|
4168
4200
|
event.dataTransfer.effectAllowed = "copyMove";
|
|
4169
4201
|
}
|
|
4170
4202
|
return false;
|
|
4171
4203
|
};
|
|
4204
|
+
handlers.dragend = view => {
|
|
4205
|
+
view.inputState.draggedContent = null;
|
|
4206
|
+
return false;
|
|
4207
|
+
};
|
|
4172
4208
|
function dropText(view, event, text, direct) {
|
|
4173
4209
|
if (!text)
|
|
4174
4210
|
return;
|
|
4175
4211
|
let dropPos = view.posAtCoords({ x: event.clientX, y: event.clientY }, false);
|
|
4176
|
-
let {
|
|
4177
|
-
let del = direct &&
|
|
4178
|
-
{ from:
|
|
4212
|
+
let { draggedContent } = view.inputState;
|
|
4213
|
+
let del = direct && draggedContent && dragMovesSelection(view, event)
|
|
4214
|
+
? { from: draggedContent.from, to: draggedContent.to } : null;
|
|
4179
4215
|
let ins = { from: dropPos, insert: text };
|
|
4180
4216
|
let changes = view.state.changes(del ? [del, ins] : ins);
|
|
4181
4217
|
view.focus();
|
|
@@ -4184,6 +4220,7 @@ function dropText(view, event, text, direct) {
|
|
|
4184
4220
|
selection: { anchor: changes.mapPos(dropPos, -1), head: changes.mapPos(dropPos, 1) },
|
|
4185
4221
|
userEvent: del ? "move.drop" : "input.drop"
|
|
4186
4222
|
});
|
|
4223
|
+
view.inputState.draggedContent = null;
|
|
4187
4224
|
}
|
|
4188
4225
|
handlers.drop = (view, event) => {
|
|
4189
4226
|
if (!event.dataTransfer)
|
|
@@ -6904,6 +6941,8 @@ class EditorView {
|
|
|
6904
6941
|
this.dispatch = this.dispatch.bind(this);
|
|
6905
6942
|
this._root = (config.root || getRoot(config.parent) || document);
|
|
6906
6943
|
this.viewState = new ViewState(config.state || state.EditorState.create(config));
|
|
6944
|
+
if (config.scrollTo && config.scrollTo.is(scrollIntoView))
|
|
6945
|
+
this.viewState.scrollTarget = config.scrollTo.value.clip(this.viewState.state);
|
|
6907
6946
|
this.plugins = this.state.facet(viewPlugin).map(spec => new PluginInstance(spec));
|
|
6908
6947
|
for (let plugin of this.plugins)
|
|
6909
6948
|
plugin.update(this);
|
|
@@ -6991,7 +7030,7 @@ class EditorView {
|
|
|
6991
7030
|
}
|
|
6992
7031
|
for (let e of tr.effects)
|
|
6993
7032
|
if (e.is(scrollIntoView))
|
|
6994
|
-
scrollTarget = e.value;
|
|
7033
|
+
scrollTarget = e.value.clip(this.state);
|
|
6995
7034
|
}
|
|
6996
7035
|
this.viewState.update(update, scrollTarget);
|
|
6997
7036
|
this.bidiCache = CachedOrder.update(this.bidiCache, update.changes);
|
|
@@ -7014,8 +7053,14 @@ class EditorView {
|
|
|
7014
7053
|
if (redrawn || attrsChanged || scrollTarget || this.viewState.mustEnforceCursorAssoc || this.viewState.mustMeasureContent)
|
|
7015
7054
|
this.requestMeasure();
|
|
7016
7055
|
if (!update.empty)
|
|
7017
|
-
for (let listener of this.state.facet(updateListener))
|
|
7018
|
-
|
|
7056
|
+
for (let listener of this.state.facet(updateListener)) {
|
|
7057
|
+
try {
|
|
7058
|
+
listener(update);
|
|
7059
|
+
}
|
|
7060
|
+
catch (e) {
|
|
7061
|
+
logException(this.state, e, "update listener");
|
|
7062
|
+
}
|
|
7063
|
+
}
|
|
7019
7064
|
if (dispatchFocus || domChange)
|
|
7020
7065
|
Promise.resolve().then(() => {
|
|
7021
7066
|
if (dispatchFocus && this.state == dispatchFocus.startState)
|
|
@@ -7597,6 +7642,23 @@ class EditorView {
|
|
|
7597
7642
|
return scrollIntoView.of(new ScrollTarget(typeof pos == "number" ? state.EditorSelection.cursor(pos) : pos, options.y, options.x, options.yMargin, options.xMargin));
|
|
7598
7643
|
}
|
|
7599
7644
|
/**
|
|
7645
|
+
Return an effect that resets the editor to its current (at the
|
|
7646
|
+
time this method was called) scroll position. Note that this
|
|
7647
|
+
only affects the editor's own scrollable element, not parents.
|
|
7648
|
+
See also
|
|
7649
|
+
[`EditorViewConfig.scrollTo`](https://codemirror.net/6/docs/ref/#view.EditorViewConfig.scrollTo).
|
|
7650
|
+
|
|
7651
|
+
The effect should be used with a document identical to the one
|
|
7652
|
+
it was created for. Failing to do so is not an error, but may
|
|
7653
|
+
not scroll to the expected position. You can
|
|
7654
|
+
[map](https://codemirror.net/6/docs/ref/#state.StateEffect.map) the effect to account for changes.
|
|
7655
|
+
*/
|
|
7656
|
+
scrollSnapshot() {
|
|
7657
|
+
let { scrollTop, scrollLeft } = this.scrollDOM;
|
|
7658
|
+
let ref = this.viewState.scrollAnchorAt(scrollTop);
|
|
7659
|
+
return scrollIntoView.of(new ScrollTarget(state.EditorSelection.cursor(ref.from), "start", "start", ref.top - scrollTop, scrollLeft, true));
|
|
7660
|
+
}
|
|
7661
|
+
/**
|
|
7600
7662
|
Returns an extension that can be used to add DOM event handlers.
|
|
7601
7663
|
The value should be an object mapping event names to handler
|
|
7602
7664
|
functions. For any given event, such functions are ordered by
|
package/dist/index.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as _codemirror_state from '@codemirror/state';
|
|
2
|
-
import { RangeSet, RangeValue, Range, EditorState, Extension, Transaction, ChangeSet, EditorSelection, EditorStateConfig,
|
|
2
|
+
import { RangeSet, RangeValue, Range, EditorState, Extension, Transaction, ChangeSet, SelectionRange, ChangeDesc, EditorSelection, EditorStateConfig, StateEffect, TransactionSpec, Line, Facet } from '@codemirror/state';
|
|
3
3
|
import { StyleModule, StyleSpec } from 'style-mod';
|
|
4
4
|
|
|
5
5
|
/**
|
|
@@ -361,6 +361,17 @@ apply to the editor, and if it can, perform it as a side effect
|
|
|
361
361
|
transaction) and return `true`.
|
|
362
362
|
*/
|
|
363
363
|
type Command = (target: EditorView) => boolean;
|
|
364
|
+
declare class ScrollTarget {
|
|
365
|
+
readonly range: SelectionRange;
|
|
366
|
+
readonly y: ScrollStrategy;
|
|
367
|
+
readonly x: ScrollStrategy;
|
|
368
|
+
readonly yMargin: number;
|
|
369
|
+
readonly xMargin: number;
|
|
370
|
+
readonly isSnapshot: boolean;
|
|
371
|
+
constructor(range: SelectionRange, y?: ScrollStrategy, x?: ScrollStrategy, yMargin?: number, xMargin?: number, isSnapshot?: boolean);
|
|
372
|
+
map(changes: ChangeDesc): ScrollTarget;
|
|
373
|
+
clip(state: EditorState): ScrollTarget;
|
|
374
|
+
}
|
|
364
375
|
/**
|
|
365
376
|
Log or report an unhandled exception in client code. Should
|
|
366
377
|
probably only be used by extension code that allows client code to
|
|
@@ -633,6 +644,13 @@ interface EditorViewConfig extends EditorStateConfig {
|
|
|
633
644
|
*/
|
|
634
645
|
root?: Document | ShadowRoot;
|
|
635
646
|
/**
|
|
647
|
+
Pass an effect created with
|
|
648
|
+
[`EditorView.scrollIntoView`](https://codemirror.net/6/docs/ref/#view.EditorView^scrollIntoView) or
|
|
649
|
+
[`EditorView.scrollSnapshot`](https://codemirror.net/6/docs/ref/#view.EditorView.scrollSnapshot)
|
|
650
|
+
here to set an initial scroll position.
|
|
651
|
+
*/
|
|
652
|
+
scrollTo?: StateEffect<any>;
|
|
653
|
+
/**
|
|
636
654
|
Override the way transactions are
|
|
637
655
|
[dispatched](https://codemirror.net/6/docs/ref/#view.EditorView.dispatch) for this editor view.
|
|
638
656
|
Your implementation, if provided, should probably call the
|
|
@@ -1032,15 +1050,30 @@ declare class EditorView {
|
|
|
1032
1050
|
/**
|
|
1033
1051
|
Extra vertical distance to add when moving something into
|
|
1034
1052
|
view. Not used with the `"center"` strategy. Defaults to 5.
|
|
1053
|
+
Must be less than the height of the editor.
|
|
1035
1054
|
*/
|
|
1036
1055
|
yMargin?: number;
|
|
1037
1056
|
/**
|
|
1038
1057
|
Extra horizontal distance to add. Not used with the `"center"`
|
|
1039
|
-
strategy. Defaults to 5.
|
|
1058
|
+
strategy. Defaults to 5. Must be less than the width of the
|
|
1059
|
+
editor.
|
|
1040
1060
|
*/
|
|
1041
1061
|
xMargin?: number;
|
|
1042
1062
|
}): StateEffect<unknown>;
|
|
1043
1063
|
/**
|
|
1064
|
+
Return an effect that resets the editor to its current (at the
|
|
1065
|
+
time this method was called) scroll position. Note that this
|
|
1066
|
+
only affects the editor's own scrollable element, not parents.
|
|
1067
|
+
See also
|
|
1068
|
+
[`EditorViewConfig.scrollTo`](https://codemirror.net/6/docs/ref/#view.EditorViewConfig.scrollTo).
|
|
1069
|
+
|
|
1070
|
+
The effect should be used with a document identical to the one
|
|
1071
|
+
it was created for. Failing to do so is not an error, but may
|
|
1072
|
+
not scroll to the expected position. You can
|
|
1073
|
+
[map](https://codemirror.net/6/docs/ref/#state.StateEffect.map) the effect to account for changes.
|
|
1074
|
+
*/
|
|
1075
|
+
scrollSnapshot(): StateEffect<ScrollTarget>;
|
|
1076
|
+
/**
|
|
1044
1077
|
Facet to add a [style
|
|
1045
1078
|
module](https://github.com/marijnh/style-mod#documentation) to
|
|
1046
1079
|
an editor view. The view will ensure that the module is
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as _codemirror_state from '@codemirror/state';
|
|
2
|
-
import { RangeSet, RangeValue, Range, EditorState, Extension, Transaction, ChangeSet, EditorSelection, EditorStateConfig,
|
|
2
|
+
import { RangeSet, RangeValue, Range, EditorState, Extension, Transaction, ChangeSet, SelectionRange, ChangeDesc, EditorSelection, EditorStateConfig, StateEffect, TransactionSpec, Line, Facet } from '@codemirror/state';
|
|
3
3
|
import { StyleModule, StyleSpec } from 'style-mod';
|
|
4
4
|
|
|
5
5
|
/**
|
|
@@ -361,6 +361,17 @@ apply to the editor, and if it can, perform it as a side effect
|
|
|
361
361
|
transaction) and return `true`.
|
|
362
362
|
*/
|
|
363
363
|
type Command = (target: EditorView) => boolean;
|
|
364
|
+
declare class ScrollTarget {
|
|
365
|
+
readonly range: SelectionRange;
|
|
366
|
+
readonly y: ScrollStrategy;
|
|
367
|
+
readonly x: ScrollStrategy;
|
|
368
|
+
readonly yMargin: number;
|
|
369
|
+
readonly xMargin: number;
|
|
370
|
+
readonly isSnapshot: boolean;
|
|
371
|
+
constructor(range: SelectionRange, y?: ScrollStrategy, x?: ScrollStrategy, yMargin?: number, xMargin?: number, isSnapshot?: boolean);
|
|
372
|
+
map(changes: ChangeDesc): ScrollTarget;
|
|
373
|
+
clip(state: EditorState): ScrollTarget;
|
|
374
|
+
}
|
|
364
375
|
/**
|
|
365
376
|
Log or report an unhandled exception in client code. Should
|
|
366
377
|
probably only be used by extension code that allows client code to
|
|
@@ -633,6 +644,13 @@ interface EditorViewConfig extends EditorStateConfig {
|
|
|
633
644
|
*/
|
|
634
645
|
root?: Document | ShadowRoot;
|
|
635
646
|
/**
|
|
647
|
+
Pass an effect created with
|
|
648
|
+
[`EditorView.scrollIntoView`](https://codemirror.net/6/docs/ref/#view.EditorView^scrollIntoView) or
|
|
649
|
+
[`EditorView.scrollSnapshot`](https://codemirror.net/6/docs/ref/#view.EditorView.scrollSnapshot)
|
|
650
|
+
here to set an initial scroll position.
|
|
651
|
+
*/
|
|
652
|
+
scrollTo?: StateEffect<any>;
|
|
653
|
+
/**
|
|
636
654
|
Override the way transactions are
|
|
637
655
|
[dispatched](https://codemirror.net/6/docs/ref/#view.EditorView.dispatch) for this editor view.
|
|
638
656
|
Your implementation, if provided, should probably call the
|
|
@@ -1032,15 +1050,30 @@ declare class EditorView {
|
|
|
1032
1050
|
/**
|
|
1033
1051
|
Extra vertical distance to add when moving something into
|
|
1034
1052
|
view. Not used with the `"center"` strategy. Defaults to 5.
|
|
1053
|
+
Must be less than the height of the editor.
|
|
1035
1054
|
*/
|
|
1036
1055
|
yMargin?: number;
|
|
1037
1056
|
/**
|
|
1038
1057
|
Extra horizontal distance to add. Not used with the `"center"`
|
|
1039
|
-
strategy. Defaults to 5.
|
|
1058
|
+
strategy. Defaults to 5. Must be less than the width of the
|
|
1059
|
+
editor.
|
|
1040
1060
|
*/
|
|
1041
1061
|
xMargin?: number;
|
|
1042
1062
|
}): StateEffect<unknown>;
|
|
1043
1063
|
/**
|
|
1064
|
+
Return an effect that resets the editor to its current (at the
|
|
1065
|
+
time this method was called) scroll position. Note that this
|
|
1066
|
+
only affects the editor's own scrollable element, not parents.
|
|
1067
|
+
See also
|
|
1068
|
+
[`EditorViewConfig.scrollTo`](https://codemirror.net/6/docs/ref/#view.EditorViewConfig.scrollTo).
|
|
1069
|
+
|
|
1070
|
+
The effect should be used with a document identical to the one
|
|
1071
|
+
it was created for. Failing to do so is not an error, but may
|
|
1072
|
+
not scroll to the expected position. You can
|
|
1073
|
+
[map](https://codemirror.net/6/docs/ref/#state.StateEffect.map) the effect to account for changes.
|
|
1074
|
+
*/
|
|
1075
|
+
scrollSnapshot(): StateEffect<ScrollTarget>;
|
|
1076
|
+
/**
|
|
1044
1077
|
Facet to add a [style
|
|
1045
1078
|
module](https://github.com/marijnh/style-mod#documentation) to
|
|
1046
1079
|
an editor view. The view will ensure that the module is
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Text, RangeSet, MapMode, RangeValue, Facet, StateEffect, ChangeSet,
|
|
1
|
+
import { Text, RangeSet, MapMode, RangeValue, Facet, StateEffect, ChangeSet, EditorSelection, findClusterBreak, findColumn, CharCategory, Annotation, EditorState, Transaction, Prec, codePointAt, codePointSize, combineConfig, StateField, RangeSetBuilder, countColumn } from '@codemirror/state';
|
|
2
2
|
import { StyleModule } from 'style-mod';
|
|
3
3
|
import { keyName, base, shift } from 'w3c-keyname';
|
|
4
4
|
|
|
@@ -1785,15 +1785,28 @@ const nativeSelectionHidden = /*@__PURE__*/Facet.define({
|
|
|
1785
1785
|
combine: values => values.some(x => x)
|
|
1786
1786
|
});
|
|
1787
1787
|
class ScrollTarget {
|
|
1788
|
-
constructor(range, y = "nearest", x = "nearest", yMargin = 5, xMargin = 5
|
|
1788
|
+
constructor(range, y = "nearest", x = "nearest", yMargin = 5, xMargin = 5,
|
|
1789
|
+
// This data structure is abused to also store precise scroll
|
|
1790
|
+
// snapshots, instead of a `scrollIntoView` request. When this
|
|
1791
|
+
// flag is `true`, `range` points at a position in the reference
|
|
1792
|
+
// line, `yMargin` holds the difference between the top of that
|
|
1793
|
+
// line and the top of the editor, and `xMargin` holds the
|
|
1794
|
+
// editor's `scrollLeft`.
|
|
1795
|
+
isSnapshot = false) {
|
|
1789
1796
|
this.range = range;
|
|
1790
1797
|
this.y = y;
|
|
1791
1798
|
this.x = x;
|
|
1792
1799
|
this.yMargin = yMargin;
|
|
1793
1800
|
this.xMargin = xMargin;
|
|
1801
|
+
this.isSnapshot = isSnapshot;
|
|
1794
1802
|
}
|
|
1795
1803
|
map(changes) {
|
|
1796
|
-
return changes.empty ? this :
|
|
1804
|
+
return changes.empty ? this :
|
|
1805
|
+
new ScrollTarget(this.range.map(changes), this.y, this.x, this.yMargin, this.xMargin, this.isSnapshot);
|
|
1806
|
+
}
|
|
1807
|
+
clip(state) {
|
|
1808
|
+
return this.range.to <= state.doc.length ? this :
|
|
1809
|
+
new ScrollTarget(EditorSelection.cursor(state.doc.length), this.y, this.x, this.yMargin, this.xMargin, this.isSnapshot);
|
|
1797
1810
|
}
|
|
1798
1811
|
}
|
|
1799
1812
|
const scrollIntoView = /*@__PURE__*/StateEffect.define({ map: (t, ch) => t.map(ch) });
|
|
@@ -3086,6 +3099,12 @@ class DocView extends ContentView {
|
|
|
3086
3099
|
];
|
|
3087
3100
|
}
|
|
3088
3101
|
scrollIntoView(target) {
|
|
3102
|
+
if (target.isSnapshot) {
|
|
3103
|
+
let ref = this.view.viewState.lineBlockAt(target.range.head);
|
|
3104
|
+
this.view.scrollDOM.scrollTop = ref.top - target.yMargin;
|
|
3105
|
+
this.view.scrollDOM.scrollLeft = target.xMargin;
|
|
3106
|
+
return;
|
|
3107
|
+
}
|
|
3089
3108
|
let { range } = target;
|
|
3090
3109
|
let rect = this.coordsAt(range.head, range.empty ? range.assoc : range.head > range.anchor ? -1 : 1), other;
|
|
3091
3110
|
if (!rect)
|
|
@@ -3098,7 +3117,8 @@ class DocView extends ContentView {
|
|
|
3098
3117
|
left: rect.left - margins.left, top: rect.top - margins.top,
|
|
3099
3118
|
right: rect.right + margins.right, bottom: rect.bottom + margins.bottom
|
|
3100
3119
|
};
|
|
3101
|
-
|
|
3120
|
+
let { offsetWidth, offsetHeight } = this.view.scrollDOM;
|
|
3121
|
+
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);
|
|
3102
3122
|
}
|
|
3103
3123
|
}
|
|
3104
3124
|
function betweenUneditable(pos) {
|
|
@@ -3635,6 +3655,9 @@ class InputState {
|
|
|
3635
3655
|
// the mutation events fire shortly after the compositionend event
|
|
3636
3656
|
this.compositionPendingChange = false;
|
|
3637
3657
|
this.mouseSelection = null;
|
|
3658
|
+
// When a drag from the editor is active, this points at the range
|
|
3659
|
+
// being dragged.
|
|
3660
|
+
this.draggedContent = null;
|
|
3638
3661
|
this.handleEvent = this.handleEvent.bind(this);
|
|
3639
3662
|
this.notifiedFocused = view.hasFocus;
|
|
3640
3663
|
// On Safari adding an input event handler somehow prevents an
|
|
@@ -3751,6 +3774,8 @@ class InputState {
|
|
|
3751
3774
|
update(update) {
|
|
3752
3775
|
if (this.mouseSelection)
|
|
3753
3776
|
this.mouseSelection.update(update);
|
|
3777
|
+
if (this.draggedContent && update.docChanged)
|
|
3778
|
+
this.draggedContent = this.draggedContent.map(update.changes);
|
|
3754
3779
|
if (update.transactions.length)
|
|
3755
3780
|
this.lastKeyCode = this.lastSelectionTime = 0;
|
|
3756
3781
|
}
|
|
@@ -3868,7 +3893,7 @@ class MouseSelection {
|
|
|
3868
3893
|
let doc = this.view.contentDOM.ownerDocument;
|
|
3869
3894
|
doc.removeEventListener("mousemove", this.move);
|
|
3870
3895
|
doc.removeEventListener("mouseup", this.up);
|
|
3871
|
-
this.view.inputState.mouseSelection = null;
|
|
3896
|
+
this.view.inputState.mouseSelection = this.view.inputState.draggedContent = null;
|
|
3872
3897
|
}
|
|
3873
3898
|
setScrollSpeed(sx, sy) {
|
|
3874
3899
|
this.scrollSpeed = { x: sx, y: sy };
|
|
@@ -3926,8 +3951,6 @@ class MouseSelection {
|
|
|
3926
3951
|
this.mustSelect = false;
|
|
3927
3952
|
}
|
|
3928
3953
|
update(update) {
|
|
3929
|
-
if (update.docChanged && this.dragging)
|
|
3930
|
-
this.dragging = this.dragging.map(update.changes);
|
|
3931
3954
|
if (this.style.update(update))
|
|
3932
3955
|
setTimeout(() => this.select(this.lastEvent), 20);
|
|
3933
3956
|
}
|
|
@@ -4155,23 +4178,36 @@ function removeRangeAround(sel, pos) {
|
|
|
4155
4178
|
return null;
|
|
4156
4179
|
}
|
|
4157
4180
|
handlers.dragstart = (view, event) => {
|
|
4158
|
-
let { selection: { main } } = view.state;
|
|
4159
|
-
|
|
4160
|
-
|
|
4161
|
-
|
|
4181
|
+
let { selection: { main: range } } = view.state;
|
|
4182
|
+
if (event.target.draggable) {
|
|
4183
|
+
let cView = view.docView.nearest(event.target);
|
|
4184
|
+
if (cView && cView.isWidget) {
|
|
4185
|
+
let from = cView.posAtStart, to = from + cView.length;
|
|
4186
|
+
if (from >= range.to || to <= range.from)
|
|
4187
|
+
range = EditorSelection.range(from, to);
|
|
4188
|
+
}
|
|
4189
|
+
}
|
|
4190
|
+
let { inputState } = view;
|
|
4191
|
+
if (inputState.mouseSelection)
|
|
4192
|
+
inputState.mouseSelection.dragging = true;
|
|
4193
|
+
inputState.draggedContent = range;
|
|
4162
4194
|
if (event.dataTransfer) {
|
|
4163
|
-
event.dataTransfer.setData("Text", view.state.sliceDoc(
|
|
4195
|
+
event.dataTransfer.setData("Text", view.state.sliceDoc(range.from, range.to));
|
|
4164
4196
|
event.dataTransfer.effectAllowed = "copyMove";
|
|
4165
4197
|
}
|
|
4166
4198
|
return false;
|
|
4167
4199
|
};
|
|
4200
|
+
handlers.dragend = view => {
|
|
4201
|
+
view.inputState.draggedContent = null;
|
|
4202
|
+
return false;
|
|
4203
|
+
};
|
|
4168
4204
|
function dropText(view, event, text, direct) {
|
|
4169
4205
|
if (!text)
|
|
4170
4206
|
return;
|
|
4171
4207
|
let dropPos = view.posAtCoords({ x: event.clientX, y: event.clientY }, false);
|
|
4172
|
-
let {
|
|
4173
|
-
let del = direct &&
|
|
4174
|
-
{ from:
|
|
4208
|
+
let { draggedContent } = view.inputState;
|
|
4209
|
+
let del = direct && draggedContent && dragMovesSelection(view, event)
|
|
4210
|
+
? { from: draggedContent.from, to: draggedContent.to } : null;
|
|
4175
4211
|
let ins = { from: dropPos, insert: text };
|
|
4176
4212
|
let changes = view.state.changes(del ? [del, ins] : ins);
|
|
4177
4213
|
view.focus();
|
|
@@ -4180,6 +4216,7 @@ function dropText(view, event, text, direct) {
|
|
|
4180
4216
|
selection: { anchor: changes.mapPos(dropPos, -1), head: changes.mapPos(dropPos, 1) },
|
|
4181
4217
|
userEvent: del ? "move.drop" : "input.drop"
|
|
4182
4218
|
});
|
|
4219
|
+
view.inputState.draggedContent = null;
|
|
4183
4220
|
}
|
|
4184
4221
|
handlers.drop = (view, event) => {
|
|
4185
4222
|
if (!event.dataTransfer)
|
|
@@ -6899,6 +6936,8 @@ class EditorView {
|
|
|
6899
6936
|
this.dispatch = this.dispatch.bind(this);
|
|
6900
6937
|
this._root = (config.root || getRoot(config.parent) || document);
|
|
6901
6938
|
this.viewState = new ViewState(config.state || EditorState.create(config));
|
|
6939
|
+
if (config.scrollTo && config.scrollTo.is(scrollIntoView))
|
|
6940
|
+
this.viewState.scrollTarget = config.scrollTo.value.clip(this.viewState.state);
|
|
6902
6941
|
this.plugins = this.state.facet(viewPlugin).map(spec => new PluginInstance(spec));
|
|
6903
6942
|
for (let plugin of this.plugins)
|
|
6904
6943
|
plugin.update(this);
|
|
@@ -6986,7 +7025,7 @@ class EditorView {
|
|
|
6986
7025
|
}
|
|
6987
7026
|
for (let e of tr.effects)
|
|
6988
7027
|
if (e.is(scrollIntoView))
|
|
6989
|
-
scrollTarget = e.value;
|
|
7028
|
+
scrollTarget = e.value.clip(this.state);
|
|
6990
7029
|
}
|
|
6991
7030
|
this.viewState.update(update, scrollTarget);
|
|
6992
7031
|
this.bidiCache = CachedOrder.update(this.bidiCache, update.changes);
|
|
@@ -7009,8 +7048,14 @@ class EditorView {
|
|
|
7009
7048
|
if (redrawn || attrsChanged || scrollTarget || this.viewState.mustEnforceCursorAssoc || this.viewState.mustMeasureContent)
|
|
7010
7049
|
this.requestMeasure();
|
|
7011
7050
|
if (!update.empty)
|
|
7012
|
-
for (let listener of this.state.facet(updateListener))
|
|
7013
|
-
|
|
7051
|
+
for (let listener of this.state.facet(updateListener)) {
|
|
7052
|
+
try {
|
|
7053
|
+
listener(update);
|
|
7054
|
+
}
|
|
7055
|
+
catch (e) {
|
|
7056
|
+
logException(this.state, e, "update listener");
|
|
7057
|
+
}
|
|
7058
|
+
}
|
|
7014
7059
|
if (dispatchFocus || domChange)
|
|
7015
7060
|
Promise.resolve().then(() => {
|
|
7016
7061
|
if (dispatchFocus && this.state == dispatchFocus.startState)
|
|
@@ -7592,6 +7637,23 @@ class EditorView {
|
|
|
7592
7637
|
return scrollIntoView.of(new ScrollTarget(typeof pos == "number" ? EditorSelection.cursor(pos) : pos, options.y, options.x, options.yMargin, options.xMargin));
|
|
7593
7638
|
}
|
|
7594
7639
|
/**
|
|
7640
|
+
Return an effect that resets the editor to its current (at the
|
|
7641
|
+
time this method was called) scroll position. Note that this
|
|
7642
|
+
only affects the editor's own scrollable element, not parents.
|
|
7643
|
+
See also
|
|
7644
|
+
[`EditorViewConfig.scrollTo`](https://codemirror.net/6/docs/ref/#view.EditorViewConfig.scrollTo).
|
|
7645
|
+
|
|
7646
|
+
The effect should be used with a document identical to the one
|
|
7647
|
+
it was created for. Failing to do so is not an error, but may
|
|
7648
|
+
not scroll to the expected position. You can
|
|
7649
|
+
[map](https://codemirror.net/6/docs/ref/#state.StateEffect.map) the effect to account for changes.
|
|
7650
|
+
*/
|
|
7651
|
+
scrollSnapshot() {
|
|
7652
|
+
let { scrollTop, scrollLeft } = this.scrollDOM;
|
|
7653
|
+
let ref = this.viewState.scrollAnchorAt(scrollTop);
|
|
7654
|
+
return scrollIntoView.of(new ScrollTarget(EditorSelection.cursor(ref.from), "start", "start", ref.top - scrollTop, scrollLeft, true));
|
|
7655
|
+
}
|
|
7656
|
+
/**
|
|
7595
7657
|
Returns an extension that can be used to add DOM event handlers.
|
|
7596
7658
|
The value should be an object mapping event names to handler
|
|
7597
7659
|
functions. For any given event, such functions are ordered by
|