@codemirror/view 6.11.2 → 6.12.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 CHANGED
@@ -1,3 +1,23 @@
1
+ ## 6.12.0 (2023-05-18)
2
+
3
+ ### Bug fixes
4
+
5
+ Remove an accidentally included `console.log`.
6
+
7
+ ### New features
8
+
9
+ `EditorViewConfig.dispatch` is now passed the view object as a second argument.
10
+
11
+ ## 6.11.3 (2023-05-17)
12
+
13
+ ### Bug fixes
14
+
15
+ Make sure pointer selection respects `EditorView.atomicRanges`.
16
+
17
+ Preserve DOM widgets when their decoration type changes but they otherwise stay in the same place.
18
+
19
+ Fix a bug in `drawSelection` that could lead to invisible or incorrect selections for a blank line below a block widget.
20
+
1
21
  ## 6.11.2 (2023-05-13)
2
22
 
3
23
  ### Bug fixes
package/dist/index.cjs CHANGED
@@ -822,6 +822,9 @@ function textCoords(text, pos, side) {
822
822
  }
823
823
  // Also used for collapsed ranges that don't have a placeholder widget!
824
824
  class WidgetView extends ContentView {
825
+ static create(widget, length, side) {
826
+ return new (widget.customView || WidgetView)(widget, length, side);
827
+ }
825
828
  constructor(widget, length, side) {
826
829
  super();
827
830
  this.widget = widget;
@@ -829,9 +832,6 @@ class WidgetView extends ContentView {
829
832
  this.side = side;
830
833
  this.prevWidget = null;
831
834
  }
832
- static create(widget, length, side) {
833
- return new (widget.customView || WidgetView)(widget, length, side);
834
- }
835
835
  split(from) {
836
836
  let result = WidgetView.create(this.widget, this.length - from, this.side);
837
837
  this.length -= from;
@@ -1647,7 +1647,7 @@ class BlockWidgetView extends ContentView {
1647
1647
  }
1648
1648
  domBoundsAround() { return null; }
1649
1649
  become(other) {
1650
- if (other instanceof BlockWidgetView && other.type == this.type &&
1650
+ if (other instanceof BlockWidgetView &&
1651
1651
  other.widget.constructor == this.widget.constructor) {
1652
1652
  if (!other.widget.compare(this.widget))
1653
1653
  this.markDirty(true);
@@ -1655,6 +1655,7 @@ class BlockWidgetView extends ContentView {
1655
1655
  this.prevWidget = this.widget;
1656
1656
  this.widget = other.widget;
1657
1657
  this.length = other.length;
1658
+ this.type = other.type;
1658
1659
  this.breakAfter = other.breakAfter;
1659
1660
  return true;
1660
1661
  }
@@ -2215,6 +2216,10 @@ Represents a contiguous range of text that has a single direction
2215
2216
  (as in left-to-right or right-to-left).
2216
2217
  */
2217
2218
  class BidiSpan {
2219
+ /**
2220
+ The direction of this span.
2221
+ */
2222
+ get dir() { return this.level % 2 ? RTL : LTR; }
2218
2223
  /**
2219
2224
  @internal
2220
2225
  */
@@ -2240,10 +2245,6 @@ class BidiSpan {
2240
2245
  this.level = level;
2241
2246
  }
2242
2247
  /**
2243
- The direction of this span.
2244
- */
2245
- get dir() { return this.level % 2 ? RTL : LTR; }
2246
- /**
2247
2248
  @internal
2248
2249
  */
2249
2250
  side(end, dir) { return (this.dir == dir) == end ? this.to : this.from; }
@@ -2495,6 +2496,7 @@ class DOMReader {
2495
2496
  let parent = start.parentNode;
2496
2497
  for (let cur = start;;) {
2497
2498
  this.findPointBefore(parent, cur);
2499
+ let oldLen = this.text.length;
2498
2500
  this.readNode(cur);
2499
2501
  let next = cur.nextSibling;
2500
2502
  if (next == end)
@@ -2502,7 +2504,7 @@ class DOMReader {
2502
2504
  let view = ContentView.get(cur), nextView = ContentView.get(next);
2503
2505
  if (view && nextView ? view.breakAfter :
2504
2506
  (view ? view.breakAfter : isBlockElement(cur)) ||
2505
- (isBlockElement(next) && (cur.nodeName != "BR" || cur.cmIgnore)))
2507
+ (isBlockElement(next) && (cur.nodeName != "BR" || cur.cmIgnore) && this.text.length > oldLen))
2506
2508
  this.lineBreak();
2507
2509
  cur = next;
2508
2510
  }
@@ -2583,6 +2585,7 @@ class DOMPoint {
2583
2585
  }
2584
2586
 
2585
2587
  class DocView extends ContentView {
2588
+ get length() { return this.view.state.doc.length; }
2586
2589
  constructor(view) {
2587
2590
  super();
2588
2591
  this.view = view;
@@ -2613,7 +2616,6 @@ class DocView extends ContentView {
2613
2616
  this.updateDeco();
2614
2617
  this.updateInner([new ChangedRange(0, 0, 0, view.state.doc.length)], 0);
2615
2618
  }
2616
- get length() { return this.view.state.doc.length; }
2617
2619
  // Update the document view to a given state. scrollIntoView can be
2618
2620
  // used as a hint to compute a new viewport that includes that
2619
2621
  // position, if we know the editor is going to scroll that position
@@ -3451,15 +3453,15 @@ function moveVertically(view, start, forward, distance) {
3451
3453
  return state.EditorSelection.cursor(pos, start.assoc, undefined, goal);
3452
3454
  }
3453
3455
  }
3454
- function skipAtoms(view, oldPos, pos) {
3455
- let atoms = view.state.facet(atomicRanges).map(f => f(view));
3456
+ function skipAtomicRanges(atoms, pos, bias) {
3456
3457
  for (;;) {
3457
- let moved = false;
3458
+ let moved = 0;
3458
3459
  for (let set of atoms) {
3459
- set.between(pos.from - 1, pos.from + 1, (from, to, value) => {
3460
- if (pos.from > from && pos.from < to) {
3461
- pos = oldPos.head > pos.from ? state.EditorSelection.cursor(from, 1) : state.EditorSelection.cursor(to, -1);
3462
- moved = true;
3460
+ set.between(pos - 1, pos + 1, (from, to, value) => {
3461
+ if (pos > from && pos < to) {
3462
+ let side = moved || bias || (pos - from < to - pos ? -1 : 1);
3463
+ pos = side < 0 ? from : to;
3464
+ moved = side;
3463
3465
  }
3464
3466
  });
3465
3467
  }
@@ -3467,9 +3469,17 @@ function skipAtoms(view, oldPos, pos) {
3467
3469
  return pos;
3468
3470
  }
3469
3471
  }
3472
+ function skipAtoms(view, oldPos, pos) {
3473
+ let newPos = skipAtomicRanges(view.state.facet(atomicRanges).map(f => f(view)), pos.from, oldPos.head > pos.from ? -1 : 1);
3474
+ return newPos == pos.from ? pos : state.EditorSelection.cursor(newPos, newPos < pos.from ? 1 : -1);
3475
+ }
3470
3476
 
3471
3477
  // This will also be where dragging info and such goes
3472
3478
  class InputState {
3479
+ setSelectionOrigin(origin) {
3480
+ this.lastSelectionOrigin = origin;
3481
+ this.lastSelectionTime = Date.now();
3482
+ }
3473
3483
  constructor(view) {
3474
3484
  this.lastKeyCode = 0;
3475
3485
  this.lastKeyTime = 0;
@@ -3566,10 +3576,6 @@ class InputState {
3566
3576
  if (browser.safari)
3567
3577
  view.contentDOM.addEventListener("input", () => null);
3568
3578
  }
3569
- setSelectionOrigin(origin) {
3570
- this.lastSelectionOrigin = origin;
3571
- this.lastSelectionTime = Date.now();
3572
- }
3573
3579
  ensureHandlers(view, plugins) {
3574
3580
  var _a;
3575
3581
  let handlers;
@@ -3716,6 +3722,7 @@ class MouseSelection {
3716
3722
  this.scrolling = -1;
3717
3723
  this.lastEvent = startEvent;
3718
3724
  this.scrollParent = scrollableParent(view.contentDOM);
3725
+ this.atoms = view.state.facet(atomicRanges).map(f => f(view));
3719
3726
  let doc = view.contentDOM.ownerDocument;
3720
3727
  doc.addEventListener("mousemove", this.move = this.move.bind(this));
3721
3728
  doc.addEventListener("mouseup", this.up = this.up.bind(this));
@@ -3789,10 +3796,33 @@ class MouseSelection {
3789
3796
  if (this.dragging === false)
3790
3797
  this.select(this.lastEvent);
3791
3798
  }
3799
+ skipAtoms(sel) {
3800
+ let ranges = null;
3801
+ for (let i = 0; i < sel.ranges.length; i++) {
3802
+ let range = sel.ranges[i], updated = null;
3803
+ if (range.empty) {
3804
+ let pos = skipAtomicRanges(this.atoms, range.from, 0);
3805
+ if (pos != range.from)
3806
+ updated = state.EditorSelection.cursor(pos, -1);
3807
+ }
3808
+ else {
3809
+ let from = skipAtomicRanges(this.atoms, range.from, -1);
3810
+ let to = skipAtomicRanges(this.atoms, range.to, 1);
3811
+ if (from != range.from || to != range.to)
3812
+ updated = state.EditorSelection.range(range.from == range.anchor ? from : to, range.from == range.head ? from : to);
3813
+ }
3814
+ if (updated) {
3815
+ if (!ranges)
3816
+ ranges = sel.ranges.slice();
3817
+ ranges[i] = updated;
3818
+ }
3819
+ }
3820
+ return ranges ? state.EditorSelection.create(ranges, sel.mainIndex) : sel;
3821
+ }
3792
3822
  select(event) {
3793
- let selection = this.style.get(event, this.extend, this.multiple);
3794
- if (this.mustSelect || !selection.eq(this.view.state.selection) ||
3795
- selection.main.assoc != this.view.state.selection.main.assoc)
3823
+ let { view } = this, selection = this.skipAtoms(this.style.get(event, this.extend, this.multiple));
3824
+ if (this.mustSelect || !selection.eq(view.state.selection) ||
3825
+ selection.main.assoc != view.state.selection.main.assoc)
3796
3826
  this.view.dispatch({
3797
3827
  selection,
3798
3828
  userEvent: "select.pointer"
@@ -6469,6 +6499,53 @@ line number gutter. It handles events and dispatches state
6469
6499
  transactions for editing actions.
6470
6500
  */
6471
6501
  class EditorView {
6502
+ /**
6503
+ The current editor state.
6504
+ */
6505
+ get state() { return this.viewState.state; }
6506
+ /**
6507
+ To be able to display large documents without consuming too much
6508
+ memory or overloading the browser, CodeMirror only draws the
6509
+ code that is visible (plus a margin around it) to the DOM. This
6510
+ property tells you the extent of the current drawn viewport, in
6511
+ document positions.
6512
+ */
6513
+ get viewport() { return this.viewState.viewport; }
6514
+ /**
6515
+ When there are, for example, large collapsed ranges in the
6516
+ viewport, its size can be a lot bigger than the actual visible
6517
+ content. Thus, if you are doing something like styling the
6518
+ content in the viewport, it is preferable to only do so for
6519
+ these ranges, which are the subset of the viewport that is
6520
+ actually drawn.
6521
+ */
6522
+ get visibleRanges() { return this.viewState.visibleRanges; }
6523
+ /**
6524
+ Returns false when the editor is entirely scrolled out of view
6525
+ or otherwise hidden.
6526
+ */
6527
+ get inView() { return this.viewState.inView; }
6528
+ /**
6529
+ Indicates whether the user is currently composing text via
6530
+ [IME](https://en.wikipedia.org/wiki/Input_method), and at least
6531
+ one change has been made in the current composition.
6532
+ */
6533
+ get composing() { return this.inputState.composing > 0; }
6534
+ /**
6535
+ Indicates whether the user is currently in composing state. Note
6536
+ that on some platforms, like Android, this will be the case a
6537
+ lot, since just putting the cursor on a word starts a
6538
+ composition there.
6539
+ */
6540
+ get compositionStarted() { return this.inputState.composing >= 0; }
6541
+ /**
6542
+ The document or shadow root that the view lives in.
6543
+ */
6544
+ get root() { return this._root; }
6545
+ /**
6546
+ @internal
6547
+ */
6548
+ get win() { return this.dom.ownerDocument.defaultView || window; }
6472
6549
  /**
6473
6550
  Construct a new view. You'll want to either provide a `parent`
6474
6551
  option, or put `view.dom` into your document after creating a
@@ -6522,56 +6599,10 @@ class EditorView {
6522
6599
  if (config.parent)
6523
6600
  config.parent.appendChild(this.dom);
6524
6601
  }
6525
- /**
6526
- The current editor state.
6527
- */
6528
- get state() { return this.viewState.state; }
6529
- /**
6530
- To be able to display large documents without consuming too much
6531
- memory or overloading the browser, CodeMirror only draws the
6532
- code that is visible (plus a margin around it) to the DOM. This
6533
- property tells you the extent of the current drawn viewport, in
6534
- document positions.
6535
- */
6536
- get viewport() { return this.viewState.viewport; }
6537
- /**
6538
- When there are, for example, large collapsed ranges in the
6539
- viewport, its size can be a lot bigger than the actual visible
6540
- content. Thus, if you are doing something like styling the
6541
- content in the viewport, it is preferable to only do so for
6542
- these ranges, which are the subset of the viewport that is
6543
- actually drawn.
6544
- */
6545
- get visibleRanges() { return this.viewState.visibleRanges; }
6546
- /**
6547
- Returns false when the editor is entirely scrolled out of view
6548
- or otherwise hidden.
6549
- */
6550
- get inView() { return this.viewState.inView; }
6551
- /**
6552
- Indicates whether the user is currently composing text via
6553
- [IME](https://en.wikipedia.org/wiki/Input_method), and at least
6554
- one change has been made in the current composition.
6555
- */
6556
- get composing() { return this.inputState.composing > 0; }
6557
- /**
6558
- Indicates whether the user is currently in composing state. Note
6559
- that on some platforms, like Android, this will be the case a
6560
- lot, since just putting the cursor on a word starts a
6561
- composition there.
6562
- */
6563
- get compositionStarted() { return this.inputState.composing >= 0; }
6564
- /**
6565
- The document or shadow root that the view lives in.
6566
- */
6567
- get root() { return this._root; }
6568
- /**
6569
- @internal
6570
- */
6571
- get win() { return this.dom.ownerDocument.defaultView || window; }
6572
6602
  dispatch(...input) {
6573
- this._dispatch(input.length == 1 && input[0] instanceof state.Transaction ? input[0]
6574
- : this.state.update(...input));
6603
+ let tr = input.length == 1 && input[0] instanceof state.Transaction ? input[0]
6604
+ : this.state.update(...input);
6605
+ this._dispatch(tr, this);
6575
6606
  }
6576
6607
  /**
6577
6608
  Update the view for the given array of transactions. This will
@@ -7718,7 +7749,7 @@ function rectanglesForRange(view, className, range) {
7718
7749
  let top = visualStart ? drawForLine(range.from, null, visualStart) : drawForWidget(startBlock, false);
7719
7750
  let bottom = visualEnd ? drawForLine(null, range.to, visualEnd) : drawForWidget(endBlock, true);
7720
7751
  let between = [];
7721
- if ((visualStart || startBlock).to < (visualEnd || endBlock).from - 1)
7752
+ if ((visualStart || startBlock).to < (visualEnd || endBlock).from - (visualStart && visualEnd ? 1 : 0))
7722
7753
  between.push(piece(leftSide, top.bottom, rightSide, bottom.top));
7723
7754
  else if (top.bottom < bottom.top && view.elementAtHeight((top.bottom + bottom.top) / 2).type == exports.BlockType.Text)
7724
7755
  top.bottom = bottom.top = (top.bottom + bottom.top) / 2;
@@ -8876,6 +8907,10 @@ const showTooltip = state.Facet.define({
8876
8907
  });
8877
8908
  const showHoverTooltip = state.Facet.define();
8878
8909
  class HoverTooltipHost {
8910
+ // Needs to be static so that host tooltip instances always match
8911
+ static create(view) {
8912
+ return new HoverTooltipHost(view);
8913
+ }
8879
8914
  constructor(view) {
8880
8915
  this.view = view;
8881
8916
  this.mounted = false;
@@ -8883,10 +8918,6 @@ class HoverTooltipHost {
8883
8918
  this.dom.classList.add("cm-tooltip-hover");
8884
8919
  this.manager = new TooltipViewManager(view, showHoverTooltip, t => this.createHostedView(t));
8885
8920
  }
8886
- // Needs to be static so that host tooltip instances always match
8887
- static create(view) {
8888
- return new HoverTooltipHost(view);
8889
- }
8890
8921
  createHostedView(tooltip) {
8891
8922
  let hostedView = tooltip.create(this.view);
8892
8923
  hostedView.dom.classList.add("cm-tooltip-section");
package/dist/index.d.ts CHANGED
@@ -2,7 +2,7 @@ import * as _codemirror_state from '@codemirror/state';
2
2
  import { RangeSet, RangeValue, Range, EditorState, Extension, Transaction, ChangeSet, EditorSelection, EditorStateConfig, TransactionSpec, SelectionRange, Line, StateEffect, Facet } from '@codemirror/state';
3
3
  import { StyleModule, StyleSpec } from 'style-mod';
4
4
 
5
- declare type Attrs = {
5
+ type Attrs = {
6
6
  [name: string]: string;
7
7
  };
8
8
 
@@ -15,7 +15,7 @@ interface Rect {
15
15
  readonly top: number;
16
16
  readonly bottom: number;
17
17
  }
18
- declare type ScrollStrategy = "nearest" | "start" | "end" | "center";
18
+ type ScrollStrategy = "nearest" | "start" | "end" | "center";
19
19
 
20
20
  interface MarkDecorationSpec {
21
21
  /**
@@ -198,7 +198,7 @@ A decoration set represents a collection of decorated ranges,
198
198
  organized for efficient access and mapping. See
199
199
  [`RangeSet`](https://codemirror.net/6/docs/ref/#state.RangeSet) for its methods.
200
200
  */
201
- declare type DecorationSet = RangeSet<Decoration>;
201
+ type DecorationSet = RangeSet<Decoration>;
202
202
  /**
203
203
  The different types of blocks that can occur in an editor view.
204
204
  */
@@ -297,7 +297,7 @@ apply to the editor, and if it can, perform it as a side effect
297
297
  (which usually means [dispatching](https://codemirror.net/6/docs/ref/#view.EditorView.dispatch) a
298
298
  transaction) and return `true`.
299
299
  */
300
- declare type Command = (target: EditorView) => boolean;
300
+ type Command = (target: EditorView) => boolean;
301
301
  /**
302
302
  Log or report an unhandled exception in client code. Should
303
303
  probably only be used by extension code that allows client code to
@@ -399,7 +399,7 @@ interface MeasureRequest<T> {
399
399
  */
400
400
  key?: any;
401
401
  }
402
- declare type AttrSource = Attrs | ((view: EditorView) => Attrs | null);
402
+ type AttrSource = Attrs | ((view: EditorView) => Attrs | null);
403
403
  /**
404
404
  View [plugins](https://codemirror.net/6/docs/ref/#view.ViewPlugin) are given instances of this
405
405
  class, which describe what happened, whenever the view is updated.
@@ -488,7 +488,7 @@ interface MouseSelectionStyle {
488
488
  */
489
489
  update: (update: ViewUpdate) => boolean | void;
490
490
  }
491
- declare type MakeSelectionStyle = (view: EditorView, event: MouseEvent) => MouseSelectionStyle | null;
491
+ type MakeSelectionStyle = (view: EditorView, event: MouseEvent) => MouseSelectionStyle | null;
492
492
 
493
493
  /**
494
494
  Record used to represent information about a block-level element
@@ -605,7 +605,7 @@ interface EditorViewConfig extends EditorStateConfig {
605
605
  if provided, should probably call the view's [`update`
606
606
  method](https://codemirror.net/6/docs/ref/#view.EditorView.update).
607
607
  */
608
- dispatch?: (tr: Transaction) => void;
608
+ dispatch?: (tr: Transaction, view: EditorView) => void;
609
609
  }
610
610
  /**
611
611
  An editor view represents the editor's user interface. It holds
@@ -1183,7 +1183,7 @@ to hold the appropriate event object type. For unknown events, it
1183
1183
  is inferred to `any`, and should be explicitly set if you want type
1184
1184
  checking.
1185
1185
  */
1186
- declare type DOMEventHandlers<This> = {
1186
+ type DOMEventHandlers<This> = {
1187
1187
  [event in keyof DOMEventMap]?: (this: This, event: DOMEventMap[event], view: EditorView) => boolean | void;
1188
1188
  };
1189
1189
 
@@ -1285,7 +1285,7 @@ handlers handled it.
1285
1285
  */
1286
1286
  declare function runScopeHandlers(view: EditorView, event: KeyboardEvent, scope: string): boolean;
1287
1287
 
1288
- declare type SelectionConfig = {
1288
+ type SelectionConfig = {
1289
1289
  /**
1290
1290
  The length of a full cursor blink cycle, in milliseconds.
1291
1291
  Defaults to 1200. Can be set to 0 to disable blinking.
@@ -1751,7 +1751,7 @@ invalidate the existing tooltip positions.
1751
1751
  */
1752
1752
  declare function repositionTooltips(view: EditorView): void;
1753
1753
 
1754
- declare type PanelConfig = {
1754
+ type PanelConfig = {
1755
1755
  /**
1756
1756
  By default, panels will be placed inside the editor's DOM
1757
1757
  structure. You can use this option to override where panels with
@@ -1805,7 +1805,7 @@ declare function getPanel(view: EditorView, panel: PanelConstructor): Panel | nu
1805
1805
  A function that initializes a panel. Used in
1806
1806
  [`showPanel`](https://codemirror.net/6/docs/ref/#view.showPanel).
1807
1807
  */
1808
- declare type PanelConstructor = (view: EditorView) => Panel;
1808
+ type PanelConstructor = (view: EditorView) => Panel;
1809
1809
  /**
1810
1810
  Opening a panel is done by providing a constructor function for
1811
1811
  the panel through this facet. (The panel is closed again when its
@@ -1846,7 +1846,7 @@ Markers given to this facet should _only_ define an
1846
1846
  in all gutters for the line).
1847
1847
  */
1848
1848
  declare const gutterLineClass: Facet<RangeSet<GutterMarker>, readonly RangeSet<GutterMarker>[]>;
1849
- declare type Handlers = {
1849
+ type Handlers = {
1850
1850
  [event: string]: (view: EditorView, line: BlockInfo, event: Event) => boolean;
1851
1851
  };
1852
1852
  interface GutterConfig {
package/dist/index.js CHANGED
@@ -818,6 +818,9 @@ function textCoords(text, pos, side) {
818
818
  }
819
819
  // Also used for collapsed ranges that don't have a placeholder widget!
820
820
  class WidgetView extends ContentView {
821
+ static create(widget, length, side) {
822
+ return new (widget.customView || WidgetView)(widget, length, side);
823
+ }
821
824
  constructor(widget, length, side) {
822
825
  super();
823
826
  this.widget = widget;
@@ -825,9 +828,6 @@ class WidgetView extends ContentView {
825
828
  this.side = side;
826
829
  this.prevWidget = null;
827
830
  }
828
- static create(widget, length, side) {
829
- return new (widget.customView || WidgetView)(widget, length, side);
830
- }
831
831
  split(from) {
832
832
  let result = WidgetView.create(this.widget, this.length - from, this.side);
833
833
  this.length -= from;
@@ -1642,7 +1642,7 @@ class BlockWidgetView extends ContentView {
1642
1642
  }
1643
1643
  domBoundsAround() { return null; }
1644
1644
  become(other) {
1645
- if (other instanceof BlockWidgetView && other.type == this.type &&
1645
+ if (other instanceof BlockWidgetView &&
1646
1646
  other.widget.constructor == this.widget.constructor) {
1647
1647
  if (!other.widget.compare(this.widget))
1648
1648
  this.markDirty(true);
@@ -1650,6 +1650,7 @@ class BlockWidgetView extends ContentView {
1650
1650
  this.prevWidget = this.widget;
1651
1651
  this.widget = other.widget;
1652
1652
  this.length = other.length;
1653
+ this.type = other.type;
1653
1654
  this.breakAfter = other.breakAfter;
1654
1655
  return true;
1655
1656
  }
@@ -2209,6 +2210,10 @@ Represents a contiguous range of text that has a single direction
2209
2210
  (as in left-to-right or right-to-left).
2210
2211
  */
2211
2212
  class BidiSpan {
2213
+ /**
2214
+ The direction of this span.
2215
+ */
2216
+ get dir() { return this.level % 2 ? RTL : LTR; }
2212
2217
  /**
2213
2218
  @internal
2214
2219
  */
@@ -2234,10 +2239,6 @@ class BidiSpan {
2234
2239
  this.level = level;
2235
2240
  }
2236
2241
  /**
2237
- The direction of this span.
2238
- */
2239
- get dir() { return this.level % 2 ? RTL : LTR; }
2240
- /**
2241
2242
  @internal
2242
2243
  */
2243
2244
  side(end, dir) { return (this.dir == dir) == end ? this.to : this.from; }
@@ -2489,6 +2490,7 @@ class DOMReader {
2489
2490
  let parent = start.parentNode;
2490
2491
  for (let cur = start;;) {
2491
2492
  this.findPointBefore(parent, cur);
2493
+ let oldLen = this.text.length;
2492
2494
  this.readNode(cur);
2493
2495
  let next = cur.nextSibling;
2494
2496
  if (next == end)
@@ -2496,7 +2498,7 @@ class DOMReader {
2496
2498
  let view = ContentView.get(cur), nextView = ContentView.get(next);
2497
2499
  if (view && nextView ? view.breakAfter :
2498
2500
  (view ? view.breakAfter : isBlockElement(cur)) ||
2499
- (isBlockElement(next) && (cur.nodeName != "BR" || cur.cmIgnore)))
2501
+ (isBlockElement(next) && (cur.nodeName != "BR" || cur.cmIgnore) && this.text.length > oldLen))
2500
2502
  this.lineBreak();
2501
2503
  cur = next;
2502
2504
  }
@@ -2577,6 +2579,7 @@ class DOMPoint {
2577
2579
  }
2578
2580
 
2579
2581
  class DocView extends ContentView {
2582
+ get length() { return this.view.state.doc.length; }
2580
2583
  constructor(view) {
2581
2584
  super();
2582
2585
  this.view = view;
@@ -2607,7 +2610,6 @@ class DocView extends ContentView {
2607
2610
  this.updateDeco();
2608
2611
  this.updateInner([new ChangedRange(0, 0, 0, view.state.doc.length)], 0);
2609
2612
  }
2610
- get length() { return this.view.state.doc.length; }
2611
2613
  // Update the document view to a given state. scrollIntoView can be
2612
2614
  // used as a hint to compute a new viewport that includes that
2613
2615
  // position, if we know the editor is going to scroll that position
@@ -3445,15 +3447,15 @@ function moveVertically(view, start, forward, distance) {
3445
3447
  return EditorSelection.cursor(pos, start.assoc, undefined, goal);
3446
3448
  }
3447
3449
  }
3448
- function skipAtoms(view, oldPos, pos) {
3449
- let atoms = view.state.facet(atomicRanges).map(f => f(view));
3450
+ function skipAtomicRanges(atoms, pos, bias) {
3450
3451
  for (;;) {
3451
- let moved = false;
3452
+ let moved = 0;
3452
3453
  for (let set of atoms) {
3453
- set.between(pos.from - 1, pos.from + 1, (from, to, value) => {
3454
- if (pos.from > from && pos.from < to) {
3455
- pos = oldPos.head > pos.from ? EditorSelection.cursor(from, 1) : EditorSelection.cursor(to, -1);
3456
- moved = true;
3454
+ set.between(pos - 1, pos + 1, (from, to, value) => {
3455
+ if (pos > from && pos < to) {
3456
+ let side = moved || bias || (pos - from < to - pos ? -1 : 1);
3457
+ pos = side < 0 ? from : to;
3458
+ moved = side;
3457
3459
  }
3458
3460
  });
3459
3461
  }
@@ -3461,9 +3463,17 @@ function skipAtoms(view, oldPos, pos) {
3461
3463
  return pos;
3462
3464
  }
3463
3465
  }
3466
+ function skipAtoms(view, oldPos, pos) {
3467
+ let newPos = skipAtomicRanges(view.state.facet(atomicRanges).map(f => f(view)), pos.from, oldPos.head > pos.from ? -1 : 1);
3468
+ return newPos == pos.from ? pos : EditorSelection.cursor(newPos, newPos < pos.from ? 1 : -1);
3469
+ }
3464
3470
 
3465
3471
  // This will also be where dragging info and such goes
3466
3472
  class InputState {
3473
+ setSelectionOrigin(origin) {
3474
+ this.lastSelectionOrigin = origin;
3475
+ this.lastSelectionTime = Date.now();
3476
+ }
3467
3477
  constructor(view) {
3468
3478
  this.lastKeyCode = 0;
3469
3479
  this.lastKeyTime = 0;
@@ -3560,10 +3570,6 @@ class InputState {
3560
3570
  if (browser.safari)
3561
3571
  view.contentDOM.addEventListener("input", () => null);
3562
3572
  }
3563
- setSelectionOrigin(origin) {
3564
- this.lastSelectionOrigin = origin;
3565
- this.lastSelectionTime = Date.now();
3566
- }
3567
3573
  ensureHandlers(view, plugins) {
3568
3574
  var _a;
3569
3575
  let handlers;
@@ -3710,6 +3716,7 @@ class MouseSelection {
3710
3716
  this.scrolling = -1;
3711
3717
  this.lastEvent = startEvent;
3712
3718
  this.scrollParent = scrollableParent(view.contentDOM);
3719
+ this.atoms = view.state.facet(atomicRanges).map(f => f(view));
3713
3720
  let doc = view.contentDOM.ownerDocument;
3714
3721
  doc.addEventListener("mousemove", this.move = this.move.bind(this));
3715
3722
  doc.addEventListener("mouseup", this.up = this.up.bind(this));
@@ -3783,10 +3790,33 @@ class MouseSelection {
3783
3790
  if (this.dragging === false)
3784
3791
  this.select(this.lastEvent);
3785
3792
  }
3793
+ skipAtoms(sel) {
3794
+ let ranges = null;
3795
+ for (let i = 0; i < sel.ranges.length; i++) {
3796
+ let range = sel.ranges[i], updated = null;
3797
+ if (range.empty) {
3798
+ let pos = skipAtomicRanges(this.atoms, range.from, 0);
3799
+ if (pos != range.from)
3800
+ updated = EditorSelection.cursor(pos, -1);
3801
+ }
3802
+ else {
3803
+ let from = skipAtomicRanges(this.atoms, range.from, -1);
3804
+ let to = skipAtomicRanges(this.atoms, range.to, 1);
3805
+ if (from != range.from || to != range.to)
3806
+ updated = EditorSelection.range(range.from == range.anchor ? from : to, range.from == range.head ? from : to);
3807
+ }
3808
+ if (updated) {
3809
+ if (!ranges)
3810
+ ranges = sel.ranges.slice();
3811
+ ranges[i] = updated;
3812
+ }
3813
+ }
3814
+ return ranges ? EditorSelection.create(ranges, sel.mainIndex) : sel;
3815
+ }
3786
3816
  select(event) {
3787
- let selection = this.style.get(event, this.extend, this.multiple);
3788
- if (this.mustSelect || !selection.eq(this.view.state.selection) ||
3789
- selection.main.assoc != this.view.state.selection.main.assoc)
3817
+ let { view } = this, selection = this.skipAtoms(this.style.get(event, this.extend, this.multiple));
3818
+ if (this.mustSelect || !selection.eq(view.state.selection) ||
3819
+ selection.main.assoc != view.state.selection.main.assoc)
3790
3820
  this.view.dispatch({
3791
3821
  selection,
3792
3822
  userEvent: "select.pointer"
@@ -6462,6 +6492,53 @@ line number gutter. It handles events and dispatches state
6462
6492
  transactions for editing actions.
6463
6493
  */
6464
6494
  class EditorView {
6495
+ /**
6496
+ The current editor state.
6497
+ */
6498
+ get state() { return this.viewState.state; }
6499
+ /**
6500
+ To be able to display large documents without consuming too much
6501
+ memory or overloading the browser, CodeMirror only draws the
6502
+ code that is visible (plus a margin around it) to the DOM. This
6503
+ property tells you the extent of the current drawn viewport, in
6504
+ document positions.
6505
+ */
6506
+ get viewport() { return this.viewState.viewport; }
6507
+ /**
6508
+ When there are, for example, large collapsed ranges in the
6509
+ viewport, its size can be a lot bigger than the actual visible
6510
+ content. Thus, if you are doing something like styling the
6511
+ content in the viewport, it is preferable to only do so for
6512
+ these ranges, which are the subset of the viewport that is
6513
+ actually drawn.
6514
+ */
6515
+ get visibleRanges() { return this.viewState.visibleRanges; }
6516
+ /**
6517
+ Returns false when the editor is entirely scrolled out of view
6518
+ or otherwise hidden.
6519
+ */
6520
+ get inView() { return this.viewState.inView; }
6521
+ /**
6522
+ Indicates whether the user is currently composing text via
6523
+ [IME](https://en.wikipedia.org/wiki/Input_method), and at least
6524
+ one change has been made in the current composition.
6525
+ */
6526
+ get composing() { return this.inputState.composing > 0; }
6527
+ /**
6528
+ Indicates whether the user is currently in composing state. Note
6529
+ that on some platforms, like Android, this will be the case a
6530
+ lot, since just putting the cursor on a word starts a
6531
+ composition there.
6532
+ */
6533
+ get compositionStarted() { return this.inputState.composing >= 0; }
6534
+ /**
6535
+ The document or shadow root that the view lives in.
6536
+ */
6537
+ get root() { return this._root; }
6538
+ /**
6539
+ @internal
6540
+ */
6541
+ get win() { return this.dom.ownerDocument.defaultView || window; }
6465
6542
  /**
6466
6543
  Construct a new view. You'll want to either provide a `parent`
6467
6544
  option, or put `view.dom` into your document after creating a
@@ -6515,56 +6592,10 @@ class EditorView {
6515
6592
  if (config.parent)
6516
6593
  config.parent.appendChild(this.dom);
6517
6594
  }
6518
- /**
6519
- The current editor state.
6520
- */
6521
- get state() { return this.viewState.state; }
6522
- /**
6523
- To be able to display large documents without consuming too much
6524
- memory or overloading the browser, CodeMirror only draws the
6525
- code that is visible (plus a margin around it) to the DOM. This
6526
- property tells you the extent of the current drawn viewport, in
6527
- document positions.
6528
- */
6529
- get viewport() { return this.viewState.viewport; }
6530
- /**
6531
- When there are, for example, large collapsed ranges in the
6532
- viewport, its size can be a lot bigger than the actual visible
6533
- content. Thus, if you are doing something like styling the
6534
- content in the viewport, it is preferable to only do so for
6535
- these ranges, which are the subset of the viewport that is
6536
- actually drawn.
6537
- */
6538
- get visibleRanges() { return this.viewState.visibleRanges; }
6539
- /**
6540
- Returns false when the editor is entirely scrolled out of view
6541
- or otherwise hidden.
6542
- */
6543
- get inView() { return this.viewState.inView; }
6544
- /**
6545
- Indicates whether the user is currently composing text via
6546
- [IME](https://en.wikipedia.org/wiki/Input_method), and at least
6547
- one change has been made in the current composition.
6548
- */
6549
- get composing() { return this.inputState.composing > 0; }
6550
- /**
6551
- Indicates whether the user is currently in composing state. Note
6552
- that on some platforms, like Android, this will be the case a
6553
- lot, since just putting the cursor on a word starts a
6554
- composition there.
6555
- */
6556
- get compositionStarted() { return this.inputState.composing >= 0; }
6557
- /**
6558
- The document or shadow root that the view lives in.
6559
- */
6560
- get root() { return this._root; }
6561
- /**
6562
- @internal
6563
- */
6564
- get win() { return this.dom.ownerDocument.defaultView || window; }
6565
6595
  dispatch(...input) {
6566
- this._dispatch(input.length == 1 && input[0] instanceof Transaction ? input[0]
6567
- : this.state.update(...input));
6596
+ let tr = input.length == 1 && input[0] instanceof Transaction ? input[0]
6597
+ : this.state.update(...input);
6598
+ this._dispatch(tr, this);
6568
6599
  }
6569
6600
  /**
6570
6601
  Update the view for the given array of transactions. This will
@@ -7711,7 +7742,7 @@ function rectanglesForRange(view, className, range) {
7711
7742
  let top = visualStart ? drawForLine(range.from, null, visualStart) : drawForWidget(startBlock, false);
7712
7743
  let bottom = visualEnd ? drawForLine(null, range.to, visualEnd) : drawForWidget(endBlock, true);
7713
7744
  let between = [];
7714
- if ((visualStart || startBlock).to < (visualEnd || endBlock).from - 1)
7745
+ if ((visualStart || startBlock).to < (visualEnd || endBlock).from - (visualStart && visualEnd ? 1 : 0))
7715
7746
  between.push(piece(leftSide, top.bottom, rightSide, bottom.top));
7716
7747
  else if (top.bottom < bottom.top && view.elementAtHeight((top.bottom + bottom.top) / 2).type == BlockType.Text)
7717
7748
  top.bottom = bottom.top = (top.bottom + bottom.top) / 2;
@@ -8869,6 +8900,10 @@ const showTooltip = /*@__PURE__*/Facet.define({
8869
8900
  });
8870
8901
  const showHoverTooltip = /*@__PURE__*/Facet.define();
8871
8902
  class HoverTooltipHost {
8903
+ // Needs to be static so that host tooltip instances always match
8904
+ static create(view) {
8905
+ return new HoverTooltipHost(view);
8906
+ }
8872
8907
  constructor(view) {
8873
8908
  this.view = view;
8874
8909
  this.mounted = false;
@@ -8876,10 +8911,6 @@ class HoverTooltipHost {
8876
8911
  this.dom.classList.add("cm-tooltip-hover");
8877
8912
  this.manager = new TooltipViewManager(view, showHoverTooltip, t => this.createHostedView(t));
8878
8913
  }
8879
- // Needs to be static so that host tooltip instances always match
8880
- static create(view) {
8881
- return new HoverTooltipHost(view);
8882
- }
8883
8914
  createHostedView(tooltip) {
8884
8915
  let hostedView = tooltip.create(this.view);
8885
8916
  hostedView.dom.classList.add("cm-tooltip-section");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codemirror/view",
3
- "version": "6.11.2",
3
+ "version": "6.12.0",
4
4
  "description": "DOM view component for the CodeMirror code editor",
5
5
  "scripts": {
6
6
  "test": "cm-runtests",