Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion src/components/clinical-dashboard/global-search-shell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ function GlobalStandaloneSearchShellClient({
const [mainElement, setMainElement] = useState<HTMLDivElement | null>(null);
const phoneScrollHide = useScrollHideReporter();
const reportPhoneScrollHideRef = useRef(phoneScrollHide.reportScroll);
const [bottomComposerHidden, setBottomComposerHidden] = useState(false);
useEffect(() => {
reportPhoneScrollHideRef.current = phoneScrollHide.reportScroll;
}, [phoneScrollHide.reportScroll]);
Expand Down Expand Up @@ -260,7 +261,7 @@ function GlobalStandaloneSearchShellClient({
const reservesFloatingComposer = shouldShowSearchComposer && !isStandaloneModeHome;
// Standalone mode homes portal the composer into the hero (in-flow at every
// width), so phones need no bottom-dock clearance there.
const mobileComposerReserve = !shouldShowSearchComposer
const visibleMobileComposerReserve = !shouldShowSearchComposer
Comment thread
BigSimmo marked this conversation as resolved.
? "2rem"
: isStandaloneModeHome
? "2rem"
Expand All @@ -271,6 +272,15 @@ function GlobalStandaloneSearchShellClient({
: useCompactBottomSearch
? "calc(5.5rem + env(safe-area-inset-bottom))"
: "calc(9rem + env(safe-area-inset-bottom))";
// Release the large bottom reserve only when the phone bottom composer is
// actually hidden (MasterSearchHeader's bottomComposerHidden). Header-only
// scroll-hide, pinned compare addons, open menus/sheets, and composer focus
// keep the full reserve so content does not slide under a still-visible dock.
// When the dock does hide, keep only a small safe-area breathing room so
// content — not the background — fills the revealed edge-to-edge viewport.
const mobileComposerReserve = bottomComposerHidden
? "max(0.75rem, env(safe-area-inset-bottom))"
: visibleMobileComposerReserve;

useEffect(() => {
// Re-derive the mode and query from the URL, but only when the search string
Expand Down Expand Up @@ -576,6 +586,7 @@ function GlobalStandaloneSearchShellClient({
// Phone-only: #main-content owns vertical scroll, so hide-on-scroll
// collapses the header/composer to hand space back to content.
hideOnScroll={{ strategy: "collapse", scrollHidden: phoneScrollHide.hidden }}
onBottomComposerHiddenChange={setBottomComposerHidden}
queryInputAutoFocus={searchParams.get("focus") === "1"}
/>
</div>
Expand Down
7 changes: 7 additions & 0 deletions src/components/clinical-dashboard/master-search-header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@ export function MasterSearchHeader({
mobileLeadingAction = "menu",
onMobileBack,
hideOnScroll,
onBottomComposerHiddenChange,
}: {
demoMode: boolean;
documents: ClinicalDocument[];
Expand Down Expand Up @@ -259,6 +260,8 @@ export function MasterSearchHeader({
/** Parent-owned hidden state for hosts that report scroll via React `onScroll`. */
scrollHidden?: boolean;
};
/** Notify hosts when the phone bottom composer is actually hidden (not merely scrolled). */
onBottomComposerHiddenChange?: (hidden: boolean) => void;
}) {
const visibleAppModeOptions = defaultVisibleAppModeOptions;
const trimmedQuery = query.trim();
Expand Down Expand Up @@ -334,6 +337,10 @@ export function MasterSearchHeader({
!scopeSheetOpen &&
!composerChromeFocused;

useEffect(() => {
onBottomComposerHiddenChange?.(bottomComposerHidden);
}, [bottomComposerHidden, onBottomComposerHiddenChange]);

useEffect(() => {
if (!loading || !commandDropdownOpen) return undefined;
const frame = window.requestAnimationFrame(() => setCommandDropdownOpen(false));
Expand Down
4 changes: 3 additions & 1 deletion tests/clinical-dashboard-merge-artifacts.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,10 @@ describe("ClinicalDashboard merge-artifact guards", () => {
});

it("reserves phone space for the fixed mode-home composer", () => {
expect(globalSearchShellSource).toContain("const mobileComposerReserve = !shouldShowSearchComposer");
expect(globalSearchShellSource).toContain("const visibleMobileComposerReserve = !shouldShowSearchComposer");
expect(globalSearchShellSource).toContain("const mobileComposerReserve = bottomComposerHidden");
expect(globalSearchShellSource).not.toContain("const mobileComposerReserve = !reservesFloatingComposer");
expect(globalSearchShellSource).not.toContain("const mobileComposerReserve = phoneScrollHide.hidden");
});

it("does not reintroduce the obsolete output-mode copy helper", () => {
Expand Down