@bobfrankston/rmfmail 1.1.161 → 1.1.162

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.ts CHANGED
@@ -3371,6 +3371,7 @@ viewBtn?.addEventListener("click", (e) => {
3371
3371
  // it renders in the expected position-absolute location.
3372
3372
  restoreToolbarDropdown("view-dropdown", "view-menu");
3373
3373
  if (viewDropdown) viewDropdown.hidden = !viewDropdown.hidden;
3374
+ refreshToolbarOverlayShield();
3374
3375
  });
3375
3376
  // Capture-phase pointerdown so we run BEFORE any handler that calls
3376
3377
  // stopPropagation. The earlier bubble-phase click listener missed clicks
@@ -3391,7 +3392,45 @@ document.addEventListener("pointerdown", (e) => {
3391
3392
  if (settingsDropdown && !settingsDropdown.hidden && !target.closest("#settings-menu") && !target.closest("#settings-dropdown")) {
3392
3393
  settingsDropdown.hidden = true;
3393
3394
  }
3395
+ refreshToolbarOverlayShield();
3394
3396
  }, true);
3397
+
3398
+ // Click-to-dismiss for the toolbar dropdowns relies on `pointerdown` firing
3399
+ // on the parent document. Clicks inside the compose iframe stay in the
3400
+ // iframe's document and never bubble out, so a Settings/View menu opened
3401
+ // over compose used to stay stuck until the user hit Escape or the toolbar
3402
+ // button again. Shield the overlay with a transparent fullscreen catcher
3403
+ // while any toolbar dropdown is open — its pointerdown lands here in the
3404
+ // parent doc, triggering the same outside-click close. The shield sits
3405
+ // above compose (z 1600) but below the dropdown itself (z 2000).
3406
+ function refreshToolbarOverlayShield(): void {
3407
+ const dropdownOpen = ["settings-dropdown", "view-dropdown", "restart-dropdown"]
3408
+ .some(id => {
3409
+ const el = document.getElementById(id);
3410
+ return el && !el.hidden;
3411
+ });
3412
+ const hasOverlay = !!document.querySelector(".compose-overlay, .popout-overlay");
3413
+ let shield = document.getElementById("tb-overlay-shield");
3414
+ if (dropdownOpen && hasOverlay) {
3415
+ if (!shield) {
3416
+ shield = document.createElement("div");
3417
+ shield.id = "tb-overlay-shield";
3418
+ shield.style.cssText = "position:fixed;inset:0;z-index:1999;background:transparent;";
3419
+ shield.addEventListener("pointerdown", (ev) => {
3420
+ ev.preventDefault();
3421
+ ev.stopPropagation();
3422
+ for (const id of ["settings-dropdown", "view-dropdown", "restart-dropdown"]) {
3423
+ const dd = document.getElementById(id);
3424
+ if (dd) dd.hidden = true;
3425
+ }
3426
+ shield?.remove();
3427
+ });
3428
+ document.body.appendChild(shield);
3429
+ }
3430
+ } else if (shield) {
3431
+ shield.remove();
3432
+ }
3433
+ }
3395
3434
  // Escape always closes any open dropdown/backdrop, regardless of how it was
3396
3435
  // opened or whether an outside-click handler missed firing. Last-resort
3397
3436
  // escape hatch for the "stuck modal" case.
@@ -3406,7 +3445,10 @@ document.addEventListener("keydown", (e) => {
3406
3445
  if (bd) { bd.remove(); closed = true; }
3407
3446
  const themeSub = document.getElementById("theme-submenu");
3408
3447
  if (themeSub && !themeSub.hidden) { themeSub.hidden = true; closed = true; }
3409
- if (closed) e.preventDefault();
3448
+ if (closed) {
3449
+ e.preventDefault();
3450
+ refreshToolbarOverlayShield();
3451
+ }
3410
3452
  });
3411
3453
 
3412
3454
  // Restore saved view settings
@@ -4385,6 +4427,7 @@ settingsBtn?.addEventListener("click", (e) => {
4385
4427
  if (restartDd) restartDd.hidden = true;
4386
4428
  restoreToolbarDropdown("settings-dropdown", "settings-menu");
4387
4429
  if (settingsDropdown) settingsDropdown.hidden = !settingsDropdown.hidden;
4430
+ refreshToolbarOverlayShield();
4388
4431
  });
4389
4432
  // Close handled by the shared document click handler above
4390
4433
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bobfrankston/rmfmail",
3
- "version": "1.1.161",
3
+ "version": "1.1.162",
4
4
  "description": "Local-first email client with IMAP sync and standalone native app",
5
5
  "type": "module",
6
6
  "main": "bin/mailx.js",
@@ -38,7 +38,7 @@
38
38
  "dependencies": {
39
39
  "@bobfrankston/iflow-direct": "^0.1.50",
40
40
  "@bobfrankston/mailx-host": "^0.1.13",
41
- "@bobfrankston/mailx-imap": "^0.1.63",
41
+ "@bobfrankston/mailx-imap": "^0.1.64",
42
42
  "@bobfrankston/mailx-store-web": "^0.1.24",
43
43
  "@bobfrankston/mailx-sync": "^0.1.19",
44
44
  "@bobfrankston/miscinfo": "^1.0.12",
@@ -118,7 +118,7 @@
118
118
  "dependencies": {
119
119
  "@bobfrankston/iflow-direct": "^0.1.50",
120
120
  "@bobfrankston/mailx-host": "^0.1.13",
121
- "@bobfrankston/mailx-imap": "^0.1.63",
121
+ "@bobfrankston/mailx-imap": "^0.1.64",
122
122
  "@bobfrankston/mailx-store-web": "^0.1.24",
123
123
  "@bobfrankston/mailx-sync": "^0.1.19",
124
124
  "@bobfrankston/miscinfo": "^1.0.12",