fix: keep arrow keys and tab inside editor mode
This commit is contained in:
+2
-1
@@ -102,7 +102,8 @@ Editing flow:
|
|||||||
|
|
||||||
- `Enter`: save and submit the current input
|
- `Enter`: save and submit the current input
|
||||||
- `Esc`: save draft and close the editor
|
- `Esc`: save draft and close the editor
|
||||||
- `Up`, `Down`, `Tab`, `Shift+Tab`: save draft and continue navigation
|
- arrow keys and `Tab` stay in the editor so the cursor can move while typing
|
||||||
|
- navigation resumes only after closing the editor with `Esc`
|
||||||
|
|
||||||
## Non-interactive mode
|
## Non-interactive mode
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -16,8 +16,8 @@ export const UI_TEXT = {
|
|||||||
reviewTitle: "Review your answers",
|
reviewTitle: "Review your answers",
|
||||||
readyToSubmit: "Ready to submit your answers?",
|
readyToSubmit: "Ready to submit your answers?",
|
||||||
unanswered: "→ (unanswered)",
|
unanswered: "→ (unanswered)",
|
||||||
footerInput: " Enter submit · Esc save and close · Tab/←→ save and navigate",
|
footerInput: " Enter submit · Esc save and close",
|
||||||
footerNote: " Enter save · Esc save and close · Tab/←→ save and navigate",
|
footerNote: " Enter save · Esc save and close",
|
||||||
footerSubmit: " ↑↓ select · Enter confirm · Esc cancel",
|
footerSubmit: " ↑↓ select · Enter confirm · Esc cancel",
|
||||||
footerMulti:
|
footerMulti:
|
||||||
" ⇆ tab · ↑↓ select · Space toggle · Enter continue · N option note · Ctrl+N question note · Esc dismiss · 1-9 quick toggle",
|
" ⇆ tab · ↑↓ select · Space toggle · Enter continue · N option note · Ctrl+N question note · Esc dismiss · 1-9 quick toggle",
|
||||||
|
|||||||
@@ -42,18 +42,6 @@ export function formatKeybindingLabel(key: string): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getEditingInputCommand(data: string): AskInputCommand {
|
function getEditingInputCommand(data: string): AskInputCommand {
|
||||||
if (matchesKey(data, Key.tab) || matchesKey(data, Key.right)) {
|
|
||||||
return { kind: "editMoveTab", delta: 1 };
|
|
||||||
}
|
|
||||||
if (matchesKey(data, Key.shift("tab")) || matchesKey(data, Key.left)) {
|
|
||||||
return { kind: "editMoveTab", delta: -1 };
|
|
||||||
}
|
|
||||||
if (matchesKey(data, Key.up)) {
|
|
||||||
return { kind: "editMoveOption", delta: -1 };
|
|
||||||
}
|
|
||||||
if (matchesKey(data, Key.down)) {
|
|
||||||
return { kind: "editMoveOption", delta: 1 };
|
|
||||||
}
|
|
||||||
if (matchesKey(data, Key.escape)) {
|
if (matchesKey(data, Key.escape)) {
|
||||||
return { kind: "editClose" };
|
return { kind: "editClose" };
|
||||||
}
|
}
|
||||||
|
|||||||
+33
-10
@@ -21,19 +21,35 @@ function inputState() {
|
|||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
test("editing views let up and down move navigation", () => {
|
test("typing mode delegates arrow keys to the editor", () => {
|
||||||
const input = inputState();
|
const input = inputState();
|
||||||
|
|
||||||
assert.deepEqual(getInputCommand(input, "\x1b[A"), {
|
assert.deepEqual(getInputCommand(input, "\x1b[A"), {
|
||||||
kind: "editMoveOption",
|
kind: "delegateToEditor",
|
||||||
delta: -1,
|
|
||||||
});
|
});
|
||||||
assert.deepEqual(getInputCommand(input, "\x1b[B"), {
|
assert.deepEqual(getInputCommand(input, "\x1b[B"), {
|
||||||
kind: "editMoveOption",
|
kind: "delegateToEditor",
|
||||||
delta: 1,
|
});
|
||||||
|
assert.deepEqual(getInputCommand(input, "\x1b[C"), {
|
||||||
|
kind: "delegateToEditor",
|
||||||
|
});
|
||||||
|
assert.deepEqual(getInputCommand(input, "\x1b[D"), {
|
||||||
|
kind: "delegateToEditor",
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test("note editing views let up and down move navigation", () => {
|
test("typing mode delegates tab to the editor", () => {
|
||||||
|
const input = inputState();
|
||||||
|
|
||||||
|
assert.deepEqual(getInputCommand(input, "\t"), {
|
||||||
|
kind: "delegateToEditor",
|
||||||
|
});
|
||||||
|
assert.deepEqual(getInputCommand(input, "\x1b[Z"), {
|
||||||
|
kind: "delegateToEditor",
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test("note editing mode delegates arrows and tab to the editor", () => {
|
||||||
const state = enterQuestionNoteMode(
|
const state = enterQuestionNoteMode(
|
||||||
createInitialState({
|
createInitialState({
|
||||||
questions: [
|
questions: [
|
||||||
@@ -48,11 +64,18 @@ test("note editing views let up and down move navigation", () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
assert.deepEqual(getInputCommand(state, "\x1b[A"), {
|
assert.deepEqual(getInputCommand(state, "\x1b[A"), {
|
||||||
kind: "editMoveOption",
|
kind: "delegateToEditor",
|
||||||
delta: -1,
|
|
||||||
});
|
});
|
||||||
assert.deepEqual(getInputCommand(state, "\x1b[B"), {
|
assert.deepEqual(getInputCommand(state, "\x1b[B"), {
|
||||||
kind: "editMoveOption",
|
kind: "delegateToEditor",
|
||||||
delta: 1,
|
});
|
||||||
|
assert.deepEqual(getInputCommand(state, "\x1b[C"), {
|
||||||
|
kind: "delegateToEditor",
|
||||||
|
});
|
||||||
|
assert.deepEqual(getInputCommand(state, "\x1b[D"), {
|
||||||
|
kind: "delegateToEditor",
|
||||||
|
});
|
||||||
|
assert.deepEqual(getInputCommand(state, "\t"), {
|
||||||
|
kind: "delegateToEditor",
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
import assert from "node:assert/strict";
|
import assert from "node:assert/strict";
|
||||||
import test from "node:test";
|
import test from "node:test";
|
||||||
import { renderEditorBlock } from "../src/ui/render-helpers.ts";
|
import {
|
||||||
|
renderEditorBlock,
|
||||||
|
renderFooterText,
|
||||||
|
} from "../src/ui/render-helpers.ts";
|
||||||
|
|
||||||
const ABC_PATTERN = /abc/;
|
const ABC_PATTERN = /abc/;
|
||||||
const BORDER_PATTERN = /┌|└/;
|
const BORDER_PATTERN = /┌|└/;
|
||||||
@@ -69,3 +72,8 @@ test("renderEditorBlock reapplies background after editor reset sequences", () =
|
|||||||
assert.match(lines[0], SELECTED_BG_PATTERN);
|
assert.match(lines[0], SELECTED_BG_PATTERN);
|
||||||
assert(lines[0].includes("\x1b[0m{selectedBg}"));
|
assert(lines[0].includes("\x1b[0m{selectedBg}"));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("editing footers do not advertise tab navigation", () => {
|
||||||
|
assert.equal(renderFooterText("input"), " Enter submit · Esc save and close");
|
||||||
|
assert.equal(renderFooterText("note"), " Enter save · Esc save and close");
|
||||||
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user