feat(ui): Arrow-Up in an empty composer edits your last message (LC-248) #301

Merged
longjacksonle merged 1 commit from feat/lc-248-arrowup-edit-last into main 2026-06-09 05:17:07 +02:00

Summary

Implements LC-248 (subtask LC-249). Press Up in an empty composer to jump straight into editing your most recent message (Slack/Discord pattern). Reuses the existing per-message edit route + inline form.

Implementation

  • Composer (room/composer.html): a keydown listener on the textarea. On Arrow-Up with no modifier, not composing, the textarea empty, and no mention/slash popover open, it finds the last button[hx-get$="/edit"] in #messages (that button only renders for the viewer's own editable messages, so the last one is the most recent own message) and clicks it, driving the existing GET /messages/{id}/edit swap. Empty-composer-only so Up still navigates the caret in a multi-line draft; the mention/slash combobox keydown handlers run in capture phase and stopPropagation when open, so they keep Arrow-Up while a popover is up (explicit guard backs that up).
  • Edit form (room/edit_form.html): add autofocus to the input so the global after-swap focus handler (layout.html) lands the caret in the editor - this also improves the hover "Edit" path - plus an Escape keydown that triggers the existing Cancel control to restore the message. Enter already saves (form submit).

Scope

Most recent own message in the main #messages list, rooms and DMs. Thread panel out of scope.

Tests

  • The room page ships the shortcut (__lcEditLast); the edit form input carries autofocus.
  • The find-last-and-click and Esc-cancel interactions are JS-only (LC-249 QA pass).
  • just test and just test-saas green; clippy + fmt clean.

No operator-visible surface, so no [operator-action] marker.

🤖 Generated with Claude Code

## Summary Implements LC-248 (subtask LC-249). Press Up in an empty composer to jump straight into editing your most recent message (Slack/Discord pattern). Reuses the existing per-message edit route + inline form. ## Implementation - **Composer** (`room/composer.html`): a keydown listener on the textarea. On Arrow-Up with no modifier, not composing, the textarea empty, and no mention/slash popover open, it finds the last `button[hx-get$="/edit"]` in `#messages` (that button only renders for the viewer's own editable messages, so the last one is the most recent own message) and clicks it, driving the existing `GET /messages/{id}/edit` swap. Empty-composer-only so Up still navigates the caret in a multi-line draft; the mention/slash combobox keydown handlers run in capture phase and `stopPropagation` when open, so they keep Arrow-Up while a popover is up (explicit guard backs that up). - **Edit form** (`room/edit_form.html`): add `autofocus` to the input so the global after-swap focus handler (`layout.html`) lands the caret in the editor - this also improves the hover "Edit" path - plus an `Escape` keydown that triggers the existing Cancel control to restore the message. Enter already saves (form submit). ## Scope Most recent own message in the main `#messages` list, rooms and DMs. Thread panel out of scope. ## Tests - The room page ships the shortcut (`__lcEditLast`); the edit form input carries `autofocus`. - The find-last-and-click and Esc-cancel interactions are JS-only (LC-249 QA pass). - `just test` and `just test-saas` green; clippy + fmt clean. No operator-visible surface, so no `[operator-action]` marker. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
feat(ui): Arrow-Up in an empty composer edits your last message (LC-248)
All checks were successful
check-secrets / Nosey parker (push) Successful in 4s
check-secrets / Kingfisher (push) Successful in 8s
check-secrets / TruffleHog (push) Successful in 8s
check-secrets / TruffleHog (pull_request) Successful in 4s
check-secrets / Nosey parker (pull_request) Successful in 6s
check-secrets / Kingfisher (pull_request) Successful in 6s
Create release / Create release from merged PR (pull_request) Has been skipped
Check / clippy + fmt + tests (pull_request) Successful in 2m9s
8fa338c88c
Press Up in an empty composer to jump straight into editing your most recent message (Slack/Discord pattern). Reuses the existing per-message edit route + inline form.

Composer (room/composer.html): a keydown listener on the textarea. On Arrow-Up with no modifier, not composing, the textarea empty, and no mention/slash popover open, it finds the last `button[hx-get$="/edit"]` in #messages - the edit button only renders for the viewer's own editable messages, so the last one is the most recent own message - and clicks it, driving the existing GET /messages/{id}/edit swap. Empty-composer-only so Up still navigates the caret in a multi-line draft; the mention/slash combobox keydown handlers run in capture phase and stopPropagation when open, so they keep Arrow-Up while a popover is up (an explicit guard backs that up).

Edit form (room/edit_form.html): add `autofocus` to the input so the global after-swap focus handler (layout.html) lands the caret in the editor - this also improves the hover "Edit" path - plus an Escape keydown that triggers the existing Cancel control to restore the message. Enter already saves (form submit).

Scope: most recent own message in the main #messages list, rooms and DMs; thread panel out of scope.

Tests: the room page ships the shortcut (`__lcEditLast`) and the edit form input carries `autofocus`. The find-last-and-click and Esc-cancel interactions are JS-only and fall to the LC-249 QA pass. just test and just test-saas green; clippy + fmt clean.

#LC-248
#LC-249

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
longjacksonle deleted branch feat/lc-248-arrowup-edit-last 2026-06-09 05:17:07 +02:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
psa-systems/lets-chat!301
No description provided.