64 lines
2.0 KiB
TypeScript
64 lines
2.0 KiB
TypeScript
import React, { useState, useCallback, useMemo, useRef } from 'react';
|
|
import PreviewZoomOverlay from './components/PreviewZoomOverlay';
|
|
import type { Document } from '../types/documents';
|
|
import type { Identifier } from '../types/identifiers';
|
|
import { createSafeContext } from '../utils/createSafeContext';
|
|
|
|
interface PreviewContextType {
|
|
openPreview: (doc: Document) => void;
|
|
closePreview: () => void;
|
|
}
|
|
|
|
const [PreviewContext, usePreviewContext] = createSafeContext<PreviewContextType>('Preview');
|
|
|
|
interface PreviewProviderProps {
|
|
children: React.ReactNode;
|
|
onNavigate?: (documentId: Identifier) => void;
|
|
}
|
|
|
|
export const PreviewProvider: React.FC<PreviewProviderProps> = ({ children, onNavigate }) => {
|
|
const [previewDoc, setPreviewDoc] = useState<Document | null>(null);
|
|
const lastFocusedElement = useRef<HTMLElement | null>(null);
|
|
|
|
const openPreview = useCallback((doc: Document) => {
|
|
if (!lastFocusedElement.current) {
|
|
lastFocusedElement.current = document.activeElement as HTMLElement;
|
|
}
|
|
setPreviewDoc(doc);
|
|
}, []);
|
|
|
|
const closePreview = useCallback(() => {
|
|
setPreviewDoc(null);
|
|
if (lastFocusedElement.current) {
|
|
lastFocusedElement.current.focus();
|
|
lastFocusedElement.current = null;
|
|
}
|
|
}, []);
|
|
|
|
const handleMaximize = useCallback(() => {
|
|
if (previewDoc && onNavigate) {
|
|
onNavigate(previewDoc.id);
|
|
closePreview();
|
|
}
|
|
}, [previewDoc, onNavigate, closePreview]);
|
|
|
|
const value = useMemo(() => ({
|
|
openPreview,
|
|
closePreview,
|
|
}), [openPreview, closePreview]);
|
|
|
|
return (
|
|
<PreviewContext.Provider value={value}>
|
|
{children}
|
|
<PreviewZoomOverlay
|
|
open={Boolean(previewDoc)}
|
|
onClose={closePreview}
|
|
onMaximize={onNavigate ? handleMaximize : undefined}
|
|
document={previewDoc}
|
|
/>
|
|
</PreviewContext.Provider>
|
|
);
|
|
};
|
|
|
|
export { usePreviewContext };
|