extract auth to lib
This commit is contained in:
139
src/contexts/RightSidebarContext.tsx
Normal file
139
src/contexts/RightSidebarContext.tsx
Normal file
@@ -0,0 +1,139 @@
|
||||
import {
|
||||
createContext,
|
||||
useCallback,
|
||||
useContext,
|
||||
useMemo,
|
||||
useState,
|
||||
type CSSProperties,
|
||||
type ReactNode
|
||||
} from 'react';
|
||||
import { isDesktopViewport, useSidePanelMachine } from '../panels/useSidePanelMachine';
|
||||
|
||||
const RIGHT_SIDEBAR_WIDTH_KEY = 'authRightSidebarWidth';
|
||||
const RIGHT_SIDEBAR_DEFAULT_WIDTH = 320;
|
||||
const RIGHT_SIDEBAR_MIN_WIDTH = 260;
|
||||
const RIGHT_SIDEBAR_MAX_WIDTH = 480;
|
||||
|
||||
export type RightSidebarContent = {
|
||||
title: string;
|
||||
content: ReactNode;
|
||||
ariaLabel?: string;
|
||||
};
|
||||
|
||||
export type RightSidebarStyle = CSSProperties & {
|
||||
'--auth-right-sidebar-width': string;
|
||||
};
|
||||
|
||||
type RightSidebarContextValue = {
|
||||
isOpen: boolean;
|
||||
content: RightSidebarContent | null;
|
||||
openSidebar: (content?: RightSidebarContent) => void;
|
||||
closeSidebar: () => void;
|
||||
toggleSidebar: (content?: RightSidebarContent) => void;
|
||||
setSidebarContent: (content: RightSidebarContent | null) => void;
|
||||
desktopSidebarStyle: RightSidebarStyle;
|
||||
startResize: ReturnType<typeof useSidePanelMachine>['startResize'];
|
||||
};
|
||||
|
||||
type RightSidebarProviderProps = {
|
||||
children: ReactNode;
|
||||
closeOnPathname?: string;
|
||||
onMobileOpenRequest?: () => void;
|
||||
};
|
||||
|
||||
const RightSidebarContext = createContext<RightSidebarContextValue | undefined>(undefined);
|
||||
|
||||
export function RightSidebarProvider({
|
||||
children,
|
||||
closeOnPathname,
|
||||
onMobileOpenRequest
|
||||
}: Readonly<RightSidebarProviderProps>) {
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const [content, setContent] = useState<RightSidebarContent | null>(null);
|
||||
|
||||
const closeSidebar = useCallback(() => {
|
||||
setIsOpen(false);
|
||||
setContent(null);
|
||||
}, []);
|
||||
|
||||
const setSidebarContent = useCallback((nextContent: RightSidebarContent | null) => {
|
||||
setContent(nextContent);
|
||||
}, []);
|
||||
|
||||
const openSidebar = useCallback((nextContent?: RightSidebarContent) => {
|
||||
const resolvedContent = nextContent ?? content;
|
||||
if (!resolvedContent) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (nextContent) {
|
||||
setContent(nextContent);
|
||||
}
|
||||
if (!isDesktopViewport()) {
|
||||
onMobileOpenRequest?.();
|
||||
}
|
||||
setIsOpen(true);
|
||||
}, [content, onMobileOpenRequest]);
|
||||
|
||||
const toggleSidebar = useCallback((nextContent?: RightSidebarContent) => {
|
||||
if (isOpen) {
|
||||
closeSidebar();
|
||||
return;
|
||||
}
|
||||
|
||||
openSidebar(nextContent);
|
||||
}, [isOpen, closeSidebar, openSidebar]);
|
||||
|
||||
const { width, startResize } = useSidePanelMachine({
|
||||
storageKey: RIGHT_SIDEBAR_WIDTH_KEY,
|
||||
defaultWidth: RIGHT_SIDEBAR_DEFAULT_WIDTH,
|
||||
minWidth: RIGHT_SIDEBAR_MIN_WIDTH,
|
||||
maxWidth: RIGHT_SIDEBAR_MAX_WIDTH,
|
||||
resizeAxis: 'from-right',
|
||||
resizingBodyClass: 'auth-right-sidebar-resizing',
|
||||
isOpen,
|
||||
canResize: isOpen,
|
||||
shouldPersistWidth: true,
|
||||
closeOnPathname,
|
||||
onCloseOnPathname: closeSidebar,
|
||||
onEscape: closeSidebar
|
||||
});
|
||||
|
||||
const desktopSidebarStyle = useMemo<RightSidebarStyle>(() => ({
|
||||
'--auth-right-sidebar-width': `${width}px`
|
||||
}), [width]);
|
||||
|
||||
const value = useMemo<RightSidebarContextValue>(() => ({
|
||||
isOpen,
|
||||
content,
|
||||
openSidebar,
|
||||
closeSidebar,
|
||||
toggleSidebar,
|
||||
setSidebarContent,
|
||||
desktopSidebarStyle,
|
||||
startResize
|
||||
}), [
|
||||
isOpen,
|
||||
content,
|
||||
openSidebar,
|
||||
closeSidebar,
|
||||
toggleSidebar,
|
||||
setSidebarContent,
|
||||
desktopSidebarStyle,
|
||||
startResize
|
||||
]);
|
||||
|
||||
return (
|
||||
<RightSidebarContext.Provider value={value}>
|
||||
{children}
|
||||
</RightSidebarContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
export function useRightSidebar() {
|
||||
const ctx = useContext(RightSidebarContext);
|
||||
if (!ctx) {
|
||||
throw new Error('useRightSidebar must be used within RightSidebarProvider');
|
||||
}
|
||||
return ctx;
|
||||
}
|
||||
Reference in New Issue
Block a user