diff --git a/README.md b/README.md index 5af8943..f0a2c07 100644 --- a/README.md +++ b/README.md @@ -239,6 +239,7 @@ Behavior details: - `details.continuation.affectedQuestionIds` lists the only questions that should be revisited - `details.continuation.questionStates` marks each question as `answered`, `needs_clarification`, or `unanswered` - submit review tab now offers `Submit`, `Elaborate`, and `Cancel` +- on the review tab, number hotkeys `1`, `2`, and `3` trigger `Submit`, `Elaborate`, and `Cancel` - while `Submit` or `Cancel` is highlighted on the review tab, notes are previewed only for questions with selected answers - while `Elaborate` is highlighted on the review tab, the preview expands to show all question notes and all option notes, including notes on unselected options - choosing `Elaborate` finishes immediately and returns `mode: "elaborate"` diff --git a/docs/contract.md b/docs/contract.md index b83f0ad..a0c59de 100644 --- a/docs/contract.md +++ b/docs/contract.md @@ -210,7 +210,7 @@ Main flow: - `Enter`: confirm or submit - `Esc`: cancel the flow - `Ctrl+C`: dismiss the entire flow immediately, even while editing a note or free-form answer -- `1..9`: select or toggle the matching option +- `1..9`: select or toggle the matching option; on the review tab, `1`, `2`, and `3` trigger `Submit`, `Elaborate`, and `Cancel` - `Space`: toggle the active option - `n`: edit the active option note - `Shift+N`: edit the current question note diff --git a/src/state/transitions.ts b/src/state/transitions.ts index 69605f9..30cf6a5 100644 --- a/src/state/transitions.ts +++ b/src/state/transitions.ts @@ -188,10 +188,20 @@ export function confirmCurrentSelection(state: AskState): AskState { } export function applyNumberShortcut(state: AskState, digit: number): AskState { - if (digit <= 0 || isSubmitTab(state)) { + if (digit <= 0) { return state; } + if (isSubmitTab(state)) { + if (digit > SUBMIT_ACTION_COUNT) { + return state; + } + return confirmCurrentSelection({ + ...state, + activeSubmitActionIndex: digit - 1, + }); + } + const question = getCurrentQuestion(state); if (!question) { return state; diff --git a/src/ui/constants.ts b/src/ui/constants.ts index ebc6bf9..e39d351 100644 --- a/src/ui/constants.ts +++ b/src/ui/constants.ts @@ -17,7 +17,7 @@ export const UI_TEXT = { unanswered: "→ unanswered", footerInput: " Enter submit · Esc close", footerNote: " Enter save · Esc close", - footerSubmit: " ↑↓ select · Enter confirm · Esc cancel", + footerSubmit: " 1..3 hotkeys · ↑↓ select · Enter confirm · Esc cancel", footerMulti: " ⇆ tab · ↑↓ select · Space toggle · Enter continue · N/Shift+N note · Esc dismiss", footerDefault: diff --git a/tests/state.test.ts b/tests/state.test.ts index 99b7650..018979a 100644 --- a/tests/state.test.ts +++ b/tests/state.test.ts @@ -556,6 +556,32 @@ test("tab navigation works with a single question", () => { assert.equal(state.view.kind, "navigate"); }); +test("submit tab number shortcuts trigger matching review actions", () => { + let state = createInitialState(sampleParams()); + state = moveTab(state, -1); + assert.equal(state.view.kind, "submit"); + + const submitted = applyNumberShortcut(state, 1); + assert.equal(submitted.completed, true); + assert.equal(submitted.cancelled, false); + assert.equal(submitted.mode, "submit"); + + const elaborated = applyNumberShortcut(state, 2); + assert.equal(elaborated.completed, true); + assert.equal(elaborated.cancelled, false); + assert.equal(elaborated.mode, "elaborate"); + + const cancelled = applyNumberShortcut(state, 3); + assert.equal(cancelled.completed, true); + assert.equal(cancelled.cancelled, true); + assert.equal(cancelled.mode, "submit"); + + const ignored = applyNumberShortcut(state, 4); + assert.equal(ignored.completed, false); + assert.equal(ignored.cancelled, false); + assert.equal(ignored.activeSubmitActionIndex, 0); +}); + test("escape cancels from main flow but only exits input and note modes when editing", () => { let state = createInitialState(sampleParams()); state = cancelFlow(state);