diff --git a/src/app/globals.css b/src/app/globals.css index d0971df7b1..b370d0fd53 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -1236,6 +1236,16 @@ summary::-webkit-details-marker { min-width: 0; } +.smart-search-suggestion-row { + display: none; +} + +@media (min-width: 1024px) { + .smart-search-suggestion-row { + display: flex; + } +} + .answer-suggestion-label { color: var(--text-soft); font-size: 0.6875rem; diff --git a/src/components/clinical-dashboard/universal-search-command-surface.tsx b/src/components/clinical-dashboard/universal-search-command-surface.tsx index 180cfa2e6e..3052409011 100644 --- a/src/components/clinical-dashboard/universal-search-command-surface.tsx +++ b/src/components/clinical-dashboard/universal-search-command-surface.tsx @@ -8,6 +8,7 @@ import { type ModeActionId, type ModeActionSetId, } from "@/components/clinical-dashboard/mode-action-popup"; +import { AnswerSuggestionChips } from "@/components/clinical-dashboard/answer-suggestion-chips"; import { cn } from "@/components/ui-primitives"; import { appModeDefinition, type AppModeId } from "@/lib/app-modes"; import { appModeIcons } from "@/lib/app-mode-icons"; @@ -53,6 +54,19 @@ function OptionShell({ active, children, hint }: { active: boolean; children: Re export type CommandSurfacePlacement = "bottom-dock" | "inline"; +function ContextHintRow({ examples, onPickExample }: { examples: string[]; onPickExample: (example: string) => void }) { + return ( + + ); +} + function ScopeChipRow({ scopes, activeScopes, @@ -531,6 +545,14 @@ export function UniversalSearchCommandSurface({ placement === "bottom-dock" ? "gap-1" : "gap-2", )} > + { + onQueryChange(example); + onDropdownOpenChange(true); + onFocusSearchInput?.(); + }} + />
{ diff --git a/tests/ui-overlap.spec.ts b/tests/ui-overlap.spec.ts index 209abe4894..22a8d994e8 100644 --- a/tests/ui-overlap.spec.ts +++ b/tests/ui-overlap.spec.ts @@ -153,4 +153,42 @@ test.describe("Header element overlap coverage", () => { ).toBeLessThanOrEqual(geometry!.clearLeft + 1); }); } + + test("desktop smart search keeps suggested words above the composer", async ({ page }) => { + await page.setViewportSize({ width: 1280, height: 900 }); + await mockDemoDashboard(page); + await gotoHome(page); + + const suggestionRow = page.getByTestId("smart-search-suggestion-row"); + await expect(suggestionRow).toBeVisible(); + await expect(suggestionRow.getByRole("button", { name: "lithium level timing" })).toBeVisible(); + await expect(suggestionRow.getByRole("button", { name: "clozapine ANC monitoring" })).toBeVisible(); + + const geometry = await page.evaluate(() => { + const row = document.querySelector('[data-testid="smart-search-suggestion-row"]'); + const input = document.querySelector('[data-testid="global-search-input"]'); + if (!row || !input) return null; + const rowRect = row.getBoundingClientRect(); + const inputRect = input.getBoundingClientRect(); + return { rowBottom: rowRect.bottom, inputTop: inputRect.top }; + }); + + expect(geometry, "suggestion row and smart search input must render").not.toBeNull(); + expect(geometry!.rowBottom, "suggestions should sit above the smart search bar").toBeLessThanOrEqual( + geometry!.inputTop + 1, + ); + + await suggestionRow.getByRole("button", { name: "lithium level timing" }).click(); + await expect(page.locator('[data-testid="global-search-input"]:visible').first()).toHaveValue( + "lithium level timing", + ); + }); + + test("phone smart search does not show the desktop suggested words row", async ({ page }) => { + await page.setViewportSize({ width: 390, height: 820 }); + await mockDemoDashboard(page); + await gotoHome(page); + + await expect(page.getByTestId("smart-search-suggestion-row")).toBeHidden(); + }); });