From 5142823b7edda7d67a44854ad24717bd0d9301ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Bombeck?= Date: Fri, 12 Jun 2026 19:35:11 +0200 Subject: [PATCH] fix(ui): the filter pills open their menu on screen again MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The pill trigger paints its own label spans and mounts no SelectValue, and Radix's item-aligned placement silently skips all positioning when the value node is absent — the open menu laid out below the height-locked app shell, fully off-viewport, which reads as a dead control. The mood and type/source pills on the mood and measurements lists were affected since the unified filter rail landed in v1.16.1. Popper placement has no value-node dependency and anchors the menu under the pill like the date-range popover next to it. --- ...t.tsx => medication-order-editor.test.tsx} | 0 .../ui/__tests__/filter-bar.test.tsx | 20 +++++++++++++++++++ src/components/ui/filter-bar.tsx | 9 ++++++++- 3 files changed, 28 insertions(+), 1 deletion(-) rename src/components/medications/__tests__/{medication-reorder-dialog.test.tsx => medication-order-editor.test.tsx} (100%) diff --git a/src/components/medications/__tests__/medication-reorder-dialog.test.tsx b/src/components/medications/__tests__/medication-order-editor.test.tsx similarity index 100% rename from src/components/medications/__tests__/medication-reorder-dialog.test.tsx rename to src/components/medications/__tests__/medication-order-editor.test.tsx diff --git a/src/components/ui/__tests__/filter-bar.test.tsx b/src/components/ui/__tests__/filter-bar.test.tsx index 5830b2e0f..bde2d54db 100644 --- a/src/components/ui/__tests__/filter-bar.test.tsx +++ b/src/components/ui/__tests__/filter-bar.test.tsx @@ -1,4 +1,6 @@ import { describe, expect, it } from "vitest"; +import { readFileSync } from "node:fs"; +import { join } from "node:path"; import { renderToStaticMarkup } from "react-dom/server"; import { I18nProvider } from "@/lib/i18n/context"; @@ -141,3 +143,21 @@ describe("FilterBar shell", () => { expect(html).toContain('aria-label="Filter entfernen: Quelle"'); }); }); + +describe("FilterBarSelect — menu positioning (source pin)", () => { + // The pill trigger paints its own label spans and mounts no + // ``. Radix's default item-aligned placement silently + // skips ALL positioning when the value node is absent — the open + // menu then lays out below the height-locked app shell, fully + // off-viewport, which users report as "clicking does nothing". SSR + // markup cannot exercise an open portal, so this pins the source: + // the content must request popper placement, which has no + // value-node dependency. + it("requests popper placement on the select content", () => { + const src = readFileSync( + join(process.cwd(), "src/components/ui/filter-bar.tsx"), + "utf8", + ); + expect(src).toMatch(//); + }); +}); diff --git a/src/components/ui/filter-bar.tsx b/src/components/ui/filter-bar.tsx index 599ecdadd..4df8852b8 100644 --- a/src/components/ui/filter-bar.tsx +++ b/src/components/ui/filter-bar.tsx @@ -175,7 +175,14 @@ export function FilterBarSelect({ {label} )} - + {/* `position="popper"` is load-bearing: this trigger paints its + own label spans and mounts no `SelectValue`, and Radix's + default item-aligned placement silently skips ALL positioning + when the value node is absent — the open menu then lays out + below the height-locked app shell, fully off-viewport. Popper + placement has no value-node dependency and anchors the menu + under the pill like the date-range popover next to it. */} + {allLabel} {options.map((opt) => (