diff --git a/frontend/src/components/palette/ComponentPalette.tsx b/frontend/src/components/palette/ComponentPalette.tsx index a2bca62..54bb445 100644 --- a/frontend/src/components/palette/ComponentPalette.tsx +++ b/frontend/src/components/palette/ComponentPalette.tsx @@ -349,11 +349,14 @@ export function ComponentPalette({ new Set(['compute', 'integration', 'security', 'tools', 'connectors']) ); - // Filter items based on search query + // Filter items based on search query. Trim BEFORE matching — an untrimmed + // query like "a " excludes items that contain "a" but not "a " (trailing + // whitespace should never change search results); Property 41 checks the + // trimmed semantics. const filteredItems = useMemo(() => { if (!searchQuery.trim()) return PALETTE_ITEMS; - const query = searchQuery.toLowerCase(); + const query = searchQuery.trim().toLowerCase(); return PALETTE_ITEMS.filter( (item) => item.label.toLowerCase().includes(query) || diff --git a/frontend/src/utils/paletteSearch.test.ts b/frontend/src/utils/paletteSearch.test.ts index ca1a3f1..da53b76 100644 --- a/frontend/src/utils/paletteSearch.test.ts +++ b/frontend/src/utils/paletteSearch.test.ts @@ -20,7 +20,11 @@ import { PALETTE_ITEMS, type PaletteItem } from '../components/palette/Component export function filterPaletteItems(items: PaletteItem[], query: string): PaletteItem[] { if (!query.trim()) return items; - const normalizedQuery = query.toLowerCase(); + // Trim BEFORE matching (mirrors ComponentPalette): a query like "a " must + // match the same items as "a" — trailing whitespace never changes results. + // Without the trim, the exclusion property fails on counterexamples like + // "A " (item contains "a" but not "a "). + const normalizedQuery = query.trim().toLowerCase(); return items.filter( (item) => item.label.toLowerCase().includes(normalizedQuery) ||