MobileSheetContext.tsx59 lines · main
1import type { PropsWithChildren, ReactNode } from 'react'
2import { createContext, useCallback, useContext, useRef, useState } from 'react'
3
4import type { TYPEOF_SIDEBAR_KEYS } from '../../ProjectLayout/LayoutSidebar/LayoutSidebarProvider'
5
6/**
7 * Sheet content: null = closed; sidebar id = one of SIDEBAR_KEYS; ReactNode = custom content (menu, search, etc.).
8 */
9export type MobileSheetContentType = null | TYPEOF_SIDEBAR_KEYS | ReactNode
10
11type MobileSheetContextValue = {
12 content: MobileSheetContentType
13 setContent: (content: MobileSheetContentType) => void
14 isOpen: boolean
15 /** Open the sheet with the current menu content. Registered by ProjectLayout (project menu) or OrganizationLayout (org menu). */
16 openMenu: () => void
17 /** Register the callback run when openMenu() is called (e.g. from MobileNavigationBar). Returns an unregister function. */
18 registerOpenMenu: (fn: () => void) => () => void
19}
20
21const MobileSheetContext = createContext<MobileSheetContextValue | null>(null)
22
23export function MobileSheetProvider({ children }: PropsWithChildren) {
24 const [content, setContentState] = useState<MobileSheetContentType>(null)
25 const openMenuRef = useRef<() => void>(() => {})
26
27 const isOpen = content !== null
28
29 const setContent = useCallback((next: MobileSheetContentType) => {
30 setContentState(next)
31 }, [])
32
33 const openMenu = useCallback(() => {
34 openMenuRef.current()
35 }, [])
36
37 const registerOpenMenu = useCallback((fn: () => void) => {
38 openMenuRef.current = fn
39 return () => {
40 openMenuRef.current = () => {}
41 }
42 }, [])
43
44 return (
45 <MobileSheetContext.Provider
46 value={{ content, setContent, isOpen, openMenu, registerOpenMenu }}
47 >
48 {children}
49 </MobileSheetContext.Provider>
50 )
51}
52
53export function useMobileSheet(): MobileSheetContextValue {
54 const ctx = useContext(MobileSheetContext)
55 if (!ctx) {
56 throw new Error('useMobileSheet must be used within MobileSheetProvider')
57 }
58 return ctx
59}