social components inlay.at
atproto components sdui
86
fork

Configure Feed

Select the types of activity you want to include in your feed.

at main 67 lines 1.4 kB view raw
1"use client"; 2 3import { 4 createContext, 5 useState, 6 useContext, 7 useEffect, 8 type ReactNode, 9} from "react"; 10import NextLink from "next/link"; 11 12// ── Context ── 13 14const BlockerContext = createContext<{ 15 isBlocked: boolean; 16 setIsBlocked: (v: boolean) => void; 17}>({ isBlocked: false, setIsBlocked: () => {} }); 18 19export function NavigationBlockerProvider({ 20 children, 21}: { 22 children: ReactNode; 23}) { 24 const [isBlocked, setIsBlocked] = useState(false); 25 26 useEffect(() => { 27 if (!isBlocked) return; 28 const handler = (e: BeforeUnloadEvent) => e.preventDefault(); 29 window.addEventListener("beforeunload", handler); 30 return () => window.removeEventListener("beforeunload", handler); 31 }, [isBlocked]); 32 33 return ( 34 <BlockerContext.Provider value={{ isBlocked, setIsBlocked }}> 35 {children} 36 </BlockerContext.Provider> 37 ); 38} 39 40export function useNavigationBlocker() { 41 return useContext(BlockerContext); 42} 43 44// ── Link ── 45 46export default function Link({ 47 onNavigate, 48 ...props 49}: React.ComponentProps<typeof NextLink>) { 50 const { isBlocked } = useContext(BlockerContext); 51 52 return ( 53 <NextLink 54 {...props} 55 onNavigate={(e) => { 56 if ( 57 isBlocked && 58 !window.confirm("You have unsaved changes. Leave anyway?") 59 ) { 60 e.preventDefault(); 61 return; 62 } 63 onNavigate?.(e); 64 }} 65 /> 66 ); 67}