@bobfrankston/rmfmail 1.1.102 → 1.1.104

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/client/app.js CHANGED
@@ -3044,20 +3044,19 @@ document.addEventListener("keydown", (e) => {
3044
3044
  }
3045
3045
  }
3046
3046
  // Ctrl+D or Delete = Delete selected messages.
3047
- // P15: don't hijack Delete inside text inputs / textareas / contenteditable
3048
- // JSONC editor's Delete key was being eaten because we always preventDefault'd.
3049
- // 2026-05-09 fix: if the LIST has multiple selected rows, the user
3050
- // clearly means "delete those" regardless of where focus is — search
3051
- // input retaining focus after filtering shouldn't make the key dead.
3052
- // Only defer to native behavior when there's no list selection AND
3053
- // focus is in a text-editing surface.
3047
+ // Focus is the only signal. Text input has focus Delete is a native
3048
+ // character edit, ALWAYS. List has focus (a row, the list container,
3049
+ // anything outside a text editor) Delete acts on the list selection,
3050
+ // single or multi. The 2026-05-09 "multi-select while typing" carve-out
3051
+ // is gone it cost Bob real messages 2026-05-20 by hard-deleting the
3052
+ // auto-selected row every time he hit Delete to backspace in the search
3053
+ // input.
3054
3054
  if ((e.ctrlKey && e.key === "d") || e.key === "Delete") {
3055
3055
  const t = e.target;
3056
3056
  const tag = t?.tagName;
3057
3057
  const editable = t?.isContentEditable;
3058
3058
  const inEditable = tag === "INPUT" || tag === "TEXTAREA" || tag === "SELECT" || editable;
3059
- const listSelectionCount = document.querySelectorAll("#ml-body .ml-row.selected").length;
3060
- if (inEditable && listSelectionCount === 0)
3059
+ if (inEditable)
3061
3060
  return;
3062
3061
  e.preventDefault();
3063
3062
  deleteSelection();
@@ -3078,10 +3077,18 @@ document.addEventListener("keydown", (e) => {
3078
3077
  e.preventDefault();
3079
3078
  document.getElementById("btn-sync")?.click();
3080
3079
  }
3081
- // R = Toggle read/unread
3082
- if (e.key.toLowerCase() === "r" && !e.ctrlKey && !e.metaKey && !e.altKey) {
3080
+ // R (no modifiers) or Ctrl+Q = Toggle read/unread on the focused row.
3081
+ // Ctrl+Q mirrors the Outlook-style "mark read/unread" combo so it works
3082
+ // even when focus is in a text input (Ctrl-modifier guarantees no
3083
+ // collision with typing). Bare R defers when typing.
3084
+ const isToggleSeen = (e.key.toLowerCase() === "r" && !e.ctrlKey && !e.metaKey && !e.altKey) ||
3085
+ (e.ctrlKey && !e.metaKey && !e.altKey && e.key.toLowerCase() === "q");
3086
+ if (isToggleSeen) {
3083
3087
  const active = document.activeElement;
3084
- if (active && (active.tagName === "INPUT" || active.tagName === "TEXTAREA" || active.tagName === "SELECT"))
3088
+ const inText = active && (active.tagName === "INPUT" || active.tagName === "TEXTAREA" || active.tagName === "SELECT" || active.isContentEditable);
3089
+ // Bare R yields to text inputs; Ctrl+Q overrides them so it's reachable
3090
+ // from the search box or compose draft list.
3091
+ if (!e.ctrlKey && inText)
3085
3092
  return;
3086
3093
  const sel = getCurrentFocused();
3087
3094
  if (!sel)