typescript
This commit is contained in:
+49
-4
@@ -1,11 +1,56 @@
|
||||
import React, { useCallback, useMemo } from 'react';
|
||||
import { useCallback, useMemo } from 'react';
|
||||
import type { JSX } from 'react';
|
||||
import DocumentInfoPanel from '../documents/DocumentInfoPanel';
|
||||
import { DownloadIcon } from '../ui/icons';
|
||||
|
||||
interface DocumentLike {
|
||||
id?: string | number;
|
||||
title?: string;
|
||||
content_type?: string;
|
||||
filename?: string;
|
||||
original_name?: string;
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
interface PreviewEntry {
|
||||
url?: string;
|
||||
contentType?: string;
|
||||
filename?: string;
|
||||
}
|
||||
|
||||
interface ContentTabConfig {
|
||||
id?: string;
|
||||
label?: string;
|
||||
enabled?: boolean;
|
||||
forceDisplay?: boolean;
|
||||
loadContent?: (options?: { signal?: AbortSignal }) => unknown | Promise<unknown>;
|
||||
loadingMessage?: string;
|
||||
emptyMessage?: string;
|
||||
unavailableMessage?: string;
|
||||
errorMessage?: string;
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
type LayoutMode = 'split' | 'stacked' | (string & {});
|
||||
|
||||
interface DocumentViewerLayoutProps {
|
||||
document?: DocumentLike | null;
|
||||
previewEntry?: PreviewEntry | null;
|
||||
summaryProps?: Record<string, unknown>;
|
||||
metadataPayload?: unknown;
|
||||
contentTabConfig?: ContentTabConfig | null;
|
||||
resetKey?: string | number | null;
|
||||
classNamePrefix?: string;
|
||||
defaultTabId?: string;
|
||||
infoPanelProps?: Record<string, unknown>;
|
||||
previewLoadingMessage?: string;
|
||||
layoutMode?: LayoutMode;
|
||||
}
|
||||
|
||||
const DocumentViewerLayout = ({
|
||||
document,
|
||||
previewEntry,
|
||||
summaryProps,
|
||||
summaryProps = {},
|
||||
metadataPayload,
|
||||
contentTabConfig,
|
||||
resetKey,
|
||||
@@ -14,7 +59,7 @@ const DocumentViewerLayout = ({
|
||||
infoPanelProps = {},
|
||||
previewLoadingMessage = 'Preparing preview…',
|
||||
layoutMode = 'split',
|
||||
}) => {
|
||||
}: DocumentViewerLayoutProps): JSX.Element => {
|
||||
const isStacked = layoutMode === 'stacked';
|
||||
|
||||
const previewContent = useMemo(() => {
|
||||
@@ -103,7 +148,7 @@ const DocumentViewerLayout = ({
|
||||
|
||||
const resolvedDefaultTabId = isStacked ? 'preview' : defaultTabId;
|
||||
const summaryPlacement = 'tabs';
|
||||
const tabsPlacement = isStacked ? 'bottom' : 'top';
|
||||
const tabsPlacement = 'bottom';
|
||||
const summaryLayout = 'compact';
|
||||
|
||||
const detailsPane = (
|
||||
+44
-4
@@ -5,12 +5,13 @@ import React, {
|
||||
useRef,
|
||||
useState,
|
||||
} from 'react';
|
||||
import type { ReactNode } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import {
|
||||
DownloadIcon,
|
||||
CloseIcon,
|
||||
IconZoomInArea,
|
||||
DetailPanelCollapseIcon,
|
||||
IconX,
|
||||
WindowMaximizeIcon,
|
||||
} from '../ui/icons';
|
||||
import PreviewZoomOverlay from '../detail/PreviewZoomOverlay';
|
||||
@@ -18,6 +19,7 @@ import {
|
||||
buildCorrespondentOptions,
|
||||
sortCorrespondents,
|
||||
} from '../documents/DocumentSummarySection';
|
||||
import type { DocumentSummarySectionProps } from '../documents/DocumentSummarySection';
|
||||
import { extractDocumentMetadataPayload } from '../documents/documentMetadata';
|
||||
import { createDocumentActionState } from '../documents/documentActions';
|
||||
import { resolveDocumentAssetUrl } from '../asset_manager';
|
||||
@@ -28,6 +30,44 @@ import DocumentViewerLayout from './DocumentViewerLayout';
|
||||
import useViewerLayoutMode from './useViewerLayoutMode';
|
||||
import { usePanelResizeBindings } from '../app/PanelManagerContext';
|
||||
|
||||
interface DocumentLike {
|
||||
id?: string | number;
|
||||
title?: string;
|
||||
issued_at?: string | null;
|
||||
correspondents?: Array<{ id?: string | number; name?: string }>;
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
interface AssetLike {
|
||||
id?: string | number;
|
||||
url?: string | null;
|
||||
metadata?: Record<string, unknown> | null;
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
interface DocumentViewerPanelProps extends DocumentSummarySectionProps {
|
||||
document: DocumentLike | null;
|
||||
previewEntry?: {
|
||||
url?: string;
|
||||
canGoPrev?: boolean;
|
||||
canGoNext?: boolean;
|
||||
goPrev?: () => void;
|
||||
goNext?: () => void;
|
||||
} | null;
|
||||
hydrateDocument?: (doc: DocumentLike | null) => DocumentLike | null;
|
||||
ensureAssetUrl?: (docId: string | number, asset: AssetLike, options?: { start?: number; limit?: number }) => Promise<unknown>;
|
||||
getDocumentAsset?: (doc: DocumentLike | null, type: string) => AssetLike | null | undefined;
|
||||
ensurePreviewData?: (docId: string | number, options?: { signal?: AbortSignal }) => Promise<DocumentLike | null | undefined>;
|
||||
resolveApiPath?: (path: string) => string;
|
||||
notifyApiError?: (error: unknown, fallbackMessage?: string) => void;
|
||||
sidebarToggle?: ReactNode;
|
||||
onClosePanel?: () => void;
|
||||
resolveFolderPath?: (doc: DocumentLike | null) => Array<{ id?: string | number; name?: string }>;
|
||||
variant?: 'viewer' | 'sidebar';
|
||||
onCollapsePanel?: () => void;
|
||||
onMaximizePanel?: () => void;
|
||||
}
|
||||
|
||||
|
||||
export const createDocumentViewerHeaderActions = ({
|
||||
document,
|
||||
@@ -74,7 +114,7 @@ export const createDocumentViewerHeaderActions = ({
|
||||
);
|
||||
};
|
||||
|
||||
const DocumentViewerPanel = ({
|
||||
const DocumentViewerPanel: React.FC<DocumentViewerPanelProps> = ({
|
||||
document,
|
||||
previewEntry,
|
||||
hydrateDocument,
|
||||
@@ -239,7 +279,7 @@ const DocumentViewerPanel = ({
|
||||
}
|
||||
}, [hydrateDocument, document?.id]);
|
||||
|
||||
const panelRef = useRef(null);
|
||||
const panelRef = useRef<HTMLDivElement | HTMLFormElement | HTMLElement | null>(null);
|
||||
const isStackedLayout = useViewerLayoutMode(panelRef, document?.id);
|
||||
|
||||
const {
|
||||
@@ -366,7 +406,7 @@ const DocumentViewerPanel = ({
|
||||
aria-label="Close detail panel"
|
||||
title="Close detail panel"
|
||||
>
|
||||
<DetailPanelCollapseIcon />
|
||||
<IconX />
|
||||
</button>
|
||||
)
|
||||
: null;
|
||||
+10
-5
@@ -1,4 +1,4 @@
|
||||
import { useLayoutEffect, useState } from 'react';
|
||||
import { MutableRefObject, useLayoutEffect, useState } from 'react';
|
||||
|
||||
export const DOCUMENT_VIEWER_PORTRAIT_HEIGHT_RATIO = 0.4;
|
||||
const PORTRAIT_RATIO_STYLE_ID = 'document-viewer-portrait-ratio-style';
|
||||
@@ -19,9 +19,14 @@ const ensurePortraitRatioStyle = () => {
|
||||
}
|
||||
};
|
||||
|
||||
const computeStackedLayoutBreakpoint = () => window.innerWidth / 2;
|
||||
const MIN_STACKED_BREAKPOINT = 480;
|
||||
|
||||
export const useViewerLayoutMode = (ref, dependency) => {
|
||||
const computeStackedLayoutBreakpoint = () => Math.max(window.innerWidth / 2, MIN_STACKED_BREAKPOINT);
|
||||
|
||||
export const useViewerLayoutMode = (
|
||||
ref: MutableRefObject<HTMLElement | null> | null,
|
||||
dependency?: unknown,
|
||||
) => {
|
||||
const [isStacked, setIsStacked] = useState(false);
|
||||
|
||||
useLayoutEffect(() => {
|
||||
@@ -35,8 +40,8 @@ export const useViewerLayoutMode = (ref, dependency) => {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
let frame = null;
|
||||
const commitMeasure = (width) => {
|
||||
let frame: number | null = null;
|
||||
const commitMeasure = (width: number) => {
|
||||
if (frame) {
|
||||
cancelAnimationFrame(frame);
|
||||
}
|
||||
Reference in New Issue
Block a user