mirror of
https://github.com/spacedriveapp/spacedrive.git
synced 2026-02-20 15:43:58 -05:00
* Fix macOS PDF rendering - Fix app crashing due to PDF rendering receiving empty URLs - Attempt fix PDF rendering empty PDFs due to it not supporting range requests * Fix dumb change from `data` to `src` in `<object>` - Fix QuickPreview not closing with space bar - Fix double-click simultaneously renaming and opening file - Minor improvements to QuickPreview header - Fix Button inside Button react error in QuickPreview - Don't render thumb without a valid source * ExternalObject events must not influence the link state - More macOS PDF range changes * Use `<iframe>` instead of `<embed>` or `<object>` to load pdf in macOS - Revert removing range support for macOS pdf type - Rename `ExternalObject` to `PDFViewer` - Fix `AddLocationDialog` sometimes requiring multiple confimations on first load * `Accept-Ranges: none` Header response as it breaks linux video playback - Extract location id from from `ExplorerItemData`, to allow rendering original versions on `Overview` * Format * cargo fmt
66 lines
2.0 KiB
TypeScript
66 lines
2.0 KiB
TypeScript
import { memo, useLayoutEffect, useMemo } from 'react';
|
|
import { useOperatingSystem } from '~/hooks';
|
|
|
|
export interface PDFViewerProps {
|
|
src: string;
|
|
onLoad?: (event: HTMLElementEventMap['load']) => void;
|
|
onError?: (event: HTMLElementEventMap['error']) => void;
|
|
className?: string;
|
|
crossOrigin?: React.ComponentProps<'link'>['crossOrigin'];
|
|
}
|
|
|
|
export const PDFViewer = memo(
|
|
({ src, onLoad, onError, className, crossOrigin }: PDFViewerProps) => {
|
|
const os = useOperatingSystem(true);
|
|
// Ignore empty urls
|
|
const href = !src || src === '#' ? null : src;
|
|
|
|
// Use link preload as a hack to get access to an onLoad and onError events for the object tag
|
|
// as well as to normalize the URL
|
|
const link = useMemo(() => {
|
|
if (href == null) return null;
|
|
|
|
const link = document.createElement('link');
|
|
link.as = 'fetch';
|
|
link.rel = 'preload';
|
|
if (crossOrigin) link.crossOrigin = crossOrigin;
|
|
link.href = href;
|
|
|
|
link.addEventListener('load', () => link.remove());
|
|
link.addEventListener('error', () => link.remove());
|
|
|
|
return link;
|
|
}, [crossOrigin, href]);
|
|
|
|
// The useLayoutEffect is used to ensure that the event listeners are added before the object is loaded
|
|
// The useLayoutEffect declaration order is important here
|
|
useLayoutEffect(() => {
|
|
if (!link) return;
|
|
|
|
if (onLoad) link.addEventListener('load', onLoad);
|
|
if (onError) link.addEventListener('error', onError);
|
|
|
|
return () => {
|
|
if (onLoad) link.removeEventListener('load', onLoad);
|
|
if (onError) link.removeEventListener('error', onError);
|
|
};
|
|
}, [link, onLoad, onError]);
|
|
|
|
useLayoutEffect(() => {
|
|
if (!link) return;
|
|
document.head.appendChild(link);
|
|
return () => link.remove();
|
|
}, [link]);
|
|
|
|
// Use link to normalize URL
|
|
return link ? (
|
|
os === 'macOS' ? (
|
|
// FIX-ME: Using <embed> isn't working in macOS for some reason
|
|
<iframe src={link.href} style={{ objectFit: 'unset' }} className={className} />
|
|
) : (
|
|
<embed src={link.href} type="application/pdf" className={className} />
|
|
)
|
|
) : null;
|
|
}
|
|
);
|