@bobfrankston/rmfmail 1.1.137 → 1.1.139

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.
@@ -701,7 +701,13 @@ async function createTinyMceEditor(container2, opts = {}) {
701
701
  // everything else so genuine HTML formatting (bold / italic /
702
702
  // tables / inline color) still comes through verbatim.
703
703
  content_style: [
704
- "body { font-family: system-ui, sans-serif; font-size: 14px; }",
704
+ // High-contrast caret: a 1-2 px slate-coloured I-beam vanishes
705
+ // against white especially on hi-DPI displays. caret-color
706
+ // recolours the native insertion bar; caret-shape:block (CSS
707
+ // UI L4, Chromium 125+) widens it into a solid block. The
708
+ // block falls back to the default bar where unsupported, so
709
+ // the color alone still buys most of the visibility win.
710
+ "body { font-family: system-ui, sans-serif; font-size: 14px; caret-color: #d32f2f; caret-shape: block; }",
705
711
  "blockquote { border-left: 3px solid #c0c8d0; margin: 0 0 0 4px; padding: 2px 0 2px 10px; color: #555; }",
706
712
  "div.reply { margin-top: 0.5em; }",
707
713
  "div.reply > p:first-child { color: #666; font-size: 0.95em; margin: 0 0 4px 0; }",
@@ -3723,13 +3729,23 @@ function setupAutocomplete(input) {
3723
3729
  const { start, end } = tokenSpanAtCaret(val, caret);
3724
3730
  return val.substring(start, end).trim();
3725
3731
  }
3726
- function replaceCaretToken(replacement) {
3732
+ function replaceCaretToken(replacement, contact) {
3727
3733
  const val = input.value;
3728
3734
  const caret = input.selectionStart ?? val.length;
3729
3735
  const { start, end } = tokenSpanAtCaret(val, caret);
3730
3736
  let before = val.substring(0, start);
3731
- const after = val.substring(end);
3737
+ let after = val.substring(end);
3732
3738
  before = before.replace(/[ \t,]+$/, "");
3739
+ if (contact) {
3740
+ const haystack = `${contact.name} ${contact.email}`.toLowerCase();
3741
+ const stripStranded = (s) => splitRecipients(s).map((p) => p.trim()).filter((p) => p.length > 0 && (p.includes("@") || !haystack.includes(p.toLowerCase()))).join(", ");
3742
+ if (before) before = stripStranded(before);
3743
+ const afterCore = after.replace(/^[\s,]+/, "").replace(/[\s,]+$/, "");
3744
+ if (afterCore) {
3745
+ const cleanedAfter = stripStranded(afterCore);
3746
+ after = cleanedAfter ? ", " + cleanedAfter : "";
3747
+ }
3748
+ }
3733
3749
  const lead = before.length ? ", " : "";
3734
3750
  const isLast = after.trim() === "";
3735
3751
  const insert = lead + replacement + (isLast ? ", " : "");
@@ -3812,7 +3828,7 @@ function setupAutocomplete(input) {
3812
3828
  e.preventDefault();
3813
3829
  if (e.button !== 0) return;
3814
3830
  const display = formatRecipient(r.name, r.email);
3815
- replaceCaretToken(display);
3831
+ replaceCaretToken(display, { name: r.name, email: r.email });
3816
3832
  });
3817
3833
  item.addEventListener("contextmenu", (e) => {
3818
3834
  e.preventDefault();