@codemirror/autocomplete 0.19.11 → 0.19.14

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
+ ## 0.19.14 (2022-03-10)
2
+
3
+ ### Bug fixes
4
+
5
+ Make the ARIA attributes added to the editor during autocompletion spec-compliant.
6
+
7
+ ## 0.19.13 (2022-02-18)
8
+
9
+ ### Bug fixes
10
+
11
+ Fix an issue where the completion tooltip stayed open if it was explicitly opened and the user backspaced past its start.
12
+
13
+ Stop snippet filling when a change happens across one of the snippet fields' boundaries.
14
+
15
+ ## 0.19.12 (2022-01-11)
16
+
17
+ ### Bug fixes
18
+
19
+ Fix completion navigation with PageUp/Down when the completion tooltip isn't part of the view DOM.
20
+
1
21
  ## 0.19.11 (2022-01-11)
2
22
 
3
23
  ### Bug fixes
package/dist/index.cjs CHANGED
@@ -514,6 +514,7 @@ class CompletionTooltip {
514
514
  const ul = document.createElement("ul");
515
515
  ul.id = id;
516
516
  ul.setAttribute("role", "listbox");
517
+ ul.setAttribute("aria-expanded", "true");
517
518
  for (let i = range.from; i < range.to; i++) {
518
519
  let { completion, match } = options[i];
519
520
  const li = ul.appendChild(document.createElement("li"));
@@ -574,7 +575,6 @@ function sortOptions(active, state) {
574
575
  }
575
576
  }
576
577
  }
577
- options.sort(cmpOption);
578
578
  let result = [], prev = null;
