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 */}
-
+