Files
supabase/apps/studio/components/layouts/Navigation/NavigationBar/StudioMobileSheetNav.tsx
Joshen Lim 66691ad9ce Joshen/fe 3384 prevent ai assistant chat panel from closing after query (#47951)
## Context

2 problems that this PR addresses - but these are in general due to the
mobile UI behaviour
- Sidebars (e.g Help Panel, Advisor Panel, etc) closes whenever there's
a route change
- This is happening because of `StudioMobileSheetNav`'s
`handleOpenChange` interfering with the sidebar visible state
- Am opting to not render `StudioMobileSheetNav` at all unless on mobile
- On mobile, if you're on the Advisor Panel, clicking the "Menu" button
closes the mobile sheet
- Clicking on the Menu button seems to be triggering `MobileSheetNav`'s
`onOpenChange`
- My suspicion is because of state asymmetry between two independent
stores (MobileSheetContext and SidebarManagerState - these 2 are a bit
too complex imo)
- Am opting to skip calling `onOpenChange` in `StudioMobileSheetNav` if
the click target is within the Floating toolbar

## To test
- [x] Desktop: Have the assistant panel open and change routes, panel
should stay open
- [x] Mobile: Open the assistant panel, then switch to the menu, panel
should stay open

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Bug Fixes**
* Improved mobile navigation interactions so the navigation sheet
remains open while toolbar actions are being selected.
* Mobile navigation now displays only on smaller screens, preventing it
from appearing at medium and larger breakpoints.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-07-15 17:19:02 +08:00

75 lines
2.5 KiB
TypeScript

import { useBreakpoint } from 'common'
import type { ReactNode } from 'react'
import { CommandWrapper } from 'ui-patterns/CommandMenu'
import { MobileSheetNav } from 'ui-patterns/MobileSheetNav'
import {
SIDEBAR_KEYS,
type TYPEOF_SIDEBAR_KEYS,
} from '../../ProjectLayout/LayoutSidebar/LayoutSidebarProvider'
import type { MobileSheetContentType } from './MobileSheetContext'
import { useMobileSheet } from './MobileSheetContext'
import { CommandMenuInnerContent } from '@/components/interfaces/App/CommandMenu/CommandMenu'
import { sidebarManagerState, useSidebarManagerSnapshot } from '@/state/sidebar-manager-state'
function isSidebarId(content: unknown): content is TYPEOF_SIDEBAR_KEYS {
return (
typeof content === 'string' &&
Object.values(SIDEBAR_KEYS).includes(content as TYPEOF_SIDEBAR_KEYS)
)
}
function getSheetChildren(
content: MobileSheetContentType,
activeSidebar: { id: string; component?: () => ReactNode } | null
): ReactNode {
if (content === null) return null
if (content === 'search') {
return (
<CommandWrapper className="h-full flex flex-col bg-background">
<CommandMenuInnerContent />
</CommandWrapper>
)
}
if (isSidebarId(content) && activeSidebar?.id === content) {
return activeSidebar.component?.() ?? null
}
if (!isSidebarId(content)) return content
return null
}
export const StudioMobileSheetNav = () => {
const isMobile = useBreakpoint('md')
const { content, setContent } = useMobileSheet()
const { activeSidebar } = useSidebarManagerSnapshot()
const sheetChildren = getSheetChildren(content, activeSidebar ?? null)
const handleOpenChange = (open: boolean) => {
if (!open) {
setContent(null)
sidebarManagerState.closeActive()
}
}
if (!isMobile) return null
return (
<MobileSheetNav
open={content !== null}
onOpenChange={handleOpenChange}
shouldCloseOnViewportResize={!activeSidebar}
onPointerDownOutside={(event) => {
// Buttons in the floating toolbar (#mobile-nav-actions) render outside this sheet, so
// Radix treats taps on them as an outside click and closes the sheet before the button's
// own onClick runs. Those buttons already manage the sheet themselves, so don't let
// Radix's outside-dismiss pre-empt them.
if ((event.target as HTMLElement | null)?.closest('#mobile-nav-actions')) {
event.preventDefault()
}
}}
>
{sheetChildren}
</MobileSheetNav>
)
}