From 5f2c4dd5bda5c25c5732180ac0ec19e5d374e882 Mon Sep 17 00:00:00 2001 From: le king fu Date: Mon, 19 Oct 2026 21:06:22 -0400 Subject: [PATCH] fix(combobox): follow the input when a render moves it (#429) Review 25431: a window centered on screen grows when its content arrives, and moves its fields with no scroll nor resize; the open list, placed in a portal, stayed where it was. While open, the combobox now reads its position again after every render (useLayoutEffect without dependencies); `keepPlacement` hands back the same state object for an unchanged position, so React renders nothing more. Pinned by CategoryCombobox.placement.test.ts (harness, useLayoutEffect mapped on its useEffect, fake input) and keepPlacement's own tests. The boundary test of placeListbox now sits at exactly 240 px below with room above (point 1), and AddKeywordDialog's comment no longer claims the list is cut (point 3). Co-Authored-By: Claude Opus 5.5 --- .../categories/AddKeywordDialog.tsx | 7 +- .../shared/CategoryCombobox.placement.test.ts | 105 ++++++++++++++++++ src/components/shared/CategoryCombobox.tsx | 13 ++- src/components/shared/placeListbox.test.ts | 33 +++++- src/components/shared/placeListbox.ts | 13 +++ 5 files changed, 161 insertions(+), 10 deletions(-) create mode 100644 src/components/shared/CategoryCombobox.placement.test.ts diff --git a/src/components/categories/AddKeywordDialog.tsx b/src/components/categories/AddKeywordDialog.tsx index 69c12ee..a67ef6b 100644 --- a/src/components/categories/AddKeywordDialog.tsx +++ b/src/components/categories/AddKeywordDialog.tsx @@ -146,9 +146,10 @@ export default function AddKeywordDialog({

{t("reports.keyword.dialogTitle")}

- {/* The two fields sit outside the scrolling block, so the open category - list is drawn over the preview below instead of being cut by its - scrollport. */} + {/* The two fields sit outside the scrolling block, so they stay in view + while the preview scrolls. The open category list does not depend + on it any more: since #429 it lives in a portal on document.body, + where no scrollport cuts it. */}