579
579
  for (let opt of options.sort(cmpOption)) {
580
580
  if (result.length == MaxOptions)
@@ -607,10 +607,11 @@ class CompletionDialog {
607
607
  let selected = 0;
608
608
  if (prev && prev.selected) {
609
609
  let selectedValue = prev.options[prev.selected].completion;
610
- for (let i = 0; i < options.length && !selected; i++) {
611
- if (options[i].completion == selectedValue)
610
+ for (let i = 0; i < options.length; i++)
611
+ if (options[i].completion == selectedValue) {
612
612
  selected = i;
613
- }
613
+ break;
614
+ }
614
615
  }
615
616
  return new CompletionDialog(options, makeAttrs(id, selected), {
616
617
  pos: active.reduce((a, b) => b.hasResult() ? Math.min(a, b.from) : a, 1e8),
@@ -671,13 +672,12 @@ function sameResults(a, b) {
671
672
  }
672
673
  }
673
674
  const baseAttrs = {
674
- "aria-autocomplete": "list",
675
- "aria-expanded": "false"
675
+ "aria-autocomplete": "list"
676
676
  };
677
677
  function makeAttrs(id, selected) {
678
678
  return {
679
679
  "aria-autocomplete": "list",
680
- "aria-expanded": "true",
680
+ "aria-haspopup": "listbox",
681
681
  "aria-activedescendant": id + "-" + selected,
682
682
  "aria-controls": id
683
683
  };
@@ -741,7 +741,9 @@ class ActiveResult extends ActiveSource {
741
741
  handleUserEvent(tr, type, conf) {
742
742
  let from = tr.changes.mapPos(this.from), to = tr.changes.mapPos(this.to, 1);
743
743
  let pos = cur(tr.state);
744
- if ((this.explicitPos > -1 ? pos < from : pos <= from) || pos > to)
744
+ if ((this.explicitPos < 0 ? pos <= from : pos < this.from) ||
745
+ pos > to ||
746
+ type == "delete" && cur(tr.startState) == this.from)
745
747
  return new ActiveSource(this.source, type == "input" && conf.activateOnTyping ? 1 /* Pending */ : 0 /* Inactive */);
746
748
  let explicitPos = this.explicitPos < 0 ? -1 : tr.changes.mapPos(this.explicitPos);
747
749
  if (this.span && (from == to || this.span.test(tr.state.sliceDoc(from, to))))
@@ -781,9 +783,10 @@ function moveCompletionSelection(forward, by = "option") {
781
783
  let cState = view.state.field(completionState, false);
782
784
  if (!cState || !cState.open || Date.now() - cState.open.timestamp < CompletionInteractMargin)
783
785
  return false;
784
- let step = 1, tooltip;
785
- if (by == "page" && (tooltip = view.dom.querySelector(".cm-tooltip-autocomplete")))
786
- step = Math.max(2, Math.floor(tooltip.offsetHeight / tooltip.querySelector("li").offsetHeight) - 1);
786
+ let step = 1, tooltip$1;
787
+ if (by == "page" && (tooltip$1 = tooltip.getTooltip(view, cState.open.tooltip)))
788
+ step = Math.max(2, Math.floor(tooltip$1.dom.offsetHeight /
789
+ tooltip$1.dom.querySelector("li").offsetHeight) - 1);
787
790
  let selected = cState.open.selected + step * (forward ? 1 : -1), { length } = cState.open.options;
788
791
  if (selected < 0)
789
792
  selected = by == "page" ? 0 : length - 1;
@@ -856,7 +859,7 @@ const completionPlugin = view.ViewPlugin.fromClass(class {
856
859
  for (let i = 0; i < this.running.length; i++) {
857
860
  let query = this.running[i];
858
861
  if (doesReset ||
859
- query.updates.length + update.transactions.length > MaxUpdateCount && query.time - Date.now() > MinAbortTime) {
862
+ query.updates.length + update.transactions.length > MaxUpdateCount && Date.now() - query.time > MinAbortTime) {
860
863
  for (let handler of query.context.abortListeners) {
861
864
  try {
862
865
  handler();
@@ -1092,7 +1095,9 @@ class FieldRange {
1092
1095
  this.to = to;
1093
1096
  }
1094
1097
  map(changes) {
1095
- return new FieldRange(this.field, changes.mapPos(this.from, -1), changes.mapPos(this.to, 1));
1098
+ let from = changes.mapPos(this.from, -1, state.MapMode.TrackDel);
1099
+ let to = changes.mapPos(this.to, 1, state.MapMode.TrackDel);
1100
+ return from == null || to == null ? null : new FieldRange(this.field, from, to);
1096
1101
  }
1097
1102
  }
1098
1103
  class Snippet {
@@ -1161,7 +1166,14 @@ class ActiveSnippet {
1161
1166
  this.deco = view.Decoration.set(ranges.map(r => (r.from == r.to ? fieldMarker : fieldRange).range(r.from, r.to)));
1162
1167
  }
1163
1168
  map(changes) {
1164
- return new ActiveSnippet(this.ranges.map(r => r.map(changes)), this.active);
1169
+ let ranges = [];
1170
+ for (let r of this.ranges) {
1171
+ let mapped = r.map(changes);
1172
+ if (!mapped)
1173
+ return null;
1174
+ ranges.push(mapped);
1175
+ }
1176
+ return new ActiveSnippet(ranges, this.active);
1165
1177
  }
1166
1178
  selectionInsideField(sel) {
1167
1179
  return sel.ranges.every(range => this.ranges.some(r => r.field == this.active && r.from <= range.from && r.to >= range.to));
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
- import { Annotation, Facet, combineConfig, StateEffect, StateField, Prec, EditorSelection, Text } from '@codemirror/state';
1
+ import { Annotation, Facet, combineConfig, StateEffect, StateField, Prec, EditorSelection, Text, MapMode } from '@codemirror/state';
2
2
  import { Direction, logException, EditorView, ViewPlugin, Decoration, WidgetType, keymap } from '@codemirror/view';
3
- import { showTooltip } from '@codemirror/tooltip';
3
+ import { showTooltip, getTooltip } from '@codemirror/tooltip';
4
4
  import { syntaxTree, indentUnit } from '@codemirror/language';
5
5
  import { codePointAt, codePointSize, fromCodePoint } from '@codemirror/text';
6
6
 
@@ -510,6 +510,7 @@ class CompletionTooltip {
510
510
  const ul = document.createElement("ul");
511
511
  ul.id = id;
512
512
  ul.setAttribute("role", "listbox");
513
+ ul.setAttribute("aria-expanded", "true");
513
514
  for (let i = range.from; i < range.to; i++) {
514
515
  let { completion, match } = options[i];
515
516
  const li = ul.appendChild(document.createElement("li"));
@@ -570,7 +571,6 @@ function sortOptions(active, state) {
570
571
  }
571
572
  }
572
573
  }
573
- options.sort(cmpOption);
574
574
  let result = [], prev = null;
575
575
  for (let opt of options.sort(cmpOption)) {
576
576
  if (result.length == MaxOptions)
@@ -603,10 +603,11 @@ class CompletionDialog {
603
603
  let selected = 0;
604
604
  if (prev && prev.selected) {
605
605
  let selectedValue = prev.options[prev.selected].completion;
606
- for (let i = 0; i < options.length && !selected; i++) {
607
- if (options[i].completion == selectedValue)
606
+ for (let i = 0; i < options.length; i++)
607
+ if (options[i].completion == selectedValue) {
608
608
  selected = i;
609
- }
609
+ break;
610
+ }
610
611
  }
611
612
  return new CompletionDialog(options, makeAttrs(id, selected), {
612
613
  pos: active.reduce((a, b) => b.hasResult() ? Math.min(a, b.from) : a, 1e8),
@@ -667,13 +668,12 @@ function sameResults(a, b) {
667
668
  }
668
669
  }
669
670
  const baseAttrs = {
670
- "aria-autocomplete": "list",
671
- "aria-expanded": "false"
671
+ "aria-autocomplete": "list"
672
672
  };
673
673
  function makeAttrs(id, selected) {
674
674
  return {
675
675
  "aria-autocomplete": "list",
676
- "aria-expanded": "true",
676
+ "aria-haspopup": "listbox",
677
677
  "aria-activedescendant": id + "-" + selected,
678
678
  "aria-controls": id
679
679
  };
@@ -737,7 +737,9 @@ class ActiveResult extends ActiveSource {
737
737
  handleUserEvent(tr, type, conf) {
738
738
  let from = tr.changes.mapPos(this.from), to = tr.changes.mapPos(this.to, 1);
739
739
  let pos = cur(tr.state);
740
- if ((this.explicitPos > -1 ? pos < from : pos <= from) || pos > to)
740
+ if ((this.explicitPos < 0 ? pos <= from : pos < this.from) ||
741
+ pos > to ||
742
+ type == "delete" && cur(tr.startState) == this.from)
741
743
  return new ActiveSource(this.source, type == "input" && conf.activateOnTyping ? 1 /* Pending */ : 0 /* Inactive */);
742
744
  let explicitPos = this.explicitPos < 0 ? -1 : tr.changes.mapPos(this.explicitPos);
743
745
  if (this.span && (from == to || this.span.test(tr.state.sliceDoc(from, to))))
@@ -778,8 +780,9 @@ function moveCompletionSelection(forward, by = "option") {
778
780
  if (!cState || !cState.open || Date.now() - cState.open.timestamp < CompletionInteractMargin)
779
781
  return false;
780
782
  let step = 1, tooltip;
781
- if (by == "page" && (tooltip = view.dom.querySelector(".cm-tooltip-autocomplete")))
782
- step = Math.max(2, Math.floor(tooltip.offsetHeight / tooltip.querySelector("li").offsetHeight) - 1);
783
+ if (by == "page" && (tooltip = getTooltip(view, cState.open.tooltip)))
784
+ step = Math.max(2, Math.floor(tooltip.dom.offsetHeight /
785
+ tooltip.dom.querySelector("li").offsetHeight) - 1);
783
786
  let selected = cState.open.selected + step * (forward ? 1 : -1), { length } = cState.open.options;
784
787
  if (selected < 0)
785
788
  selected = by == "page" ? 0 : length - 1;
@@ -852,7 +855,7 @@ const completionPlugin = /*@__PURE__*/ViewPlugin.fromClass(class {
852
855
  for (let i = 0; i < this.running.length; i++) {
853
856
  let query = this.running[i];
854
857
  if (doesReset ||
855
- query.updates.length + update.transactions.length > MaxUpdateCount && query.time - Date.now() > MinAbortTime) {
858
+ query.updates.length + update.transactions.length > MaxUpdateCount && Date.now() - query.time > MinAbortTime) {
856
859
  for (let handler of query.context.abortListeners) {
857
860
  try {
858
861
  handler();
@@ -1088,7 +1091,9 @@ class FieldRange {
1088
1091
  this.to = to;
1089
1092
  }
1090
1093
  map(changes) {
1091
- return new FieldRange(this.field, changes.mapPos(this.from, -1), changes.mapPos(this.to, 1));
1094
+ let from = changes.mapPos(this.from, -1, MapMode.TrackDel);
1095
+ let to = changes.mapPos(this.to, 1, MapMode.TrackDel);
1096
+ return from == null || to == null ? null : new FieldRange(this.field, from, to);
1092
1097
  }
1093
1098
  }
1094
1099
  class Snippet {
@@ -1157,7 +1162,14 @@ class ActiveSnippet {
1157
1162
  this.deco = Decoration.set(ranges.map(r => (r.from == r.to ? fieldMarker : fieldRange).range(r.from, r.to)));
1158
1163
  }
1159
1164
  map(changes) {
1160
- return new ActiveSnippet(this.ranges.map(r => r.map(changes)), this.active);
1165
+ let ranges = [];
1166
+ for (let r of this.ranges) {
1167
+ let mapped = r.map(changes);
1168
+ if (!mapped)
1169
+ return null;
1170
+ ranges.push(mapped);
1171
+ }
1172
+ return new ActiveSnippet(ranges, this.active);
1161
1173
  }
1162
1174
  selectionInsideField(sel) {
1163
1175
  return sel.ranges.every(range => this.ranges.some(r => r.field == this.active && r.from <= range.from && r.to >= range.to));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codemirror/autocomplete",
3
- "version": "0.19.11",
3
+ "version": "0.19.14",
4
4
  "description": "Autocompletion for the CodeMirror code editor",
5
5
  "scripts": {
6
6
  "test": "cm-runtests",
@@ -29,7 +29,7 @@
29
29
  "@codemirror/language": "^0.19.0",
30
30
  "@codemirror/state": "^0.19.4",
31
31
  "@codemirror/text": "^0.19.2",
32
- "@codemirror/tooltip": "^0.19.0",
32
+ "@codemirror/tooltip": "^0.19.12",
33
33
  "@codemirror/view": "^0.19.0",
34
34
  "@lezer/common": "^0.15.0"
35
35
  },