mirror of
https://github.com/spacedriveapp/spacedrive
synced 2024-07-07 07:53:33 +00:00
* Centralize the file preview logic in `Thumb.tsx` * Fix useEffect * Fix Inspector thumb keeping internal state from previous selected files - Change video border to follow video aspect-ratio, just like Finder * Restore memo to Thumb - Only add borders to video thumb, not the video itself * Simplify and improve Thumb logic - Add A internal Thumbnail component - Rename main component to FileThumb to match mobile naming - Move getIcon utility function to assets/icons * Add new `useCallbackToWatchResize` hook - Replace `ResizeObserver` with new resize hook in `Thumb` - Simplify and improve `useIsDark` hook by replacing `react-responsive` with direct usage of WebAPI `matchMedia` - Fix `Thumb` src not updating correctly - Fix video extension incorrectly showing when size <= 80 in `Thumb` * Fix `Inspector` not updating thumb type - Remove superfluous `newThumb` from `getExplorerItemData` * Remove superfluous `ThumSize` * Forgot a `?` * Fix incorrect className check in `Thumb` - Updated changed files to use the hooks root import * Format * Fix PDF preview compleatly breaking the application - Allow Linux to access both the spacedrive:// custom protocol and the workaround webserver - On Linux only use the webserver for audio and video, which don't work when requested through a custom protocol - Configure tauri IPC to allow API access to the spacedrive://localhost domain, to avoid PDF previews from breaking the security scope and rendering the application unusable - Configure CSP to allow the pdf plugin custom protocol used by webkit - Fix race condition between Thumb error handler and thumbType useEffect, by using replacing it with a useLayoutEffect - Improve Thumb's error handling
78 lines
2.1 KiB
TypeScript
78 lines
2.1 KiB
TypeScript
import { DependencyList, Dispatch, RefObject, SetStateAction, useCallback, useEffect } from 'react';
|
|
|
|
export type ResizeRect = Readonly<Omit<DOMRectReadOnly, 'toJSON'>>;
|
|
type Cb = (rect: ResizeRect) => void;
|
|
|
|
const defaultRect: ResizeRect = {
|
|
y: 0,
|
|
x: 0,
|
|
top: 0,
|
|
left: 0,
|
|
right: 0,
|
|
width: 0,
|
|
height: 0,
|
|
bottom: 0
|
|
};
|
|
|
|
const observedElementsCb = new WeakMap<Element, Set<Cb>>();
|
|
|
|
// Why use a single ResizeObserver instead of one per component?
|
|
// https://github.com/WICG/resize-observer/issues/59
|
|
const resizeObserver = new ResizeObserver((entries) => {
|
|
for (const entry of entries) {
|
|
const elem = entry.target;
|
|
const cbs = observedElementsCb.get(elem);
|
|
if (cbs) {
|
|
// TODO: contentRect is included in the spec for web compat reasons, and may be deprecated one day
|
|
// Find a way to reconstruct contentRect from the other properties
|
|
// Do not use elem.getBoundingClientRect() as it is very CPU expensive
|
|
for (const cb of cbs) cb(entry.contentRect);
|
|
} else {
|
|
resizeObserver.unobserve(elem);
|
|
}
|
|
}
|
|
});
|
|
|
|
export function useCallbackToWatchResize(
|
|
callback: Cb,
|
|
deps: [RefObject<Element>, ...React.DependencyList]
|
|
): void;
|
|
export function useCallbackToWatchResize(
|
|
callback: Cb,
|
|
deps: React.DependencyList,
|
|
_ref: RefObject<Element>
|
|
): void;
|
|
export function useCallbackToWatchResize(
|
|
callback: Cb,
|
|
deps: DependencyList,
|
|
_ref?: RefObject<Element>
|
|
) {
|
|
const ref = _ref ?? (deps[0] as RefObject<Element> | undefined);
|
|
if (ref == null) throw new Error('Element not provided');
|
|
|
|
// Disable lint warning because this hook is a wrapper for useCallback
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
const onResize = useCallback(callback, deps);
|
|
|
|
useEffect(() => {
|
|
const elem = ref.current;
|
|
if (elem == null) {
|
|
onResize(defaultRect);
|
|
return;
|
|
}
|
|
|
|
const setStates =
|
|
observedElementsCb.get(elem) ?? new Set<Dispatch<SetStateAction<ResizeRect>>>();
|
|
observedElementsCb.set(elem, setStates);
|
|
setStates.add(onResize);
|
|
|
|
resizeObserver.observe(elem);
|
|
|
|
return () => {
|
|
resizeObserver.unobserve(elem);
|
|
setStates.delete(onResize);
|
|
if (setStates.size === 0) observedElementsCb.delete(elem);
|
|
};
|
|
}, [ref, onResize]);
|
|
}
|