From 65651a0e862fdde8e9ab23e7c9530c55c3633243 Mon Sep 17 00:00:00 2001 From: BigSimmo <87357024+BigSimmo@users.noreply.github.com> Date: Wed, 12 Aug 2026 13:43:50 +0800 Subject: [PATCH 1/2] fix(ui): restore phone suggestion ticker --- src/components/ClinicalDashboard.tsx | 1 + .../global-search-shell.tsx | 1 + .../master-search-header.tsx | 4 + .../universal-search-command-surface.tsx | 99 ++++++++++++++++--- tests/ui-overlap.spec.ts | 16 ++- 5 files changed, 109 insertions(+), 12 deletions(-) diff --git a/src/components/ClinicalDashboard.tsx b/src/components/ClinicalDashboard.tsx index 05fb92a664..f33ccf8e36 100644 --- a/src/components/ClinicalDashboard.tsx +++ b/src/components/ClinicalDashboard.tsx @@ -3366,6 +3366,7 @@ export function ClinicalDashboard({ composerFollowUpSuggestions={searchMode === "answer" ? answerFollowUpSuggestions : undefined} onPickComposerFollowUpSuggestion={handlePickFollowUpSuggestion} composerFollowUpSuggestionsDisabled={loading} + showPhoneSuggestionTickerOnHome={showSharedHome} sharedHomeIdentity={showSharedHome} composerPlaceholder={searchMode === "answer" && latestAnswerQuery ? "Ask a follow-up..." : undefined} mobileSearchPlacement={hasMobileBottomSearch ? "bottom" : "default"} diff --git a/src/components/clinical-dashboard/global-search-shell.tsx b/src/components/clinical-dashboard/global-search-shell.tsx index 651a4cb0c3..84247b396a 100644 --- a/src/components/clinical-dashboard/global-search-shell.tsx +++ b/src/components/clinical-dashboard/global-search-shell.tsx @@ -877,6 +877,7 @@ function GlobalStandaloneSearchShellBody({ differentialsCompareAddonActive ? differentialsMobileCompareAddonSlotId : undefined } desktopSearchPlacement={desktopSearchPlacement === "hero" && isStandaloneModeHome ? "hero" : "default"} + showPhoneSuggestionTickerOnHome={isStandaloneModeHome || pathname === "/"} searchComposerVisible={shouldShowSearchComposer} desktopHomeComposerSlotId={isStandaloneModeHome ? modeHomeDesktopComposerSlotId : undefined} desktopPageComposerSlotId={ diff --git a/src/components/clinical-dashboard/master-search-header.tsx b/src/components/clinical-dashboard/master-search-header.tsx index 1cc6aa23e3..e87b6c29a8 100644 --- a/src/components/clinical-dashboard/master-search-header.tsx +++ b/src/components/clinical-dashboard/master-search-header.tsx @@ -195,6 +195,7 @@ export function MasterSearchHeader({ mobileBottomSearchVariant = "default", desktopSearchPlacement = "default", searchComposerVisible = true, + showPhoneSuggestionTickerOnHome = false, desktopHomeComposerSlotId, desktopPageComposerSlotId, heroComposerBreakpoint = "all", @@ -250,6 +251,8 @@ export function MasterSearchHeader({ * content keeps maximum screen space. Every phone dock uses it now; the * "default" value remains for hosts that need the taller legacy dock. */ mobileBottomSearchVariant?: "default" | "compact"; + /** Show the compact phone suggestion ticker only for standalone-mode homes. */ + showPhoneSuggestionTickerOnHome?: boolean; desktopSearchPlacement?: "default" | "hero"; searchComposerVisible?: boolean; /** Mode-home slot the composer portals into so the search pill sits in the @@ -1816,6 +1819,7 @@ export function MasterSearchHeader({ onListboxIdReady={setCommandListboxId} onActiveItemIdChange={setCommandActiveItemId} onFocusSearchInput={handleFocusSearchInput} + showPhoneSuggestionTicker={showPhoneSuggestionTickerOnHome} >
void; +}) { const [activeExampleIndex, setActiveExampleIndex] = useState(0); + const [heldTickerExample, setHeldTickerExample] = useState(null); + const [isTickerHeld, setIsTickerHeld] = useState(false); const activeExample = examples[activeExampleIndex % examples.length]; useEffect(() => { + if (isTickerHeld) { + return; + } + if (examples.length <= 1) return; const intervalId = window.setInterval(() => { setActiveExampleIndex((current) => (current + 1) % examples.length); }, SMART_HINT_ROTATION_MS); return () => window.clearInterval(intervalId); - }, [examples]); + }, [examples, isTickerHeld]); + + const freezeTicker = useCallback(() => { + setHeldTickerExample(activeExample); + setIsTickerHeld(true); + }, [activeExample]); + + const releaseTicker = useCallback(() => { + setIsTickerHeld(false); + }, []); + + const resolvedTickerExample = isTickerHeld ? (heldTickerExample ?? activeExample) : activeExample; if (!activeExample) return null; return ( -
- Smart search - - - Try “{activeExample}” in {modeLabel}. - -
+ <> +
+ Smart search + + + Try “{activeExample}” in {modeLabel}. + +
+ {showPhoneTicker ? ( + + ) : null} + ); } @@ -364,6 +430,7 @@ export function UniversalSearchCommandSurface({ onFocusSearchInput, onListboxIdReady, onActiveItemIdChange, + showPhoneSuggestionTicker = false, placement = "inline", children, }: { @@ -384,6 +451,8 @@ export function UniversalSearchCommandSurface({ onFocusSearchInput?: () => void; onListboxIdReady?: (listboxId: string) => void; onActiveItemIdChange?: (activeItemId: string | null) => void; + /** Show the compact, tappable suggestion ticker below an in-flow phone home composer. */ + showPhoneSuggestionTicker?: boolean; placement?: CommandSurfacePlacement; children: ReactNode; }) { @@ -992,7 +1061,15 @@ export function UniversalSearchCommandSurface({ placement === "bottom-dock" ? "gap-1" : "gap-2", )} > - + { + onQueryChange(example); + onFocusSearchInput?.(); + }} + />
{ diff --git a/tests/ui-overlap.spec.ts b/tests/ui-overlap.spec.ts index 79923b3f6a..94ee44dbc1 100644 --- a/tests/ui-overlap.spec.ts +++ b/tests/ui-overlap.spec.ts @@ -266,12 +266,26 @@ test.describe("Header element overlap coverage", () => { ); }); - test("phone smart search does not show the desktop rotating text or prompt row", async ({ page }) => { + test("phone smart search replaces desktop rows with one tappable ticker", async ({ page }) => { await page.setViewportSize({ width: 390, height: 820 }); await mockDemoDashboard(page); await gotoHome(page); await expect(page.getByTestId("smart-search-rotating-text")).toBeHidden(); await expect(page.getByTestId("smart-search-prompt-row")).toBeHidden(); + + const ticker = page.getByTestId("smart-search-phone-ticker"); + await expect(ticker).toBeVisible(); + await expect(ticker).toContainText("Try this"); + await expect(ticker).toContainText("Tap to search"); + + const tickerBox = await ticker.boundingBox(); + expect(tickerBox, "phone suggestion ticker must render").not.toBeNull(); + expect(tickerBox!.height, "phone ticker must meet the tap-target floor").toBeGreaterThanOrEqual(48); + + const suggestion = (await ticker.getAttribute("aria-label"))?.replace("Try suggested search: ", ""); + expect(suggestion).toBeTruthy(); + await ticker.click(); + await expect(page.locator('[data-testid="global-search-input"]:visible').first()).toHaveValue(suggestion ?? ""); }); }); From 8368bd3664afb4f919ebdddaf1ada25de18d51c5 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 12 Aug 2026 07:45:13 +0000 Subject: [PATCH 2/2] Fix phone suggestion ticker to show on all hero-owned mode homes, not just / Co-authored-by: BigSimmo <87357024+BigSimmo@users.noreply.github.com> --- src/components/ClinicalDashboard.tsx | 2 +- tests/ui-overlap.spec.ts | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/components/ClinicalDashboard.tsx b/src/components/ClinicalDashboard.tsx index f33ccf8e36..1ec7998a20 100644 --- a/src/components/ClinicalDashboard.tsx +++ b/src/components/ClinicalDashboard.tsx @@ -3366,7 +3366,7 @@ export function ClinicalDashboard({ composerFollowUpSuggestions={searchMode === "answer" ? answerFollowUpSuggestions : undefined} onPickComposerFollowUpSuggestion={handlePickFollowUpSuggestion} composerFollowUpSuggestionsDisabled={loading} - showPhoneSuggestionTickerOnHome={showSharedHome} + showPhoneSuggestionTickerOnHome={heroOwnsPhoneComposer} sharedHomeIdentity={showSharedHome} composerPlaceholder={searchMode === "answer" && latestAnswerQuery ? "Ask a follow-up..." : undefined} mobileSearchPlacement={hasMobileBottomSearch ? "bottom" : "default"} diff --git a/tests/ui-overlap.spec.ts b/tests/ui-overlap.spec.ts index 94ee44dbc1..f04fb4bb7c 100644 --- a/tests/ui-overlap.spec.ts +++ b/tests/ui-overlap.spec.ts @@ -288,4 +288,21 @@ test.describe("Header element overlap coverage", () => { await ticker.click(); await expect(page.locator('[data-testid="global-search-input"]:visible').first()).toHaveValue(suggestion ?? ""); }); + + test("phone suggestion ticker renders on /documents mode home", async ({ page }) => { + await page.setViewportSize({ width: 390, height: 820 }); + await mockDemoDashboard(page); + await page.goto("/documents", { waitUntil: "domcontentloaded" }); + await expect(async () => { + const header = page.locator("header#search"); + await expect(header).toHaveCount(1); + await expect(header).toBeVisible(); + }).toPass({ timeout: 30_000 }); + + const ticker = page.getByTestId("smart-search-phone-ticker"); + await expect(ticker).toBeVisible(); + const tickerBox = await ticker.boundingBox(); + expect(tickerBox, "phone suggestion ticker must render on /documents home").not.toBeNull(); + expect(tickerBox!.height, "phone ticker must meet the tap-target floor on /documents").toBeGreaterThanOrEqual(48); + }); });