@codemirror/view 6.17.1 → 6.18.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { EditorState, Text, RangeSet, MapMode, RangeValue, Facet, StateEffect, ChangeSet, findClusterBreak, EditorSelection, findColumn, CharCategory, Annotation, Transaction, Prec, codePointAt, codePointSize, combineConfig, StateField, RangeSetBuilder, countColumn } from '@codemirror/state';
1
+ import { Text, RangeSet, MapMode, RangeValue, Facet, StateEffect, ChangeSet, findClusterBreak, EditorSelection, 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
 
@@ -99,6 +99,7 @@ function scrollRectIntoView(dom, rect, side, x, y, xMargin, yMargin, ltr) {
99
99
  for (let cur = dom, stop = false; cur && !stop;) {
100
100
  if (cur.nodeType == 1) { // Element
101
101
  let bounding, top = cur == doc.body;
102
+ let scaleX = 1, scaleY = 1;
102
103
  if (top) {
103
104
  bounding = windowRect(win);
104
105
  }
@@ -110,9 +111,11 @@ function scrollRectIntoView(dom, rect, side, x, y, xMargin, yMargin, ltr) {
110
111
  continue;
111
112
  }
112
113
  let rect = cur.getBoundingClientRect();
114
+ scaleX = rect.width / cur.offsetWidth;
115
+ scaleY = rect.height / cur.offsetHeight;
113
116
  // Make sure scrollbar width isn't included in the rectangle
114
- bounding = { left: rect.left, right: rect.left + cur.clientWidth,
115
- top: rect.top, bottom: rect.top + cur.clientHeight };
117
+ bounding = { left: rect.left, right: rect.left + cur.clientWidth * scaleX,
118
+ top: rect.top, bottom: rect.top + cur.clientHeight * scaleY };
116
119
  }
117
120
  let moveX = 0, moveY = 0;
118
121
  if (y == "nearest") {
@@ -160,13 +163,13 @@ function scrollRectIntoView(dom, rect, side, x, y, xMargin, yMargin, ltr) {
160
163
  let movedX = 0, movedY = 0;
161
164
  if (moveY) {
162
165
  let start = cur.scrollTop;
163
- cur.scrollTop += moveY;
164
- movedY = cur.scrollTop - start;
166
+ cur.scrollTop += moveY / scaleY;
167
+ movedY = (cur.scrollTop - start) * scaleY;
165
168
  }
166
169
  if (moveX) {
167
170
  let start = cur.scrollLeft;
168
- cur.scrollLeft += moveX;
169
- movedX = cur.scrollLeft - start;
171
+ cur.scrollLeft += moveX / scaleX;
172
+ movedX = (cur.scrollLeft - start) * scaleX;
170
173
  }
171
174
  rect = { left: rect.left - movedX, top: rect.top - movedY,
172
175
  right: rect.right - movedX, bottom: rect.bottom - movedY };
@@ -479,6 +482,8 @@ class ContentView {
479
482
  }
480
483
  }
481
484
  setDOM(dom) {
485
+ if (this.dom == dom)
486
+ return;
482
487
  if (this.dom)
483
488
  this.dom.cmView = null;
484
489
  this.dom = dom;
@@ -651,113 +656,6 @@ function mergeChildrenInto(parent, from, to, insert, openStart, openEnd) {
651
656
  replaceRange(parent, fromI, fromOff, toI, toOff, insert, 0, openStart, openEnd);
652
657
  }
653
658
 
654
- const LineBreakPlaceholder = "\uffff";
655
- class DOMReader {
656
- constructor(points, state) {
657
- this.points = points;
658
- this.text = "";
659
- this.lineSeparator = state.facet(EditorState.lineSeparator);
660
- }
661
- append(text) {
662
- this.text += text;
663
- }
664
- lineBreak() {
665
- this.text += LineBreakPlaceholder;
666
- }
667
- readRange(start, end) {
668
- if (!start)
669
- return this;
670
- let parent = start.parentNode;
671
- for (let cur = start;;) {
672
- this.findPointBefore(parent, cur);
673
- let oldLen = this.text.length;
674
- this.readNode(cur);
675
- let next = cur.nextSibling;
676
- if (next == end)
677
- break;
678
- let view = ContentView.get(cur), nextView = ContentView.get(next);
679
- if (view && nextView ? view.breakAfter :
680
- (view ? view.breakAfter : isBlockElement(cur)) ||
681
- (isBlockElement(next) && (cur.nodeName != "BR" || cur.cmIgnore) && this.text.length > oldLen))
682
- this.lineBreak();
683
- cur = next;
684
- }
685
- this.findPointBefore(parent, end);
686
- return this;
687
- }
688
- readTextNode(node) {
689
- let text = node.nodeValue;
690
- for (let point of this.points)
691
- if (point.node == node)
692
- point.pos = this.text.length + Math.min(point.offset, text.length);
693
- for (let off = 0, re = this.lineSeparator ? null : /\r\n?|\n/g;;) {
694
- let nextBreak = -1, breakSize = 1, m;
695
- if (this.lineSeparator) {
696
- nextBreak = text.indexOf(this.lineSeparator, off);
697
- breakSize = this.lineSeparator.length;
698
- }
699
- else if (m = re.exec(text)) {
700
- nextBreak = m.index;
701
- breakSize = m[0].length;
702
- }
703
- this.append(text.slice(off, nextBreak < 0 ? text.length : nextBreak));
704
- if (nextBreak < 0)
705
- break;
706
- this.lineBreak();
707
- if (breakSize > 1)
708
- for (let point of this.points)
709
- if (point.node == node && point.pos > this.text.length)
710
- point.pos -= breakSize - 1;
711
- off = nextBreak + breakSize;
712
- }
713
- }
714
- readNode(node) {
715
- if (node.cmIgnore)
716
- return;
717
- let view = ContentView.get(node);
718
- let fromView = view && view.overrideDOMText;
719
- if (fromView != null) {
720
- this.findPointInside(node, fromView.length);
721
- for (let i = fromView.iter(); !i.next().done;) {
722
- if (i.lineBreak)
723
- this.lineBreak();
724
- else
725
- this.append(i.value);
726
- }
727
- }
728
- else if (node.nodeType == 3) {
729
- this.readTextNode(node);
730
- }
731
- else if (node.nodeName == "BR") {
732
- if (node.nextSibling)
733
- this.lineBreak();
734
- }
735
- else if (node.nodeType == 1) {
736
- this.readRange(node.firstChild, null);
737
- }
738
- }
739
- findPointBefore(node, next) {
740
- for (let point of this.points)
741
- if (point.node == node && node.childNodes[point.offset] == next)
742
- point.pos = this.text.length;
743
- }
744
- findPointInside(node, maxLen) {
745
- for (let point of this.points)
746
- if (node.nodeType == 3 ? point.node == node : node.contains(point.node))
747
- point.pos = this.text.length + Math.min(maxLen, point.offset);
748
- }
749
- }
750
- function isBlockElement(node) {
751
- return node.nodeType == 1 && /^(DIV|P|LI|UL|OL|BLOCKQUOTE|DD|DT|H\d|SECTION|PRE)$/.test(node.nodeName);
752
- }
753
- class DOMPoint {
754
- constructor(node, offset) {
755
- this.node = node;
756
- this.offset = offset;
757
- this.pos = -1;
758
- }
759
- }
760
-
761
659
  let nav = typeof navigator != "undefined" ? navigator : { userAgent: "", vendor: "", platform: "" };
762
660
  let doc = typeof document != "undefined" ? document : { documentElement: { style: {} } };
763
661
  const ie_edge = /*@__PURE__*//Edge\/(\d+)/.exec(nav.userAgent);
@@ -2699,6 +2597,7 @@ class DocView extends ContentView {
2699
2597
  this.view = view;
2700
2598
  this.decorations = [];
2701
2599
  this.dynamicDecorationMap = [];
2600
+ this.domChanged = null;
2702
2601
  this.hasComposition = null;
2703
2602
  this.markedForComposition = new Set;
2704
2603
  // Track a minimum width for the editor. When measuring sizes in
@@ -2727,6 +2626,7 @@ class DocView extends ContentView {
2727
2626
  }
2728
2627
  // Update the document view to a given state.
2729
2628
  update(update) {
2629
+ var _a;
2730
2630
  let changedRanges = update.changedRanges;
2731
2631
  if (this.minWidth > 0 && changedRanges.length) {
2732
2632
  if (!changedRanges.every(({ fromA, toA }) => toA < this.minWidthFrom || fromA > this.minWidthTo)) {
@@ -2737,7 +2637,15 @@ class DocView extends ContentView {
2737
2637
  this.minWidthTo = update.changes.mapPos(this.minWidthTo, 1);
2738
2638
  }
2739
2639
  }
2740
- let composition = this.view.inputState.composing < 0 ? null : findCompositionRange(this.view, update.changes);
2640
+ let readCompositionAt = -1;
2641
+ if (this.view.inputState.composing >= 0) {
2642
+ if ((_a = this.domChanged) === null || _a === void 0 ? void 0 : _a.newSel)
2643
+ readCompositionAt = this.domChanged.newSel.head;
2644
+ else if (!touchesComposition(update.changes, this.hasComposition) && !update.selectionSet)
2645
+ readCompositionAt = update.state.selection.main.head;
2646
+ }
2647
+ let composition = readCompositionAt > -1 ? findCompositionRange(this.view, update.changes, readCompositionAt) : null;
2648
+ this.domChanged = null;
2741
2649
  if (this.hasComposition) {
2742
2650
  this.markedForComposition.clear();
2743
2651
  let { from, to } = this.hasComposition;
@@ -2777,7 +2685,7 @@ class DocView extends ContentView {
2777
2685
  // messes with the scroll position during DOM mutation (though
2778
2686
  // no relayout is triggered and I cannot imagine how it can
2779
2687
  // recompute the scroll position without a layout)
2780
- this.dom.style.height = this.view.viewState.contentHeight + "px";
2688
+ this.dom.style.height = this.view.viewState.contentHeight / this.view.scaleY + "px";
2781
2689
  this.dom.style.flexBasis = this.minWidth ? this.minWidth + "px" : "";
2782
2690
  // Chrome will sometimes, when DOM mutations occur directly
2783
2691
  // around the selection, get confused and report a different
@@ -2849,14 +2757,12 @@ class DocView extends ContentView {
2849
2757
  }
2850
2758
  fixCompositionDOM(composition) {
2851
2759
  let fix = (dom, cView) => {
2852
- cView.flags |= 8 /* ViewFlag.Composition */;
2760
+ cView.flags |= 8 /* ViewFlag.Composition */ | (cView.children.some(c => c.flags & 7 /* ViewFlag.Dirty */) ? 1 /* ViewFlag.ChildDirty */ : 0);
2853
2761
  this.markedForComposition.add(cView);
2854
2762
  let prev = ContentView.get(dom);
2855
- if (prev != cView) {
2856
- if (prev)
2857
- prev.dom = null;
2858
- cView.setDOM(dom);
2859
- }
2763
+ if (prev && prev != cView)
2764
+ prev.dom = null;
2765
+ cView.setDOM(dom);
2860
2766
  };
2861
2767
  let pos = this.childPos(composition.range.fromB, 1);
2862
2768
  let cView = this.children[pos.i];
@@ -2879,9 +2785,8 @@ class DocView extends ContentView {
2879
2785
  let force = this.forceSelection;
2880
2786
  this.forceSelection = false;
2881
2787
  let main = this.view.state.selection.main;
2882
- // FIXME need to handle the case where the selection falls inside a block range
2883
- let anchor = this.domAtPos(main.anchor);
2884
- let head = main.empty ? anchor : this.domAtPos(main.head);
2788
+ let anchor = this.moveToLine(this.domAtPos(main.anchor));
2789
+ let head = main.empty ? anchor : this.moveToLine(this.domAtPos(main.head));
2885
2790
  // Always reset on Firefox when next to an uneditable node to
2886
2791
  // avoid invisible cursor bugs (#111)
2887
2792
  if (browser.gecko && main.empty && !this.hasComposition && betweenUneditable(anchor)) {
@@ -2914,12 +2819,12 @@ class DocView extends ContentView {
2914
2819
  if (nextTo && nextTo != (1 /* NextTo.Before */ | 2 /* NextTo.After */)) {
2915
2820
  let text = nearbyTextNode(anchor.node, anchor.offset, nextTo == 1 /* NextTo.Before */ ? 1 : -1);
2916
2821
  if (text)
2917
- anchor = new DOMPos(text, nextTo == 1 /* NextTo.Before */ ? 0 : text.nodeValue.length);
2822
+ anchor = new DOMPos(text.node, text.offset);
2918
2823
  }
2919
2824
  }
2920
2825
  rawSel.collapse(anchor.node, anchor.offset);
2921
- if (main.bidiLevel != null && domSel.caretBidiLevel != null)
2922
- domSel.caretBidiLevel = main.bidiLevel;
2826
+ if (main.bidiLevel != null && rawSel.caretBidiLevel !== undefined)
2827
+ rawSel.caretBidiLevel = main.bidiLevel;
2923
2828
  }
2924
2829
  else if (rawSel.extend) {
2925
2830
  // Selection.extend can be used to create an 'inverted' selection
@@ -2982,6 +2887,26 @@ class DocView extends ContentView {
2982
2887
  if (view.docView.posFromDOM(newRange.anchorNode, newRange.anchorOffset) != cursor.from)
2983
2888
  sel.collapse(anchorNode, anchorOffset);
2984
2889
  }
2890
+ // If a position is in/near a block widget, move it to a nearby text
2891
+ // line, since we don't want the cursor inside a block widget.
2892
+ moveToLine(pos) {
2893
+ // Block widgets will return positions before/after them, which
2894
+ // are thus directly in the document DOM element.
2895
+ let dom = this.dom, newPos;
2896
+ if (pos.node != dom)
2897
+ return pos;
2898
+ for (let i = pos.offset; !newPos && i < dom.childNodes.length; i++) {
2899
+ let view = ContentView.get(dom.childNodes[i]);
2900
+ if (view instanceof LineView)
2901
+ newPos = view.domAtPos(0);
2902
+ }
2903
+ for (let i = pos.offset - 1; !newPos && i >= 0; i--) {
2904
+ let view = ContentView.get(dom.childNodes[i]);
2905
+ if (view instanceof LineView)
2906
+ newPos = view.domAtPos(view.length);
2907
+ }
2908
+ return newPos ? new DOMPos(newPos.node, newPos.offset, true) : pos;
2909
+ }
2985
2910
  nearest(dom) {
2986
2911
  for (let cur = dom; cur;) {
2987
2912
  let domView = ContentView.get(cur);
@@ -3115,7 +3040,7 @@ class DocView extends ContentView {
3115
3040
  let next = i == vs.viewports.length ? null : vs.viewports[i];
3116
3041
  let end = next ? next.from - 1 : this.length;
3117
3042
  if (end > pos) {
3118
- let height = vs.lineBlockAt(end).bottom - vs.lineBlockAt(pos).top;
3043
+ let height = (vs.lineBlockAt(end).bottom - vs.lineBlockAt(pos).top) / this.view.scaleY;
3119
3044
  deco.push(Decoration.replace({
3120
3045
  widget: new BlockGapWidget(height),
3121
3046
  block: true,
@@ -3180,74 +3105,27 @@ class BlockGapWidget extends WidgetType {
3180
3105
  }
3181
3106
  get estimatedHeight() { return this.height; }
3182
3107
  }
3183
- function findCompositionNode(view, dLen) {
3108
+ function findCompositionNode(view, headPos) {
3184
3109
  let sel = view.observer.selectionRange;
3185
3110
  let textNode = sel.focusNode && nearbyTextNode(sel.focusNode, sel.focusOffset, 0);
3186
3111
  if (!textNode)
3187
3112
  return null;
3188
- let cView = ContentView.get(textNode);
3189
- let from, to;
3190
- if (cView instanceof TextView) {
3191
- from = cView.posAtStart;
3192
- to = from + cView.length;
3193
- }
3194
- else {
3195
- let oldLen = Math.max(0, textNode.nodeValue.length - dLen);
3196
- up: for (let offset = 0, node = textNode;;) {
3197
- for (let sibling = node.previousSibling, cView; sibling; sibling = sibling.previousSibling) {
3198
- if (cView = ContentView.get(sibling)) {
3199
- to = cView.posAtEnd + offset;
3200
- from = Math.max(0, to - oldLen);
3201
- break up;
3202
- }
3203
- let reader = new DOMReader([], view.state);
3204
- reader.readNode(sibling);
3205
- if (reader.text.indexOf(LineBreakPlaceholder) > -1)
3206
- return null;
3207
- offset += reader.text.length;
3208
- }
3209
- node = node.parentNode;
3210
- if (!node)
3211
- return null;
3212
- let parentView = ContentView.get(node);
3213
- if (parentView) {
3214
- from = parentView.posAtStart + offset;
3215
- to = from + oldLen;
3216
- break;
3217
- }
3218
- }
3219
- }
3220
- return { from, to: to, node: textNode };
3113
+ let from = headPos - textNode.offset;
3114
+ return { from, to: from + textNode.node.nodeValue.length, node: textNode.node };
3221
3115
  }
3222
- function findCompositionRange(view, changes) {
3223
- let found = findCompositionNode(view, changes.newLength - changes.length);
3116
+ function findCompositionRange(view, changes, headPos) {
3117
+ let found = findCompositionNode(view, headPos);
3224
3118
  if (!found)
3225
3119
  return null;
3226
- let { from: fromA, to: toA, node: textNode } = found;
3227
- let fromB = changes.mapPos(fromA, -1), toB = changes.mapPos(toA, 1);
3228
- let text = textNode.nodeValue;
3120
+ let { node: textNode, from, to } = found, text = textNode.nodeValue;
3229
3121
  // Don't try to preserve multi-line compositions
3230
3122
  if (/[\n\r]/.test(text))
3231
3123
  return null;
3232
- if (toB - fromB != text.length) {
3233
- // If there is a length mismatch, see if mapping non-inclusively helps
3234
- let fromB2 = changes.mapPos(fromA, 1), toB2 = changes.mapPos(toA, -1);
3235
- if (toB2 - fromB2 == text.length)
3236
- fromB = fromB2, toB = toB2;
3237
- // See if we can find an instance of the text at either side
3238
- else if (view.state.doc.sliceString(toB - text.length, toB) == text)
3239
- fromB = toB - text.length;
3240
- else if (view.state.doc.sliceString(fromB, fromB + text.length) == text)
3241
- toB = fromB + text.length;
3242
- // Not found
3243
- else
3244
- return null;
3245
- }
3246
- let { main } = view.state.selection;
3247
- if (view.state.doc.sliceString(fromB, toB) != text || fromB > main.head || toB < main.head)
3124
+ if (view.state.doc.sliceString(found.from, found.to) != text)
3248
3125
  return null;
3126
+ let inv = changes.invertedDesc;
3127
+ let range = new ChangedRange(inv.mapPos(from), inv.mapPos(to), from, to);
3249
3128
  let marks = [];
3250
- let range = new ChangedRange(fromA, toA, fromB, toB);
3251
3129
  for (let parent = textNode.parentNode;; parent = parent.parentNode) {
3252
3130
  let parentView = ContentView.get(parent);
3253
3131
  if (parentView instanceof MarkView)
@@ -3268,7 +3146,7 @@ function nearbyTextNode(startNode, startOffset, side) {
3268
3146
  if (side <= 0)
3269
3147
  for (let node = startNode, offset = startOffset;;) {
3270
3148
  if (node.nodeType == 3)
3271
- return node;
3149
+ return { node: node, offset: offset };
3272
3150
  if (node.nodeType == 1 && offset > 0) {
3273
3151
  node = node.childNodes[offset - 1];
3274
3152
  offset = maxOffset(node);
@@ -3280,7 +3158,7 @@ function nearbyTextNode(startNode, startOffset, side) {
3280
3158
  if (side >= 0)
3281
3159
  for (let node = startNode, offset = startOffset;;) {
3282
3160
  if (node.nodeType == 3)
3283
- return node;
3161
+ return { node: node, offset: offset };
3284
3162
  if (node.nodeType == 1 && offset < node.childNodes.length && side >= 0) {
3285
3163
  node = node.childNodes[offset];
3286
3164
  offset = 0;
@@ -3317,6 +3195,15 @@ function inUneditable(node, inside) {
3317
3195
  }
3318
3196
  return false;
3319
3197
  }
3198
+ function touchesComposition(changes, composition) {
3199
+ let touched = false;
3200
+ if (composition)
3201
+ changes.iterChangedRanges((from, to) => {
3202
+ if (from < composition.to && to > composition.from)
3203
+ touched = true;
3204
+ });
3205
+ return touched;
3206
+ }
3320
3207
 
3321
3208
  function groupAt(state, pos, bias = 1) {
3322
3209
  let categorize = state.charCategorizer(pos);
@@ -5271,8 +5158,10 @@ class LineGap {
5271
5158
  }
5272
5159
  return true;
5273
5160
  }
5274
- draw(wrapping) {
5275
- return Decoration.replace({ widget: new LineGapWidget(this.size, wrapping) }).range(this.from, this.to);
5161
+ draw(viewState, wrapping) {
5162
+ return Decoration.replace({
5163
+ widget: new LineGapWidget(this.size * (wrapping ? viewState.scaleY : viewState.scaleX), wrapping)
5164
+ }).range(this.from, this.to);
5276
5165
  }
5277
5166
  }
5278
5167
  class LineGapWidget extends WidgetType {
@@ -5302,14 +5191,18 @@ class ViewState {
5302
5191
  // These are contentDOM-local coordinates
5303
5192
  this.pixelViewport = { left: 0, right: window.innerWidth, top: 0, bottom: 0 };
5304
5193
  this.inView = true;
5305
- this.paddingTop = 0;
5306
- this.paddingBottom = 0;
5307
- this.contentDOMWidth = 0;
5308
- this.contentDOMHeight = 0;
5309
- this.editorHeight = 0;
5310
- this.editorWidth = 0;
5311
- this.scrollTop = 0;
5194
+ this.paddingTop = 0; // Padding above the document, scaled
5195
+ this.paddingBottom = 0; // Padding below the document, scaled
5196
+ this.contentDOMWidth = 0; // contentDOM.getBoundingClientRect().width
5197
+ this.contentDOMHeight = 0; // contentDOM.getBoundingClientRect().height
5198
+ this.editorHeight = 0; // scrollDOM.clientHeight, unscaled
5199
+ this.editorWidth = 0; // scrollDOM.clientWidth, unscaled
5200
+ this.scrollTop = 0; // Last seen scrollDOM.scrollTop, scaled
5312
5201
  this.scrolledToBottom = true;
5202
+ // The CSS-transformation scale of the editor (transformed size /
5203
+ // concrete size)
5204
+ this.scaleX = 1;
5205
+ this.scaleY = 1;
5313
5206
  // The vertical position (document-relative) to which to anchor the
5314
5207
  // scroll position. -1 means anchor to the end of the document.
5315
5208
  this.scrollAnchorPos = 0;
@@ -5343,7 +5236,7 @@ class ViewState {
5343
5236
  this.updateViewportLines();
5344
5237
  this.updateForViewport();
5345
5238
  this.lineGaps = this.ensureLineGaps([]);
5346
- this.lineGapDeco = Decoration.set(this.lineGaps.map(gap => gap.draw(false)));
5239
+ this.lineGapDeco = Decoration.set(this.lineGaps.map(gap => gap.draw(this, false)));
5347
5240
  this.computeVisibleRanges();
5348
5241
  }
5349
5242
  updateForViewport() {
@@ -5415,8 +5308,23 @@ class ViewState {
5415
5308
  this.contentDOMHeight = domRect.height;
5416
5309
  this.mustMeasureContent = false;
5417
5310
  let result = 0, bias = 0;
5311
+ if (domRect.width && domRect.height) {
5312
+ let scaleX = domRect.width / dom.offsetWidth;
5313
+ let scaleY = domRect.height / dom.offsetHeight;
5314
+ if (scaleX > 0.995 && scaleX < 1.005)
5315
+ scaleX = 1;
5316
+ if (scaleY > 0.995 && scaleY < 1.005)
5317
+ scaleY = 1;
5318
+ if (this.scaleX != scaleX || this.scaleY != scaleY) {
5319
+ this.scaleX = scaleX;
5320
+ this.scaleY = scaleY;
5321
+ result |= 8 /* UpdateFlag.Geometry */;
5322
+ refresh = measureContent = true;
5323
+ }
5324
+ }
5418
5325
  // Vertical padding
5419
- let paddingTop = parseInt(style.paddingTop) || 0, paddingBottom = parseInt(style.paddingBottom) || 0;
5326
+ let paddingTop = (parseInt(style.paddingTop) || 0) * this.scaleY;
5327
+ let paddingBottom = (parseInt(style.paddingBottom) || 0) * this.scaleY;
5420
5328
  if (this.paddingTop != paddingTop || this.paddingBottom != paddingBottom) {
5421
5329
  this.paddingTop = paddingTop;
5422
5330
  this.paddingBottom = paddingBottom;
@@ -5428,9 +5336,10 @@ class ViewState {
5428
5336
  this.editorWidth = view.scrollDOM.clientWidth;
5429
5337
  result |= 8 /* UpdateFlag.Geometry */;
5430
5338
  }
5431
- if (this.scrollTop != view.scrollDOM.scrollTop) {
5339
+ let scrollTop = view.scrollDOM.scrollTop * this.scaleY;
5340
+ if (this.scrollTop != scrollTop) {
5432
5341
  this.scrollAnchorHeight = -1;
5433
- this.scrollTop = view.scrollDOM.scrollTop;
5342
+ this.scrollTop = scrollTop;
5434
5343
  }
5435
5344
  this.scrolledToBottom = isScrolledToBottom(view.scrollDOM);
5436
5345
  // Pixel viewport
@@ -5651,7 +5560,7 @@ class ViewState {
5651
5560
  updateLineGaps(gaps) {
5652
5561
  if (!LineGap.same(gaps, this.lineGaps)) {
5653
5562
  this.lineGaps = gaps;
5654
- this.lineGapDeco = Decoration.set(gaps.map(gap => gap.draw(this.heightOracle.lineWrapping)));
5563
+ this.lineGapDeco = Decoration.set(gaps.map(gap => gap.draw(this, this.heightOracle.lineWrapping)));
5655
5564
  }
5656
5565
  }
5657
5566
  computeVisibleRanges() {
@@ -6052,6 +5961,113 @@ const baseTheme$1 = /*@__PURE__*/buildTheme("." + baseThemeID, {
6052
5961
  }
6053
5962
  }, lightDarkIDs);
6054
5963
 
5964
+ const LineBreakPlaceholder = "\uffff";
5965
+ class DOMReader {
5966
+ constructor(points, state) {
5967
+ this.points = points;
5968
+ this.text = "";
5969
+ this.lineSeparator = state.facet(EditorState.lineSeparator);
5970
+ }
5971
+ append(text) {
5972
+ this.text += text;
5973
+ }
5974
+ lineBreak() {
5975
+ this.text += LineBreakPlaceholder;
5976
+ }
5977
+ readRange(start, end) {
5978
+ if (!start)
5979
+ return this;
5980
+ let parent = start.parentNode;
5981
+ for (let cur = start;;) {
5982
+ this.findPointBefore(parent, cur);
5983
+ let oldLen = this.text.length;
5984
+ this.readNode(cur);
5985
+ let next = cur.nextSibling;
5986
+ if (next == end)
5987
+ break;
5988
+ let view = ContentView.get(cur), nextView = ContentView.get(next);
5989
+ if (view && nextView ? view.breakAfter :
5990
+ (view ? view.breakAfter : isBlockElement(cur)) ||
5991
+ (isBlockElement(next) && (cur.nodeName != "BR" || cur.cmIgnore) && this.text.length > oldLen))
5992
+ this.lineBreak();
5993
+ cur = next;
5994
+ }
5995
+ this.findPointBefore(parent, end);
5996
+ return this;
5997
+ }
5998
+ readTextNode(node) {
5999
+ let text = node.nodeValue;
6000
+ for (let point of this.points)
6001
+ if (point.node == node)
6002
+ point.pos = this.text.length + Math.min(point.offset, text.length);
6003
+ for (let off = 0, re = this.lineSeparator ? null : /\r\n?|\n/g;;) {
6004
+ let nextBreak = -1, breakSize = 1, m;
6005
+ if (this.lineSeparator) {
6006
+ nextBreak = text.indexOf(this.lineSeparator, off);
6007
+ breakSize = this.lineSeparator.length;
6008
+ }
6009
+ else if (m = re.exec(text)) {
6010
+ nextBreak = m.index;
6011
+ breakSize = m[0].length;
6012
+ }
6013
+ this.append(text.slice(off, nextBreak < 0 ? text.length : nextBreak));
6014
+ if (nextBreak < 0)
6015
+ break;
6016
+ this.lineBreak();
6017
+ if (breakSize > 1)
6018
+ for (let point of this.points)
6019
+ if (point.node == node && point.pos > this.text.length)
6020
+ point.pos -= breakSize - 1;
6021
+ off = nextBreak + breakSize;
6022
+ }
6023
+ }
6024
+ readNode(node) {
6025
+ if (node.cmIgnore)
6026
+ return;
6027
+ let view = ContentView.get(node);
6028
+ let fromView = view && view.overrideDOMText;
6029
+ if (fromView != null) {
6030
+ this.findPointInside(node, fromView.length);
6031
+ for (let i = fromView.iter(); !i.next().done;) {
6032
+ if (i.lineBreak)
6033
+ this.lineBreak();
6034
+ else
6035
+ this.append(i.value);
6036
+ }
6037
+ }
6038
+ else if (node.nodeType == 3) {
6039
+ this.readTextNode(node);
6040
+ }
6041
+ else if (node.nodeName == "BR") {
6042
+ if (node.nextSibling)
6043
+ this.lineBreak();
6044
+ }
6045
+ else if (node.nodeType == 1) {
6046
+ this.readRange(node.firstChild, null);
6047
+ }
6048
+ }
6049
+ findPointBefore(node, next) {
6050
+ for (let point of this.points)
6051
+ if (point.node == node && node.childNodes[point.offset] == next)
6052
+ point.pos = this.text.length;
6053
+ }
6054
+ findPointInside(node, maxLen) {
6055
+ for (let point of this.points)
6056
+ if (node.nodeType == 3 ? point.node == node : node.contains(point.node))
6057
+ point.pos = this.text.length + Math.min(maxLen, point.offset);
6058
+ }
6059
+ }
6060
+ function isBlockElement(node) {
6061
+ return node.nodeType == 1 && /^(DIV|P|LI|UL|OL|BLOCKQUOTE|DD|DT|H\d|SECTION|PRE)$/.test(node.nodeName);
6062
+ }
6063
+ class DOMPoint {
6064
+ constructor(node, offset) {
6065
+ this.node = node;
6066
+ this.offset = offset;
6067
+ this.pos = -1;
6068
+ }
6069
+ }
6070
+
6055
6071
  class DOMChange {
6056
6072
  constructor(view, start, end, typeOver) {
6057
6073
  this.typeOver = typeOver;
@@ -6202,8 +6218,14 @@ function applyDefaultInsert(view, change, newSel) {
6202
6218
  if (startState.selection.ranges.length > 1 && view.inputState.composing >= 0 &&
6203
6219
  change.to <= sel.to && change.to >= sel.to - 10) {
6204
6220
  let replaced = view.state.sliceDoc(change.from, change.to);
6205
- let composition = findCompositionNode(view, change.insert.length - (change.to - change.from)) ||
6206
- view.state.doc.lineAt(sel.head);
6221
+ let compositionRange, composition = newSel && findCompositionNode(view, newSel.main.head);
6222
+ if (composition) {
6223
+ let dLen = change.insert.length - (change.to - change.from);
6224
+ compositionRange = { from: composition.from, to: composition.to - dLen };
6225
+ }
6226
+ else {
6227
+ compositionRange = view.state.doc.lineAt(sel.head);
6228
+ }
6207
6229
  let offset = sel.to - change.to, size = sel.to - sel.from;
6208
6230
  tr = startState.changeByRange(range => {
6209
6231
  if (range.from == sel.from && range.to == sel.to)
@@ -6214,7 +6236,7 @@ function applyDefaultInsert(view, change, newSel) {
6214
6236
  // changes in the same node work without aborting
6215
6237
  // composition, so cursors in the composition range are
6216
6238
  // ignored.
6217
- composition && range.to >= composition.from && range.from <= composition.to)
6239
+ range.to >= compositionRange.from && range.from <= compositionRange.to)
6218
6240
  return { range };
6219
6241
  let rangeChanges = startState.changes({ from, to, insert: change.insert }), selOff = range.to - sel.to;
6220
6242
  return {
@@ -6633,7 +6655,9 @@ class DOMObserver {
6633
6655
  this.lastChange = Date.now();
6634
6656
  this.view.inputState.lastFocusTime = 0;
6635
6657
  this.selectionChanged = false;
6636
- return new DOMChange(this.view, from, to, typeOver);
6658
+ let change = new DOMChange(this.view, from, to, typeOver);
6659
+ this.view.docView.domChanged = { newSel: change.newSel ? change.newSel.main : null };
6660
+ return change;
6637
6661
  }
6638
6662
  // Apply pending changes, if any
6639
6663
  flush(readSelection = true) {
@@ -7062,9 +7086,9 @@ class EditorView {
7062
7086
  if (flush)
7063
7087
  this.observer.forceFlush();
7064
7088
  let updated = null;
7065
- let sDOM = this.scrollDOM, { scrollTop } = sDOM;
7089
+ let sDOM = this.scrollDOM, scrollTop = sDOM.scrollTop * this.scaleY;
7066
7090
  let { scrollAnchorPos, scrollAnchorHeight } = this.viewState;
7067
- if (scrollTop != this.viewState.scrollTop)
7091
+ if (Math.abs(scrollTop - this.viewState.scrollTop) > 1)
7068
7092
  scrollAnchorHeight = -1;
7069
7093
  this.viewState.scrollAnchorHeight = -1;
7070
7094
  try {
@@ -7141,7 +7165,8 @@ class EditorView {
7141
7165
  this.viewState.lineBlockAt(scrollAnchorPos).top;
7142
7166
  let diff = newAnchorHeight - scrollAnchorHeight;
7143
7167
  if (diff > 1 || diff < -1) {
7144
- scrollTop = sDOM.scrollTop = scrollTop + diff;
7168
+ scrollTop = scrollTop + diff;
7169
+ sDOM.scrollTop = scrollTop / this.scaleY;
7145
7170
  scrollAnchorHeight = -1;
7146
7171
  continue;
7147
7172
  }
@@ -7268,6 +7293,16 @@ class EditorView {
7268
7293
  return { top: this.viewState.paddingTop, bottom: this.viewState.paddingBottom };
7269
7294
  }
7270
7295
  /**
7296
+ If the editor is transformed with CSS, this provides the scale
7297
+ along the X axis. Otherwise, it will just be 1. Note that
7298
+ transforms other than translation and scaling are not supported.
7299
+ */
7300
+ get scaleX() { return this.viewState.scaleX; }
7301
+ /**
7302
+ Provide the CSS transformed scale along the Y axis.
7303
+ */
7304
+ get scaleY() { return this.viewState.scaleY; }
7305
+ /**
7271
7306
  Find the text line or block widget at the given vertical
7272
7307
  position (which is interpreted as relative to the [top of the
7273
7308
  document](https://codemirror.net/6/docs/ref/#view.EditorView.documentTop)).
@@ -8058,8 +8093,8 @@ class RectangleMarker {
8058
8093
  }
8059
8094
  function getBase(view) {
8060
8095
  let rect = view.scrollDOM.getBoundingClientRect();
8061
- let left = view.textDirection == Direction.LTR ? rect.left : rect.right - view.scrollDOM.clientWidth;
8062
- return { left: left - view.scrollDOM.scrollLeft, top: rect.top - view.scrollDOM.scrollTop };
8096
+ let left = view.textDirection == Direction.LTR ? rect.left : rect.right - view.scrollDOM.clientWidth * view.scaleX;
8097
+ return { left: left - view.scrollDOM.scrollLeft * view.scaleX, top: rect.top - view.scrollDOM.scrollTop * view.scaleY };
8063
8098
  }
8064
8099
  function wrappedLine(view, pos, inside) {
8065
8100
  let range = EditorSelection.cursor(pos);
@@ -8161,6 +8196,8 @@ class LayerView {
8161
8196
  this.view = view;
8162
8197
  this.layer = layer;
8163
8198
  this.drawn = [];
8199
+ this.scaleX = 1;
8200
+ this.scaleY = 1;
8164
8201
  this.measureReq = { read: this.measure.bind(this), write: this.draw.bind(this) };
8165
8202
  this.dom = view.scrollDOM.appendChild(document.createElement("div"));
8166
8203
  this.dom.classList.add("cm-layer");
@@ -8168,6 +8205,7 @@ class LayerView {
8168
8205
  this.dom.classList.add("cm-layer-above");
8169
8206
  if (layer.class)
8170
8207
  this.dom.classList.add(layer.class);
8208
+ this.scale();
8171
8209
  this.dom.setAttribute("aria-hidden", "true");
8172
8210
  this.setOrder(view.state);
8173
8211
  view.requestMeasure(this.measureReq);
@@ -8177,8 +8215,10 @@ class LayerView {
8177
8215
  update(update) {
8178
8216
  if (update.startState.facet(layerOrder) != update.state.facet(layerOrder))
8179
8217
  this.setOrder(update.state);
8180
- if (this.layer.update(update, this.dom) || update.geometryChanged)
8218
+ if (this.layer.update(update, this.dom) || update.geometryChanged) {
8219
+ this.scale();
8181
8220
  update.view.requestMeasure(this.measureReq);
8221
+ }
8182
8222
  }
8183
8223
  setOrder(state) {
8184
8224
  let pos = 0, order = state.facet(layerOrder);
@@ -8189,6 +8229,14 @@ class LayerView {
8189
8229
  measure() {
8190
8230
  return this.layer.markers(this.view);
8191
8231
  }
8232
+ scale() {
8233
+ let { scaleX, scaleY } = this.view;
8234
+ if (scaleX != this.scaleX || scaleY != this.scaleY) {
8235
+ this.scaleX = scaleX;
8236
+ this.scaleY = scaleY;
8237
+ this.dom.style.transform = `scale(${1 / scaleX}, ${1 / scaleY})`;
8238
+ }
8239
+ }
8192
8240
  draw(markers) {
8193
8241
  if (markers.length != this.drawn.length || markers.some((p, i) => !sameMarker(p, this.drawn[i]))) {
8194
8242
  let old = this.dom.firstChild, oldI = 0;
@@ -8358,23 +8406,25 @@ const drawDropCursor = /*@__PURE__*/ViewPlugin.fromClass(class {
8358
8406
  }
8359
8407
  }
8360
8408
  readPos() {
8361
- let pos = this.view.state.field(dropCursorPos);
8362
- let rect = pos != null && this.view.coordsAtPos(pos);
8409
+ let { view } = this;
8410
+ let pos = view.state.field(dropCursorPos);
8411
+ let rect = pos != null && view.coordsAtPos(pos);
8363
8412
  if (!rect)
8364
8413
  return null;
8365
- let outer = this.view.scrollDOM.getBoundingClientRect();
8414
+ let outer = view.scrollDOM.getBoundingClientRect();
8366
8415
  return {
8367
- left: rect.left - outer.left + this.view.scrollDOM.scrollLeft,
8368
- top: rect.top - outer.top + this.view.scrollDOM.scrollTop,
8416
+ left: rect.left - outer.left + view.scrollDOM.scrollLeft * view.scaleX,
8417
+ top: rect.top - outer.top + view.scrollDOM.scrollTop * view.scaleY,
8369
8418
  height: rect.bottom - rect.top
8370
8419
  };
8371
8420
  }
8372
8421
  drawCursor(pos) {
8373
8422
  if (this.cursor) {
8423
+ let { scaleX, scaleY } = this.view;
8374
8424
  if (pos) {
8375
- this.cursor.style.left = pos.left + "px";
8376
- this.cursor.style.top = pos.top + "px";
8377
- this.cursor.style.height = pos.height + "px";
8425
+ this.cursor.style.left = pos.left / scaleX + "px";
8426
+ this.cursor.style.top = pos.top / scaleY + "px";
8427
+ this.cursor.style.height = pos.height / scaleY + "px";
8378
8428
  }
8379
8429
  else {
8380
8430
  this.cursor.style.left = "-100000px";
@@ -8616,7 +8666,9 @@ function specialCharPlugin() {
8616
8666
  if (code == 9) {
8617
8667
  let line = doc.lineAt(pos);
8618
8668
  let size = view.state.tabSize, col = countColumn(line.text, size, pos - line.from);
8619
- return Decoration.replace({ widget: new TabWidget((size - (col % size)) * this.view.defaultCharacterWidth) });
8669
+ return Decoration.replace({
8670
+ widget: new TabWidget((size - (col % size)) * this.view.defaultCharacterWidth / this.view.scaleX)
8671
+ });
8620
8672
  }
8621
8673
  return this.decorationCache[code] ||
8622
8674
  (this.decorationCache[code] = Decoration.replace({ widget: new SpecialCharWidget(conf, code) }));
@@ -8693,7 +8745,8 @@ const plugin = /*@__PURE__*/ViewPlugin.fromClass(class {
8693
8745
  }
8694
8746
  update(update) {
8695
8747
  let { view } = update;
8696
- let height = view.viewState.editorHeight - view.defaultLineHeight - view.documentPadding.top - 0.5;
8748
+ let height = view.viewState.editorHeight * view.scaleY -
8749
+ view.defaultLineHeight - view.documentPadding.top - 0.5;
8697
8750
  if (height >= 0 && height != this.height) {
8698
8751
  this.height = height;
8699
8752
  this.attrs = { style: `padding-bottom: ${height}px` };
@@ -8990,6 +9043,7 @@ const tooltipPlugin = /*@__PURE__*/ViewPlugin.fromClass(class {
8990
9043
  constructor(view) {
8991
9044
  this.view = view;
8992
9045
  this.inView = true;
9046
+ this.madeAbsolute = false;
8993
9047
  this.lastTransaction = 0;
8994
9048
  this.measureTimeout = -1;
8995
9049
  let config = view.state.facet(tooltipConfig);
@@ -9041,7 +9095,7 @@ const tooltipPlugin = /*@__PURE__*/ViewPlugin.fromClass(class {
9041
9095
  this.observeIntersection();
9042
9096
  let shouldMeasure = updated || update.geometryChanged;
9043
9097
  let newConfig = update.state.facet(tooltipConfig);
9044
- if (newConfig.position != this.position) {
9098
+ if (newConfig.position != this.position && !this.madeAbsolute) {
9045
9099
  this.position = newConfig.position;
9046
9100
  for (let t of this.manager.tooltipViews)
9047
9101
  t.dom.style.position = this.position;
@@ -9089,6 +9143,27 @@ const tooltipPlugin = /*@__PURE__*/ViewPlugin.fromClass(class {
9089
9143
  }
9090
9144
  readMeasure() {
9091
9145
  let editor = this.view.dom.getBoundingClientRect();
9146
+ let scaleX = 1, scaleY = 1, makeAbsolute = false;
9147
+ if (this.position == "fixed") {
9148
+ let views = this.manager.tooltipViews;
9149
+ // When the dialog's offset parent isn't the body, we are
9150
+ // probably in a transformed container, and should use absolute
9151
+ // positioning instead, since fixed positioning inside a
9152
+ // transform works in a very broken way.
9153
+ makeAbsolute = views.length > 0 && views[0].dom.offsetParent != this.container.ownerDocument.body;
9154
+ }
9155
+ if (makeAbsolute || this.position == "absolute") {
9156
+ if (this.parent) {
9157
+ let rect = this.parent.getBoundingClientRect();
9158
+ if (rect.width && rect.height) {
9159
+ scaleX = rect.width / this.parent.offsetWidth;
9160
+ scaleY = rect.height / this.parent.offsetHeight;
9161
+ }
9162
+ }
9163
+ else {
9164
+ ({ scaleX, scaleY } = this.view.viewState);
9165
+ }
9166
+ }
9092
9167
  return {
9093
9168
  editor,
9094
9169
  parent: this.parent ? this.container.getBoundingClientRect() : editor,
@@ -9098,11 +9173,18 @@ const tooltipPlugin = /*@__PURE__*/ViewPlugin.fromClass(class {
9098
9173
  }),
9099
9174
  size: this.manager.tooltipViews.map(({ dom }) => dom.getBoundingClientRect()),
9100
9175
  space: this.view.state.facet(tooltipConfig).tooltipSpace(this.view),
9176
+ scaleX, scaleY, makeAbsolute
9101
9177
  };
9102
9178
  }
9103
9179
  writeMeasure(measured) {
9104
9180
  var _a;
9105
- let { editor, space } = measured;
9181
+ if (measured.makeAbsolute) {
9182
+ this.madeAbsolute = true;
9183
+ this.position = "absolute";
9184
+ for (let t of this.manager.tooltipViews)
9185
+ t.dom.style.position = "absolute";
9186
+ }
9187
+ let { editor, space, scaleX, scaleY } = measured;
9106
9188
  let others = [];
9107
9189
  for (let i = 0; i < this.manager.tooltips.length; i++) {
9108
9190
  let tooltip = this.manager.tooltips[i], tView = this.manager.tooltipViews[i], { dom } = tView;
@@ -9135,7 +9217,7 @@ const tooltipPlugin = /*@__PURE__*/ViewPlugin.fromClass(class {
9135
9217
  continue;
9136
9218
  }
9137
9219
  knownHeight.set(tView, height);
9138
- dom.style.height = (height = spaceVert) + "px";
9220
+ dom.style.height = (height = spaceVert) / scaleY + "px";
9139
9221
  }
9140
9222
  else if (dom.style.height) {
9141
9223
  dom.style.height = "";
@@ -9147,15 +9229,17 @@ const tooltipPlugin = /*@__PURE__*/ViewPlugin.fromClass(class {
9147
9229
  if (r.left < right && r.right > left && r.top < top + height && r.bottom > top)
9148
9230
  top = above ? r.top - height - 2 - arrowHeight : r.bottom + arrowHeight + 2;
9149
9231
  if (this.position == "absolute") {
9150
- dom.style.top = (top - measured.parent.top) + "px";
9151
- dom.style.left = (left - measured.parent.left) + "px";
9232
+ dom.style.top = (top - measured.parent.top) / scaleY + "px";
9233
+ dom.style.left = (left - measured.parent.left) / scaleX + "px";
9152
9234
  }
9153
9235
  else {
9154
- dom.style.top = top + "px";
9155
- dom.style.left = left + "px";
9236
+ dom.style.top = top / scaleY + "px";
9237
+ dom.style.left = left / scaleX + "px";
9238
+ }
9239
+ if (arrow) {
9240
+ let arrowLeft = pos.left + (ltr ? offset.x : -offset.x) - (left + 14 /* Arrow.Offset */ - 7 /* Arrow.Size */);
9241
+ arrow.style.left = arrowLeft / scaleX + "px";
9156
9242
  }
9157
- if (arrow)
9158
- arrow.style.left = `${pos.left + (ltr ? offset.x : -offset.x) - (left + 14 /* Arrow.Offset */ - 7 /* Arrow.Size */)}px`;
9159
9243
  if (tView.overlap !== true)
9160
9244
  others.push({ left, top, right, bottom: top + height });
9161
9245
  dom.classList.toggle("cm-tooltip-above", above);
@@ -9757,7 +9841,7 @@ const gutterView = /*@__PURE__*/ViewPlugin.fromClass(class {
9757
9841
  this.dom = document.createElement("div");
9758
9842
  this.dom.className = "cm-gutters";
9759
9843
  this.dom.setAttribute("aria-hidden", "true");
9760
- this.dom.style.minHeight = this.view.contentHeight + "px";
9844
+ this.dom.style.minHeight = (this.view.contentHeight / this.view.scaleY) + "px";
9761
9845
  this.gutters = view.state.facet(activeGutters).map(conf => new SingleGutterView(view, conf));
9762
9846
  for (let gutter of this.gutters)
9763
9847
  this.dom.appendChild(gutter.dom);
@@ -9818,6 +9902,10 @@ const gutterView = /*@__PURE__*/ViewPlugin.fromClass(class {
9818
9902
  for (let cx of contexts)
9819
9903
  cx.line(this.view, line, classSet);
9820
9904
  }
9905
+ else if (line.widget) {
9906
+ for (let cx of contexts)
9907
+ cx.widget(this.view, line);
9908
+ }
9821
9909
  }
9822
9910
  for (let cx of contexts)
9823
9911
  cx.finish();
@@ -9867,7 +9955,9 @@ const gutterView = /*@__PURE__*/ViewPlugin.fromClass(class {
9867
9955
  let value = view.plugin(plugin);
9868
9956
  if (!value || value.gutters.length == 0 || !value.fixed)
9869
9957
  return null;
9870
- return view.textDirection == Direction.LTR ? { left: value.dom.offsetWidth } : { right: value.dom.offsetWidth };
9958
+ return view.textDirection == Direction.LTR
9959
+ ? { left: value.dom.offsetWidth * view.scaleX }
9960
+ : { right: value.dom.offsetWidth * view.scaleX };
9871
9961
  })
9872
9962
  });
9873
9963
  function asArray(val) { return (Array.isArray(val) ? val : [val]); }
@@ -9984,10 +10074,12 @@ class GutterElement {
9984
10074
  this.update(view, height, above, markers);
9985
10075
  }
9986
10076
  update(view, height, above, markers) {
9987
- if (this.height != height)
9988
- this.dom.style.height = (this.height = height) + "px";
10077
+ if (this.height != height) {
10078
+ this.height = height;
10079
+ this.dom.style.height = height / view.scaleY + "px";
10080
+ }
9989
10081
  if (this.above != above)
9990
- this.dom.style.marginTop = (this.above = above) ? above + "px" : "";
10082
+ this.dom.style.marginTop = (this.above = above) ? above / view.scaleY + "px" : "";
9991
10083
  if (!sameMarkers(this.markers, markers))
9992
10084
  this.setMarkers(view, markers);
9993
10085
  }