@codemirror/view 0.19.24 → 0.19.25

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,17 @@
1
+ ## 0.19.25 (2021-12-02)
2
+
3
+ ### Bug fixes
4
+
5
+ Widgets around replaced ranges are now visible when their side does not point towards the replaced range.
6
+
7
+ A replaced line with a line decoration no longer creates an extra empty line block in the editor.
8
+
9
+ The `scrollPastEnd` extension will now over-reserve space at the bottom of the editor on startup, to prevent restored scroll positions from being clipped.
10
+
11
+ ### New features
12
+
13
+ `EditorView.editorAttributes` and `contentAttributes` may now hold functions that produce the attributes.
14
+
1
15
  ## 0.19.24 (2021-12-01)
2
16
 
3
17
  ### Bug fixes
package/dist/index.cjs CHANGED
@@ -1086,8 +1086,9 @@ class Decoration extends rangeset.RangeValue {
1086
1086
  position.
1087
1087
  */
1088
1088
  static widget(spec) {
1089
- let side = spec.side || 0;
1090
- return new PointDecoration(spec, side, side, !!spec.block, spec.widget || null, false);
1089
+ let side = spec.side || 0, block = !!spec.block;
1090
+ side += block ? (side > 0 ? 300000000 /* BlockAfter */ : -400000000 /* BlockBefore */) : (side > 0 ? 100000000 /* InlineAfter */ : -100000000 /* InlineBefore */);
1091
+ return new PointDecoration(spec, side, side, block, spec.widget || null, false);
1091
1092
  }
1092
1093
  /**
1093
1094
  Create a replace decoration which replaces the given range with
@@ -1096,8 +1097,8 @@ class Decoration extends rangeset.RangeValue {
1096
1097
  static replace(spec) {
1097
1098
  let block = !!spec.block;
1098
1099
  let { start, end } = getInclusive(spec, block);
1099
- let startSide = 100000000 /* Big */ * (start ? -1 : 1) * (block ? 2 : 1);
1100
- let endSide = 100000000 /* Big */ * (end ? 1 : -1) * (block ? 2 : 1);
1100
+ let startSide = block ? (start ? -300000000 /* BlockIncStart */ : -1 /* InlineIncStart */) : 400000000 /* NonIncStart */;
1101
+ let endSide = block ? (end ? 200000000 /* BlockIncEnd */ : 1 /* InlineIncEnd */) : -500000000 /* NonIncEnd */;
1101
1102
  return new PointDecoration(spec, startSide, endSide, block, spec.widget || null, true);
1102
1103
  }
1103
1104
  /**
@@ -1127,7 +1128,7 @@ Decoration.none = rangeset.RangeSet.empty;
1127
1128
  class MarkDecoration extends Decoration {
1128
1129
  constructor(spec) {
1129
1130
  let { start, end } = getInclusive(spec);
1130
- super(100000000 /* Big */ * (start ? -1 : 1), 100000000 /* Big */ * (end ? 1 : -1), null, spec);
1131
+ super(start ? -1 /* InlineIncStart */ : 400000000 /* NonIncStart */, end ? 1 /* InlineIncEnd */ : -500000000 /* NonIncEnd */, null, spec);
1131
1132
  this.tagName = spec.tagName || "span";
1132
1133
  this.class = spec.class || "";
1133
1134
  this.attrs = spec.attributes || null;
