UX: avoid triggering the autocomplete mid-word (#30042)

With the previous logic, autocompletes were being opened mid-word, which was annoying and didn't properly work – selecting an option would generate an invalid format, mixing existing with new.

This PR makes a simple change: only ever trigger an autocomplete on word ends, and close them when arrow-navigating out of the word-end boundary.

ref /t/-/143169
This commit is contained in:
Renato Atilio 2025-01-03 16:27:44 -03:00 committed by GitHub
parent dacb5d5d33
commit b4f0a8748d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 47 additions and 1 deletions

View File

@ -478,7 +478,11 @@ export default function (options) {
}
prevTerm = term;
if (term.length !== 0 && term.trim().length === 0) {
if (
(term.length !== 0 && term.trim().length === 0) ||
// close unless the caret is at the end of a word, like #line|<-
options.textHandler.value[options.textHandler.getCaretPosition()]?.trim()
) {
closeAutocomplete();
return null;
} else {

View File

@ -1,3 +1,4 @@
import { triggerKeyEvent } from "@ember/test-helpers";
import { setupTest } from "ember-qunit";
import { compile } from "handlebars";
import $ from "jquery";
@ -169,4 +170,45 @@ module("Unit | Utility | autocomplete", function (hooks) {
assert.strictEqual(element.value, "@t");
});
test("Autocomplete does not trigger with right-left arrow keys", async function (assert) {
const element = textArea();
$(element).autocomplete({
key: ":",
template,
transformComplete: (e) => e.slice(1),
dataSource: () => [":smile:"],
});
await simulateKeys(element, ":smi\t");
assert.dom(element).hasValue(":smile: ");
await triggerArrowKey(element, "ArrowLeft");
await triggerArrowKey(element, "ArrowLeft");
await triggerArrowKey(element, "ArrowLeft");
await triggerArrowKey(element, "ArrowRight");
assert.strictEqual(element.selectionStart, 6);
// This is passing, but it's a false positive
// triggerArrowKey isn't triggering the event the autocomplete listens to
assert.dom("#ac-testing").doesNotExist();
await triggerArrowKey(element, "ArrowRight");
await simulateKey(element, "\b");
assert.dom(element).hasValue(":smile ");
assert.dom("#ac-testing").exists();
});
});
async function triggerArrowKey(element, key) {
await triggerKeyEvent(element, "keydown", key, { code: key });
await triggerKeyEvent(element, "keyup", key, { code: key });
const pos = element.selectionStart;
const direction = key === "ArrowLeft" ? -1 : 1;
element.setSelectionRange(pos + 1 * direction, pos + 1 * direction);
}