From dddf79ec2f82807fef6f71a18ebe1998a449540f Mon Sep 17 00:00:00 2001 From: npeter83 Date: Sun, 27 Sep 2026 15:02:42 +0200 Subject: [PATCH] refactor(ui): FilterSelect and Combobox draw their checks with MenuCheck They still painted their own 14px box beside the menus' 16px MenuCheck. A contract test holds the filled-box paint to MenuCheck alone. --- frontend/src/components/ui/Combobox.tsx | 11 +++-------- frontend/src/components/ui/FilterSelect.tsx | 14 ++------------ .../components/ui/menuCheck.contract.test.ts | 19 +++++++++++++++++++ 3 files changed, 24 insertions(+), 20 deletions(-) create mode 100644 frontend/src/components/ui/menuCheck.contract.test.ts diff --git a/frontend/src/components/ui/Combobox.tsx b/frontend/src/components/ui/Combobox.tsx index aa87f9ee..5b1eebfc 100644 --- a/frontend/src/components/ui/Combobox.tsx +++ b/frontend/src/components/ui/Combobox.tsx @@ -1,7 +1,8 @@ import clsx from "clsx"; import { useCallback, useEffect, useMemo, useRef, useState, type ReactNode } from "react"; import { useTranslation } from "react-i18next"; -import { Check, ChevronDown } from "lucide-react"; +import { ChevronDown } from "lucide-react"; +import { MenuCheck } from "./MenuCheck"; import { PopoverSurface, PopoverItem } from "./AnchoredPopover"; import { useAnchoredPopover } from "./anchoredPopoverHooks"; import { useScrollFade } from "../../lib/useScrollFade"; @@ -285,13 +286,7 @@ export default function Combobox({ renderOption(o, on) ) : ( <> - - {on && } - + {o.label ?? o.value} {o.count != null && ( diff --git a/frontend/src/components/ui/FilterSelect.tsx b/frontend/src/components/ui/FilterSelect.tsx index 49a821be..d310cc06 100644 --- a/frontend/src/components/ui/FilterSelect.tsx +++ b/frontend/src/components/ui/FilterSelect.tsx @@ -1,5 +1,5 @@ import { useState } from "react"; -import { Check } from "lucide-react"; +import { MenuCheck } from "./MenuCheck"; import { SelectTrigger } from "./SelectTrigger"; import { PopoverItem, PopoverSurface } from "./AnchoredPopover"; import { useAnchoredPopover } from "./anchoredPopoverHooks"; @@ -129,17 +129,7 @@ export default function FilterSelect({ on ? "text-fg" : "text-muted" }`} > - {multiple ? ( - - {on && } - - ) : ( - - )} + {o.label} {o.count != null && ( {o.count} diff --git a/frontend/src/components/ui/menuCheck.contract.test.ts b/frontend/src/components/ui/menuCheck.contract.test.ts new file mode 100644 index 00000000..3d9a97f0 --- /dev/null +++ b/frontend/src/components/ui/menuCheck.contract.test.ts @@ -0,0 +1,19 @@ +import { readdirSync, readFileSync } from "node:fs"; +import { describe, expect, it } from "vitest"; + +// E28 review L2: `ui/MenuCheck` is the ONE drawn check box of a checkable row (S3e3b replaced seven +// hand-drawn copies), yet FilterSelect and Combobox still painted their own — a 14px box beside the +// menus' 16px one. The filled-box paint is the tell: it may live in MenuCheck only. +describe("the drawn check box", () => { + it("is painted by MenuCheck alone", () => { + const root = new URL("../", import.meta.url); + const offenders = readdirSync(root, { recursive: true, encoding: "utf8" }) + .filter((f) => f.endsWith(".tsx") && !f.includes(".test.") && !f.endsWith("MenuCheck.tsx")) + .filter((f) => + /border-accent bg-accent text-accent-fg/.test( + readFileSync(new URL(f.replace(/\\/g, "/"), root), "utf8"), + ), + ); + expect(offenders).toEqual([]); + }); +});