@@ -1148,7 +1149,7 @@ class MarkDecoration extends Decoration {
1148
1149
  MarkDecoration.prototype.point = false;
1149
1150
  class LineDecoration extends Decoration {
1150
1151
  constructor(spec) {
1151
- super(-100000000 /* Big */, -100000000 /* Big */, null, spec);
1152
+ super(-200000000 /* Line */, -200000000 /* Line */, null, spec);
1152
1153
  }
1153
1154
  eq(other) {
1154
1155
  return other instanceof LineDecoration && attrsEq(this.spec.attributes, other.spec.attributes);
@@ -1727,36 +1728,39 @@ class PluginInstance {
1727
1728
  this.value = null;
1728
1729
  }
1729
1730
  takeField(type, target) {
1730
- for (let { field, get } of this.spec.fields)
1731
- if (field == type)
1732
- target.push(get(this.value));
1731
+ if (this.spec)
1732
+ for (let { field, get } of this.spec.fields)
1733
+ if (field == type)
1734
+ target.push(get(this.value));
1733
1735
  }
1734
1736
  update(view) {
1735
1737
  if (!this.value) {
1736
- try {
1737
- this.value = this.spec.create(view);
1738
- }
1739
- catch (e) {
1740
- logException(view.state, e, "CodeMirror plugin crashed");
1741
- return PluginInstance.dummy;
1738
+ if (this.spec) {
1739
+ try {
1740
+ this.value = this.spec.create(view);
1741
+ }
1742
+ catch (e) {
1743
+ logException(view.state, e, "CodeMirror plugin crashed");
1744
+ this.deactivate();
1745
+ }
1742
1746
  }
1743
1747
  }
1744
1748
  else if (this.mustUpdate) {
1745
1749
  let update = this.mustUpdate;
1746
1750
  this.mustUpdate = null;
1747
- if (!this.value.update)
1748
- return this;
1749
- try {
1750
- this.value.update(update);
1751
- }
1752
- catch (e) {
1753
- logException(update.state, e, "CodeMirror plugin crashed");
1754
- if (this.value.destroy)
1755
- try {
1756
- this.value.destroy();
1757
- }
1758
- catch (_) { }
1759
- return PluginInstance.dummy;
1751
+ if (this.value.update) {
1752
+ try {
1753
+ this.value.update(update);
1754
+ }
1755
+ catch (e) {
1756
+ logException(update.state, e, "CodeMirror plugin crashed");
1757
+ if (this.value.destroy)
1758
+ try {
1759
+ this.value.destroy();
1760
+ }
1761
+ catch (_) { }
1762
+ this.deactivate();
1763
+ }
1760
1764
  }
1761
1765
  }
1762
1766
  return this;
@@ -1772,20 +1776,12 @@ class PluginInstance {
1772
1776
  }
1773
1777
  }
1774
1778
  }
1779
+ deactivate() {
1780
+ this.spec = this.value = null;
1781
+ }
1775
1782
  }
1776
- PluginInstance.dummy = new PluginInstance(ViewPlugin.define(() => ({})));
1777
- function combineFacetAttrs(values) {
1778
- let result = {};
1779
- for (let i = values.length - 1; i >= 0; i--)
1780
- combineAttrs(values[i], result);
1781
- return result;
1782
- }
1783
- const editorAttributes = state.Facet.define({
1784
- combine: combineFacetAttrs
1785
- });
1786
- const contentAttributes = state.Facet.define({
1787
- combine: combineFacetAttrs
1788
- });
1783
+ const editorAttributes = state.Facet.define();
1784
+ const contentAttributes = state.Facet.define();
1789
1785
  // Provide decorations
1790
1786
  const decorations = state.Facet.define();
1791
1787
  const styleModule = state.Facet.define();
@@ -1933,12 +1929,12 @@ class DocView extends ContentView {
1933
1929
  this.compositionDeco = Decoration.none;
1934
1930
  this.decorations = [];
1935
1931
  // Track a minimum width for the editor. When measuring sizes in
1936
- // checkLayout, this is updated to point at the width of a given
1937
- // element and its extent in the document. When a change happens in
1938
- // that range, these are reset. That way, once we've seen a
1939
- // line/element of a given length, we keep the editor wide enough to
1940
- // fit at least that element, until it is changed, at which point we
1941
- // forget it again.
1932
+ // measureVisibleLineHeights, this is updated to point at the width
1933
+ // of a given element and its extent in the document. When a change
1934
+ // happens in that range, these are reset. That way, once we've seen
1935
+ // a line/element of a given length, we keep the editor wide enough
1936
+ // to fit at least that element, until it is changed, at which point
1937
+ // we forget it again.
1942
1938
  this.minWidth = 0;
1943
1939
  this.minWidthFrom = 0;
1944
1940
  this.minWidthTo = 0;
@@ -2008,7 +2004,7 @@ class DocView extends ContentView {
2008
2004
  this.updateSelection();
2009
2005
  }
2010
2006
  }
2011
- // Used both by update and checkLayout do perform the actual DOM
2007
+ // Used by update and the constructor do perform the actual DOM
2012
2008
  // update
2013
2009
  updateInner(changes, deco, oldLength) {
2014
2010
  this.view.viewState.mustMeasureContent = true;
@@ -2931,7 +2927,7 @@ function posAtCoords(view, { x, y }, precise, bias = -1) {
2931
2927
  y = docTop + yOffset;
2932
2928
  let lineStart = block.from;
2933
2929
  // Clip x to the viewport sides
2934
- x = Math.max(content.left + 1, Math.min(content.right - 1, x));
2930
+ x = Math.max(content.left + 1, Math.min(Math.max(content.right, content.left + view.docView.minWidth) - 1, x));
2935
2931
  // If this is outside of the rendered viewport, we can't determine a position
2936
2932
  if (lineStart < view.viewport.from)
2937
2933
  return view.viewport.from == 0 ? 0 : posAtCoordsImprecise(view, content, block, x, y);
@@ -5065,7 +5061,7 @@ const baseTheme = buildTheme("." + baseThemeID, {
5065
5061
  color: "inherit",
5066
5062
  fontSize: "70%",
5067
5063
  padding: ".2em 1em",
5068
- borderRadius: "3px"
5064
+ borderRadius: "1px"
5069
5065
  },
5070
5066
  "&light .cm-button": {
5071
5067
  backgroundImage: "linear-gradient(#eff1f5, #d9d9df)",
@@ -5387,6 +5383,7 @@ class DOMObserver {
5387
5383
  for (let dom of this.scrollTargets)
5388
5384
  dom.removeEventListener("scroll", this.onScroll);
5389
5385
  window.removeEventListener("scroll", this.onScroll);
5386
+ this.dom.ownerDocument.removeEventListener("selectionchange", this.onSelectionChange);
5390
5387
  clearTimeout(this.parentCheck);
5391
5388
  clearTimeout(this.resizeTimeout);
5392
5389
  }
@@ -5683,6 +5680,7 @@ class EditorView {
5683
5680
  */
5684
5681
  config = {}) {
5685
5682
  this.plugins = [];
5683
+ this.pluginMap = new Map;
5686
5684
  this.editorAttrs = {};
5687
5685
  this.contentAttrs = {};
5688
5686
  this.bidiCache = [];
@@ -5852,6 +5850,7 @@ class EditorView {
5852
5850
  plugin.destroy(this);
5853
5851
  this.viewState = new ViewState(newState);
5854
5852
  this.plugins = newState.facet(viewPlugin).map(spec => new PluginInstance(spec).update(this));
5853
+ this.pluginMap.clear();
5855
5854
  this.docView = new DocView(this);
5856
5855
  this.inputState.ensureHandlers(this);
5857
5856
  this.mountStyles();
@@ -5882,6 +5881,7 @@ class EditorView {
5882
5881
  if (plugin.mustUpdate != update)
5883
5882
  plugin.destroy(this);
5884
5883
  this.plugins = newPlugins;
5884
+ this.pluginMap.clear();
5885
5885
  this.inputState.ensureHandlers(this);
5886
5886
  }
5887
5887
  else {
@@ -5889,7 +5889,7 @@ class EditorView {
5889
5889
  p.mustUpdate = update;
5890
5890
  }
5891
5891
  for (let i = 0; i < this.plugins.length; i++)
5892
- this.plugins[i] = this.plugins[i].update(this);
5892
+ this.plugins[i].update(this);
5893
5893
  }
5894
5894
  /**
5895
5895
  @internal
@@ -5978,7 +5978,7 @@ class EditorView {
5978
5978
  this.state.facet(theme);
5979
5979
  }
5980
5980
  updateAttrs() {
5981
- let editorAttrs = combineAttrs(this.state.facet(editorAttributes), {
5981
+ let editorAttrs = attrsFromFacet(this, editorAttributes, {
5982
5982
  class: "cm-editor" + (this.hasFocus ? " cm-focused " : " ") + this.themeClasses
5983
5983
  });
5984
5984
  let contentAttrs = {
@@ -5994,7 +5994,7 @@ class EditorView {
5994
5994
  };
5995
5995
  if (this.state.readOnly)
5996
5996
  contentAttrs["aria-readonly"] = "true";
5997
- combineAttrs(this.state.facet(contentAttributes), contentAttrs);
5997
+ attrsFromFacet(this, contentAttributes, contentAttrs);
5998
5998
  this.observer.ignore(() => {
5999
5999
  updateAttrs(this.contentDOM, this.contentAttrs, contentAttrs);
6000
6000
  updateAttrs(this.dom, this.editorAttrs, editorAttrs);
@@ -6063,10 +6063,10 @@ class EditorView {
6063
6063
  the return value of this method.
6064
6064
  */
6065
6065
  plugin(plugin) {
6066
- for (let inst of this.plugins)
6067
- if (inst.spec == plugin)
6068
- return inst.update(this).value;
6069
- return null;
6066
+ let known = this.pluginMap.get(plugin);
6067
+ if (known === undefined || known && known.spec != plugin)
6068
+ this.pluginMap.set(plugin, known = this.plugins.find(p => p.spec == plugin) || null);
6069
+ return known && known.update(this).value;
6070
6070
  }
6071
6071
  /**
6072
6072
  The top position of the document, in screen coordinates. This
@@ -6553,6 +6553,14 @@ class CachedOrder {
6553
6553
  return result;
6554
6554
  }
6555
6555
  }
6556
+ function attrsFromFacet(view, facet, base) {
6557
+ for (let sources = view.state.facet(facet), i = sources.length - 1; i >= 0; i--) {
6558
+ let source = sources[i], value = typeof source == "function" ? source(view) : source;
6559
+ if (value)
6560
+ combineAttrs(value, base);
6561
+ }
6562
+ return base;
6563
+ }
6556
6564
 
6557
6565
  const currentPlatform = browser.mac ? "mac" : browser.windows ? "win" : browser.linux ? "linux" : "key";
6558
6566
  function normalizeKeyName(name, platform) {
@@ -7205,35 +7213,29 @@ class TabWidget extends WidgetType {
7205
7213
  }
7206
7214
 
7207
7215
  const plugin = ViewPlugin.fromClass(class {
7208
- constructor(view) {
7209
- this.height = -1;
7210
- this.measure = {
7211
- read: view => Math.max(0, view.scrollDOM.clientHeight - view.defaultLineHeight),
7212
- write: (value, view) => {
7213
- if (Math.abs(value - this.height) > 1) {
7214
- this.height = value;
7215
- view.contentDOM.style.paddingBottom = value + "px";
7216
- }
7217
- }
7218
- };
7219
- view.requestMeasure(this.measure);
7216
+ constructor() {
7217
+ this.height = 1000;
7218
+ this.attrs = { style: "padding-bottom: 1000px" };
7220
7219
  }
7221
7220
  update(update) {
7222
- if (update.geometryChanged)
7223
- update.view.requestMeasure(this.measure);
7221
+ let height = update.view.viewState.editorHeight - update.view.defaultLineHeight;
7222
+ if (height != this.height) {
7223
+ this.height = height;
7224
+ this.attrs = { style: `padding-bottom: ${height}px` };
7225
+ }
7224
7226
  }
7225
7227
  });
7226
7228
  /**
7227
- Returns a plugin that makes sure the content has a bottom margin
7228
- equivalent to the height of the editor, minus one line height, so
7229
- that every line in the document can be scrolled to the top of the
7230
- editor.
7229
+ Returns an extension that makes sure the content has a bottom
7230
+ margin equivalent to the height of the editor, minus one line
7231
+ height, so that every line in the document can be scrolled to the
7232
+ top of the editor.
7231
7233
 
7232
7234
  This is only meaningful when the editor is scrollable, and should
7233
7235
  not be enabled in editors that take the size of their content.
7234
7236
  */
7235
7237
  function scrollPastEnd() {
7236
- return plugin;
7238
+ return [plugin, contentAttributes.of(view => { var _a; return ((_a = view.plugin(plugin)) === null || _a === void 0 ? void 0 : _a.attrs) || null; })];
7237
7239
  }
7238
7240
 
7239
7241
  /**
package/dist/index.d.ts CHANGED
@@ -431,6 +431,7 @@ interface MeasureRequest<T> {
431
431
  */
432
432
  key?: any;
433
433
  }
434
+ declare type AttrSource = Attrs | ((view: EditorView) => Attrs | null);
434
435
  /**
435
436
  View [plugins](https://codemirror.net/6/docs/ref/#view.ViewPlugin) are given instances of this
436
437
  class, which describe what happened, whenever the view is updated.
@@ -694,6 +695,7 @@ declare class EditorView {
694
695
  readonly contentDOM: HTMLElement;
695
696
  private announceDOM;
696
697
  private plugins;
698
+ private pluginMap;
697
699
  private editorAttrs;
698
700
  private contentAttrs;
699
701
  private styleModules;
@@ -1008,7 +1010,7 @@ declare class EditorView {
1008
1010
  mounted in its [document
1009
1011
  root](https://codemirror.net/6/docs/ref/#view.EditorView.constructor^config.root).
1010
1012
  */
1011
- static styleModule: _codemirror_state.Facet<StyleModule, readonly StyleModule[]>;
1013
+ static styleModule: Facet<StyleModule, readonly StyleModule[]>;
1012
1014
  /**
1013
1015
  Facet that can be used to add DOM event handlers. The value
1014
1016
  should be an object mapping event names to handler functions. The
@@ -1029,7 +1031,7 @@ declare class EditorView {
1029
1031
  content. When one returns true, no further input handlers are
1030
1032
  called and the default behavior is prevented.
1031
1033
  */
1032
- static inputHandler: _codemirror_state.Facet<(view: EditorView, from: number, to: number, text: string) => boolean, readonly ((view: EditorView, from: number, to: number, text: string) => boolean)[]>;
1034
+ static inputHandler: Facet<(view: EditorView, from: number, to: number, text: string) => boolean, readonly ((view: EditorView, from: number, to: number, text: string) => boolean)[]>;
1033
1035
  /**
1034
1036
  Allows you to provide a function that should be called when the
1035
1037
  library catches an exception from an extension (mostly from view
@@ -1037,12 +1039,12 @@ declare class EditorView {
1037
1039
  from user-code-provided callbacks). This is mostly useful for
1038
1040
  debugging and logging. See [`logException`](https://codemirror.net/6/docs/ref/#view.logException).
1039
1041
  */
1040
- static exceptionSink: _codemirror_state.Facet<(exception: any) => void, readonly ((exception: any) => void)[]>;
1042
+ static exceptionSink: Facet<(exception: any) => void, readonly ((exception: any) => void)[]>;
1041
1043
  /**
1042
1044
  A facet that can be used to register a function to be called
1043
1045
  every time the view updates.
1044
1046
  */
1045
- static updateListener: _codemirror_state.Facet<(update: ViewUpdate) => void, readonly ((update: ViewUpdate) => void)[]>;
1047
+ static updateListener: Facet<(update: ViewUpdate) => void, readonly ((update: ViewUpdate) => void)[]>;
1046
1048
  /**
1047
1049
  Facet that controls whether the editor content DOM is editable.
1048
1050
  When its highest-precedence value is `false`, the element will
@@ -1051,33 +1053,33 @@ declare class EditorView {
1051
1053
  even when those are bound to keys or buttons. See the
1052
1054
  [`readOnly`](https://codemirror.net/6/docs/ref/#state.EditorState.readOnly) facet for that.)
1053
1055
  */
1054
- static editable: _codemirror_state.Facet<boolean, boolean>;
1056
+ static editable: Facet<boolean, boolean>;
1055
1057
  /**
1056
1058
  Allows you to influence the way mouse selection happens. The
1057
1059
  functions in this facet will be called for a `mousedown` event
1058
1060
  on the editor, and can return an object that overrides the way a
1059
1061
  selection is computed from that mouse click or drag.
1060
1062
  */
1061
- static mouseSelectionStyle: _codemirror_state.Facet<MakeSelectionStyle, readonly MakeSelectionStyle[]>;
1063
+ static mouseSelectionStyle: Facet<MakeSelectionStyle, readonly MakeSelectionStyle[]>;
1062
1064
  /**
1063
1065
  Facet used to configure whether a given selection drag event
1064
1066
  should move or copy the selection. The given predicate will be
1065
1067
  called with the `mousedown` event, and can return `true` when
1066
1068
  the drag should move the content.
1067
1069
  */
1068
- static dragMovesSelection: _codemirror_state.Facet<(event: MouseEvent) => boolean, readonly ((event: MouseEvent) => boolean)[]>;
1070
+ static dragMovesSelection: Facet<(event: MouseEvent) => boolean, readonly ((event: MouseEvent) => boolean)[]>;
1069
1071
  /**
1070
1072
  Facet used to configure whether a given selecting click adds
1071
1073
  a new range to the existing selection or replaces it entirely.
1072
1074
  */
1073
- static clickAddsSelectionRange: _codemirror_state.Facet<(event: MouseEvent) => boolean, readonly ((event: MouseEvent) => boolean)[]>;
1075
+ static clickAddsSelectionRange: Facet<(event: MouseEvent) => boolean, readonly ((event: MouseEvent) => boolean)[]>;
1074
1076
  /**
1075
1077
  A facet that determines which [decorations](https://codemirror.net/6/docs/ref/#view.Decoration)
1076
1078
  are shown in the view. See also [view
1077
1079
  plugins](https://codemirror.net/6/docs/ref/#view.EditorView^decorations), which have a separate
1078
1080
  mechanism for providing decorations.
1079
1081
  */
1080
- static decorations: _codemirror_state.Facet<DecorationSet, readonly DecorationSet[]>;
1082
+ static decorations: Facet<DecorationSet, readonly DecorationSet[]>;
1081
1083
  /**
1082
1084
  Create a theme extension. The first argument can be a
1083
1085
  [`style-mod`](https://github.com/marijnh/style-mod#documentation)
@@ -1115,12 +1117,12 @@ declare class EditorView {
1115
1117
  Facet that provides additional DOM attributes for the editor's
1116
1118
  editable DOM element.
1117
1119
  */
1118
- static contentAttributes: _codemirror_state.Facet<Attrs, Attrs>;
1120
+ static contentAttributes: Facet<AttrSource, readonly AttrSource[]>;
1119
1121
  /**
1120
1122
  Facet that provides DOM attributes for the editor's outer
1121
1123
  element.
1122
1124
  */
1123
- static editorAttributes: _codemirror_state.Facet<Attrs, Attrs>;
1125
+ static editorAttributes: Facet<AttrSource, readonly AttrSource[]>;
1124
1126
  /**
1125
1127
  An extension that enables line wrapping in the editor (by
1126
1128
  setting CSS `white-space` to `pre-wrap` in the content).
@@ -1318,10 +1320,10 @@ Configuration options.
1318
1320
  config?: SpecialCharConfig): Extension;
1319
1321
 
1320
1322
  /**
1321
- Returns a plugin that makes sure the content has a bottom margin
1322
- equivalent to the height of the editor, minus one line height, so
1323
- that every line in the document can be scrolled to the top of the
1324
- editor.
1323
+ Returns an extension that makes sure the content has a bottom
1324
+ margin equivalent to the height of the editor, minus one line
1325
+ height, so that every line in the document can be scrolled to the
1326
+ top of the editor.
1325
1327
 
1326
1328
  This is only meaningful when the editor is scrollable, and should
1327
1329
  not be enabled in editors that take the size of their content.
package/dist/index.js CHANGED
@@ -1082,8 +1082,9 @@ class Decoration extends RangeValue {
1082
1082
  position.
1083
1083
  */
1084
1084
  static widget(spec) {
1085
- let side = spec.side || 0;
1086
- return new PointDecoration(spec, side, side, !!spec.block, spec.widget || null, false);
1085
+ let side = spec.side || 0, block = !!spec.block;
1086
+ side += block ? (side > 0 ? 300000000 /* BlockAfter */ : -400000000 /* BlockBefore */) : (side > 0 ? 100000000 /* InlineAfter */ : -100000000 /* InlineBefore */);
1087
+ return new PointDecoration(spec, side, side, block, spec.widget || null, false);
1087
1088
  }
1088
1089
  /**
1089
1090
  Create a replace decoration which replaces the given range with
@@ -1092,8 +1093,8 @@ class Decoration extends RangeValue {
1092
1093
  static replace(spec) {
1093
1094
  let block = !!spec.block;
1094
1095
  let { start, end } = getInclusive(spec, block);
1095
- let startSide = 100000000 /* Big */ * (start ? -1 : 1) * (block ? 2 : 1);
1096
- let endSide = 100000000 /* Big */ * (end ? 1 : -1) * (block ? 2 : 1);
1096
+ let startSide = block ? (start ? -300000000 /* BlockIncStart */ : -1 /* InlineIncStart */) : 400000000 /* NonIncStart */;
1097
+ let endSide = block ? (end ? 200000000 /* BlockIncEnd */ : 1 /* InlineIncEnd */) : -500000000 /* NonIncEnd */;
1097
1098
  return new PointDecoration(spec, startSide, endSide, block, spec.widget || null, true);
1098
1099
  }
1099
1100
  /**
@@ -1123,7 +1124,7 @@ Decoration.none = RangeSet.empty;
1123
1124
  class MarkDecoration extends Decoration {
1124
1125
  constructor(spec) {
1125
1126
  let { start, end } = getInclusive(spec);
1126
- super(100000000 /* Big */ * (start ? -1 : 1), 100000000 /* Big */ * (end ? 1 : -1), null, spec);
1127
+ super(start ? -1 /* InlineIncStart */ : 400000000 /* NonIncStart */, end ? 1 /* InlineIncEnd */ : -500000000 /* NonIncEnd */, null, spec);
1127
1128
  this.tagName = spec.tagName || "span";
1128
1129
  this.class = spec.class || "";
1129
1130
  this.attrs = spec.attributes || null;
@@ -1144,7 +1145,7 @@ class MarkDecoration extends Decoration {
1144
1145
  MarkDecoration.prototype.point = false;
1145
1146
  class LineDecoration extends Decoration {
1146
1147
  constructor(spec) {
1147
- super(-100000000 /* Big */, -100000000 /* Big */, null, spec);
1148
+ super(-200000000 /* Line */, -200000000 /* Line */, null, spec);
1148
1149
  }
1149
1150
  eq(other) {
1150
1151
  return other instanceof LineDecoration && attrsEq(this.spec.attributes, other.spec.attributes);
@@ -1723,36 +1724,39 @@ class PluginInstance {
1723
1724
  this.value = null;
1724
1725
  }
1725
1726
  takeField(type, target) {
1726
- for (let { field, get } of this.spec.fields)
1727
- if (field == type)
1728
- target.push(get(this.value));
1727
+ if (this.spec)
1728
+ for (let { field, get } of this.spec.fields)
1729
+ if (field == type)
1730
+ target.push(get(this.value));
1729
1731
  }
1730
1732
  update(view) {
1731
1733
  if (!this.value) {
1732
- try {
1733
- this.value = this.spec.create(view);
1734
- }
1735
- catch (e) {
1736
- logException(view.state, e, "CodeMirror plugin crashed");
1737
- return PluginInstance.dummy;
1734
+ if (this.spec) {
1735
+ try {
1736
+ this.value = this.spec.create(view);
1737
+ }
1738
+ catch (e) {
1739
+ logException(view.state, e, "CodeMirror plugin crashed");
1740
+ this.deactivate();
1741
+ }
1738
1742
  }
1739
1743
  }
1740
1744
  else if (this.mustUpdate) {
1741
1745
  let update = this.mustUpdate;
1742
1746
  this.mustUpdate = null;
1743
- if (!this.value.update)
1744
- return this;
1745
- try {
1746
- this.value.update(update);
1747
- }
1748
- catch (e) {
1749
- logException(update.state, e, "CodeMirror plugin crashed");
1750
- if (this.value.destroy)
1751
- try {
1752
- this.value.destroy();
1753
- }
1754
- catch (_) { }
1755
- return PluginInstance.dummy;
1747
+ if (this.value.update) {
1748
+ try {
1749
+ this.value.update(update);
1750
+ }
1751
+ catch (e) {
1752
+ logException(update.state, e, "CodeMirror plugin crashed");
1753
+ if (this.value.destroy)
1754
+ try {
1755
+ this.value.destroy();
1756
+ }
1757
+ catch (_) { }
1758
+ this.deactivate();
1759
+ }
1756
1760
  }
1757
1761
  }
1758
1762
  return this;
@@ -1768,20 +1772,12 @@ class PluginInstance {
1768
1772
  }
1769
1773
  }
1770
1774
  }
1775
+ deactivate() {
1776
+ this.spec = this.value = null;
1777
+ }
1771
1778
  }
1772
- PluginInstance.dummy = /*@__PURE__*/new PluginInstance(/*@__PURE__*/ViewPlugin.define(() => ({})));
1773
- function combineFacetAttrs(values) {
1774
- let result = {};
1775
- for (let i = values.length - 1; i >= 0; i--)
1776
- combineAttrs(values[i], result);
1777
- return result;
1778
- }
1779
- const editorAttributes = /*@__PURE__*/Facet.define({
1780
- combine: combineFacetAttrs
1781
- });
1782
- const contentAttributes = /*@__PURE__*/Facet.define({
1783
- combine: combineFacetAttrs
1784
- });
1779
+ const editorAttributes = /*@__PURE__*/Facet.define();
1780
+ const contentAttributes = /*@__PURE__*/Facet.define();
1785
1781
  // Provide decorations
1786
1782
  const decorations = /*@__PURE__*/Facet.define();
1787
1783
  const styleModule = /*@__PURE__*/Facet.define();
@@ -1929,12 +1925,12 @@ class DocView extends ContentView {
1929
1925
  this.compositionDeco = Decoration.none;
1930
1926
  this.decorations = [];
1931
1927
  // Track a minimum width for the editor. When measuring sizes in
1932
- // checkLayout, this is updated to point at the width of a given
1933
- // element and its extent in the document. When a change happens in
1934
- // that range, these are reset. That way, once we've seen a
1935
- // line/element of a given length, we keep the editor wide enough to
1936
- // fit at least that element, until it is changed, at which point we
1937
- // forget it again.
1928
+ // measureVisibleLineHeights, this is updated to point at the width
1929
+ // of a given element and its extent in the document. When a change
1930
+ // happens in that range, these are reset. That way, once we've seen
1931
+ // a line/element of a given length, we keep the editor wide enough
1932
+ // to fit at least that element, until it is changed, at which point
1933
+ // we forget it again.
1938
1934
  this.minWidth = 0;
1939
1935
  this.minWidthFrom = 0;
1940
1936
  this.minWidthTo = 0;
@@ -2004,7 +2000,7 @@ class DocView extends ContentView {
2004
2000
  this.updateSelection();
2005
2001
  }
2006
2002
  }
2007
- // Used both by update and checkLayout do perform the actual DOM
2003
+ // Used by update and the constructor do perform the actual DOM
2008
2004
  // update
2009
2005
  updateInner(changes, deco, oldLength) {
2010
2006
  this.view.viewState.mustMeasureContent = true;
@@ -2926,7 +2922,7 @@ function posAtCoords(view, { x, y }, precise, bias = -1) {
2926
2922
  y = docTop + yOffset;
2927
2923
  let lineStart = block.from;
2928
2924
  // Clip x to the viewport sides
2929
- x = Math.max(content.left + 1, Math.min(content.right - 1, x));
2925
+ x = Math.max(content.left + 1, Math.min(Math.max(content.right, content.left + view.docView.minWidth) - 1, x));
2930
2926
  // If this is outside of the rendered viewport, we can't determine a position
2931
2927
  if (lineStart < view.viewport.from)
2932
2928
  return view.viewport.from == 0 ? 0 : posAtCoordsImprecise(view, content, block, x, y);
@@ -5059,7 +5055,7 @@ const baseTheme = /*@__PURE__*/buildTheme("." + baseThemeID, {
5059
5055
  color: "inherit",
5060
5056
  fontSize: "70%",
5061
5057
  padding: ".2em 1em",
5062
- borderRadius: "3px"
5058
+ borderRadius: "1px"
5063
5059
  },
5064
5060
  "&light .cm-button": {
5065
5061
  backgroundImage: "linear-gradient(#eff1f5, #d9d9df)",
@@ -5381,6 +5377,7 @@ class DOMObserver {
5381
5377
  for (let dom of this.scrollTargets)
5382
5378
  dom.removeEventListener("scroll", this.onScroll);
5383
5379
  window.removeEventListener("scroll", this.onScroll);
5380
+ this.dom.ownerDocument.removeEventListener("selectionchange", this.onSelectionChange);
5384
5381
  clearTimeout(this.parentCheck);
5385
5382
  clearTimeout(this.resizeTimeout);
5386
5383
  }
@@ -5677,6 +5674,7 @@ class EditorView {
5677
5674
  */
5678
5675
  config = {}) {
5679
5676
  this.plugins = [];
5677
+ this.pluginMap = new Map;
5680
5678
  this.editorAttrs = {};
5681
5679
  this.contentAttrs = {};
5682
5680
  this.bidiCache = [];
@@ -5846,6 +5844,7 @@ class EditorView {
5846
5844
  plugin.destroy(this);
5847
5845
  this.viewState = new ViewState(newState);
5848
5846
  this.plugins = newState.facet(viewPlugin).map(spec => new PluginInstance(spec).update(this));
5847
+ this.pluginMap.clear();
5849
5848
  this.docView = new DocView(this);
5850
5849
  this.inputState.ensureHandlers(this);
5851
5850
  this.mountStyles();
@@ -5876,6 +5875,7 @@ class EditorView {
5876
5875
  if (plugin.mustUpdate != update)
5877
5876
  plugin.destroy(this);
5878
5877
  this.plugins = newPlugins;
5878
+ this.pluginMap.clear();
5879
5879
  this.inputState.ensureHandlers(this);
5880
5880
  }
5881
5881
  else {
@@ -5883,7 +5883,7 @@ class EditorView {
5883
5883
  p.mustUpdate = update;
5884
5884
  }
5885
5885
  for (let i = 0; i < this.plugins.length; i++)
5886
- this.plugins[i] = this.plugins[i].update(this);
5886
+ this.plugins[i].update(this);
5887
5887
  }
5888
5888
  /**
5889
5889
  @internal
@@ -5972,7 +5972,7 @@ class EditorView {
5972
5972
  this.state.facet(theme);
5973
5973
  }
5974
5974
  updateAttrs() {
5975
- let editorAttrs = combineAttrs(this.state.facet(editorAttributes), {
5975
+ let editorAttrs = attrsFromFacet(this, editorAttributes, {
5976
5976
  class: "cm-editor" + (this.hasFocus ? " cm-focused " : " ") + this.themeClasses
5977
5977
  });
5978
5978
  let contentAttrs = {
@@ -5988,7 +5988,7 @@ class EditorView {
5988
5988
  };
5989
5989
  if (this.state.readOnly)
5990
5990
  contentAttrs["aria-readonly"] = "true";
5991
- combineAttrs(this.state.facet(contentAttributes), contentAttrs);
5991
+ attrsFromFacet(this, contentAttributes, contentAttrs);
5992
5992
  this.observer.ignore(() => {
5993
5993
  updateAttrs(this.contentDOM, this.contentAttrs, contentAttrs);
5994
5994
  updateAttrs(this.dom, this.editorAttrs, editorAttrs);
@@ -6057,10 +6057,10 @@ class EditorView {
6057
6057
  the return value of this method.
6058
6058
  */
6059
6059
  plugin(plugin) {
6060
- for (let inst of this.plugins)
6061
- if (inst.spec == plugin)
6062
- return inst.update(this).value;
6063
- return null;
6060
+ let known = this.pluginMap.get(plugin);
6061
+ if (known === undefined || known && known.spec != plugin)
6062
+ this.pluginMap.set(plugin, known = this.plugins.find(p => p.spec == plugin) || null);
6063
+ return known && known.update(this).value;
6064
6064
  }
6065
6065
  /**
6066
6066
  The top position of the document, in screen coordinates. This
@@ -6547,6 +6547,14 @@ class CachedOrder {
6547
6547
  return result;
6548
6548
  }
6549
6549
  }
6550
+ function attrsFromFacet(view, facet, base) {
6551
+ for (let sources = view.state.facet(facet), i = sources.length - 1; i >= 0; i--) {
6552
+ let source = sources[i], value = typeof source == "function" ? source(view) : source;
6553
+ if (value)
6554
+ combineAttrs(value, base);
6555
+ }
6556
+ return base;
6557
+ }
6550
6558
 
6551
6559
  const currentPlatform = browser.mac ? "mac" : browser.windows ? "win" : browser.linux ? "linux" : "key";
6552
6560
  function normalizeKeyName(name, platform) {
@@ -7199,35 +7207,29 @@ class TabWidget extends WidgetType {
7199
7207
  }
7200
7208
 
7201
7209
  const plugin = /*@__PURE__*/ViewPlugin.fromClass(class {
7202
- constructor(view) {
7203
- this.height = -1;
7204
- this.measure = {
7205
- read: view => Math.max(0, view.scrollDOM.clientHeight - view.defaultLineHeight),
7206
- write: (value, view) => {
7207
- if (Math.abs(value - this.height) > 1) {
7208
- this.height = value;
7209
- view.contentDOM.style.paddingBottom = value + "px";
7210
- }
7211
- }
7212
- };
7213
- view.requestMeasure(this.measure);
7210
+ constructor() {
7211
+ this.height = 1000;
7212
+ this.attrs = { style: "padding-bottom: 1000px" };
7214
7213
  }
7215
7214
  update(update) {
7216
- if (update.geometryChanged)
7217
- update.view.requestMeasure(this.measure);
7215
+ let height = update.view.viewState.editorHeight - update.view.defaultLineHeight;
7216
+ if (height != this.height) {
7217
+ this.height = height;
7218
+ this.attrs = { style: `padding-bottom: ${height}px` };
7219
+ }
7218
7220
  }
7219
7221
  });
7220
7222
  /**
7221
- Returns a plugin that makes sure the content has a bottom margin
7222
- equivalent to the height of the editor, minus one line height, so
7223
- that every line in the document can be scrolled to the top of the
7224
- editor.
7223
+ Returns an extension that makes sure the content has a bottom
7224
+ margin equivalent to the height of the editor, minus one line
7225
+ height, so that every line in the document can be scrolled to the
7226
+ top of the editor.
7225
7227
 
7226
7228
  This is only meaningful when the editor is scrollable, and should
7227
7229
  not be enabled in editors that take the size of their content.
7228
7230
  */
7229
7231
  function scrollPastEnd() {
7230
- return plugin;
7232
+ return [plugin, contentAttributes.of(view => { var _a; return ((_a = view.plugin(plugin)) === null || _a === void 0 ? void 0 : _a.attrs) || null; })];
7231
7233
  }
7232
7234
 
7233
7235
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codemirror/view",
3
- "version": "0.19.24",
3
+ "version": "0.19.25",
4
4
  "description": "DOM view component for the CodeMirror code editor",
5
5
  "scripts": {
6
6
  "test": "cm-runtests",