From b866d2b99da27796d231cd7992a5bdbcdcd6b5f4 Mon Sep 17 00:00:00 2001 From: Matthew Meszaros Date: Sun, 19 Jul 2026 10:21:25 +0200 Subject: [PATCH] feat: harden the From menu's tag filter and search field: tag chips now derive from the store's mailbox directory sorted by position instead of the candidates fetch (so they show even while candidates load), the search input gets a real slate border instead of the invisible white-on-white fill, and the panel clamps against clientWidth so its right edge cannot slip under a scrollbar --- .../app/unibox/compose/MailboxPicker.tsx | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/web/src/components/app/unibox/compose/MailboxPicker.tsx b/web/src/components/app/unibox/compose/MailboxPicker.tsx index f7d0a606..41f32770 100644 --- a/web/src/components/app/unibox/compose/MailboxPicker.tsx +++ b/web/src/components/app/unibox/compose/MailboxPicker.tsx @@ -48,7 +48,9 @@ export default function MailboxPicker({ value, onChange, candidates, loading }: const el = boxRef.current; if (!el) return; const r = el.getBoundingClientRect(); - const vw = window.innerWidth; + // clientWidth excludes any scrollbar; innerWidth would let the + // panel's right edge slide underneath it. + const vw = document.documentElement.clientWidth; const vh = window.innerHeight; const left = Math.min(Math.max(r.left, 8), vw - PANEL_WIDTH - 8); // Flip above the trigger when the space below is tight. @@ -83,11 +85,16 @@ export default function MailboxPicker({ value, onChange, candidates, loading }: return m; }, [storeEmails]); + // Derived from the store's mailbox directory, not the candidates + // response, so the chips render even while candidates are still + // loading for a new recipient. const usedTags = React.useMemo(() => { const used = new Set(); - for (const a of accounts) for (const t of tagsByAccount.get(a.id) ?? []) used.add(t); - return storeTags.filter((t) => used.has(t.id)); - }, [accounts, storeTags, tagsByAccount]); + for (const e of storeEmails) for (const t of e.tags ?? []) used.add(t); + return storeTags + .filter((t) => used.has(t.id)) + .sort((a, b) => a.position - b.position); + }, [storeEmails, storeTags]); const filtered = React.useMemo(() => { const q = search.trim().toLowerCase(); @@ -162,7 +169,7 @@ export default function MailboxPicker({ value, onChange, candidates, loading }: > {/* Search + tag filter header */}
-
+