@bobfrankston/rmfmail 1.2.126 → 1.2.128

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
@@ -1040,7 +1040,15 @@ async function openCompose(mode, overrideMsg, overrideAccountId) {
1040
1040
  mode === "editAsNew" ? "Edit as new" :
1041
1041
  "Compose";
1042
1042
  const titleSubject = mode === "new" ? "" : (msg?.subject || "");
1043
- const frame = showComposeOverlay(titleSubject ? `${titlePrefix}: ${titleSubject}` : titlePrefix);
1043
+ const composeTitle = titleSubject ? `${titlePrefix}: ${titleSubject}` : titlePrefix;
1044
+ // Default: compose/reply/forward open in their OWN OS window — an
1045
+ // overlay covering the message list/preview is the thing Bob wants gone
1046
+ // (2026-07-12 "the default on a reply should just be a separate window
1047
+ // outside the frame"). Overlay remains: small screens, Android (no
1048
+ // popout host), Settings toggle off, or daemon spawn failure.
1049
+ const preferWindow = window.innerWidth > 768 && window.innerHeight > 600
1050
+ && localStorage.getItem("mailx-compose-in-window") !== "0";
1051
+ let frame = preferWindow ? null : showComposeOverlay(composeTitle);
1044
1052
  // Now finish initialisation off the critical path — editor bootstrap
1045
1053
  // inside the iframe runs concurrently with this await.
1046
1054
  const accounts = await accountsP;
@@ -1253,6 +1261,19 @@ async function openCompose(mode, overrideMsg, overrideAccountId) {
1253
1261
  // payload so the iframe can populate even when storage doesn't bridge.
1254
1262
  // sessionStorage remains as the fast-path for iframes that finish
1255
1263
  // loading before postMessage fires.
1264
+ if (preferWindow && !frame) {
1265
+ try {
1266
+ const { popoutCompose } = await import("./lib/api-client.js");
1267
+ const r = await popoutCompose(init);
1268
+ if (r?.ok)
1269
+ return;
1270
+ console.error("[compose] separate-window open failed — overlay fallback:", r?.reason);
1271
+ }
1272
+ catch (e) {
1273
+ console.error("[compose] separate-window open threw — overlay fallback:", e?.message || e);
1274
+ }
1275
+ frame = showComposeOverlay(composeTitle);
1276
+ }
1256
1277
  const initJson = JSON.stringify(init);
1257
1278
  try {
1258
1279
  sessionStorage.setItem("composeInit", initJson);
@@ -5627,12 +5648,32 @@ getSettings().then((s) => {
5627
5648
  optEditorTiptap.checked = ed === "tiptap";
5628
5649
  if (optEditorTinymce)
5629
5650
  optEditorTinymce.checked = ed === "tinymce";
5651
+ const cwEl = document.getElementById("opt-compose-window");
5652
+ if (cwEl) {
5653
+ const inWindow = s.ui?.composeInWindow !== false;
5654
+ cwEl.checked = inWindow;
5655
+ try {
5656
+ localStorage.setItem("mailx-compose-in-window", inWindow ? "1" : "0");
5657
+ }
5658
+ catch { /* */ }
5659
+ }
5630
5660
  const fontEl = document.getElementById("opt-compose-font-size");
5631
5661
  if (fontEl) {
5632
5662
  const px = Number(s.ui?.composeFontSize);
5633
5663
  fontEl.value = String(Number.isFinite(px) && px >= 8 && px <= 32 ? px : 15);
5634
5664
  }
5635
5665
  }).catch(() => { });
5666
+ document.getElementById("opt-compose-window")?.addEventListener("change", (e) => {
5667
+ const on = e.target.checked;
5668
+ try {
5669
+ localStorage.setItem("mailx-compose-in-window", on ? "1" : "0");
5670
+ }
5671
+ catch { /* */ }
5672
+ getSettings().then((settings) => {
5673
+ settings.ui = { ...settings.ui, composeInWindow: on };
5674
+ saveSettings(settings);
5675
+ }).catch(() => { });
5676
+ });
5636
5677
  // Unified compose editing font size (px). Same sync-cache-then-persist shape
5637
5678
  // as saveEditorSetting: compose.ts reads `mailx-compose-font-size` from
5638
5679
  // localStorage at module load, so the very next compose-open is correct.