mirror of
https://github.com/spacedriveapp/spacedrive
synced 2024-07-14 08:54:04 +00:00
30e7c9d709
* 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
66 lines
2.4 KiB
TypeScript
66 lines
2.4 KiB
TypeScript
import { useCallback, useEffect, useRef } from 'react';
|
|
import { EventType, FieldPath, FieldValues, UseFormReturn } from 'react-hook-form';
|
|
|
|
const noop = () => {};
|
|
|
|
type Cb<S extends FieldValues> = (
|
|
value: S,
|
|
info: {
|
|
name?: FieldPath<S>;
|
|
type?: EventType;
|
|
}
|
|
) => void | Promise<void>;
|
|
|
|
export function useCallbackToWatchForm<S extends FieldValues>(
|
|
callback: Cb<S>,
|
|
deps: [UseFormReturn<S, unknown>, ...React.DependencyList]
|
|
): void;
|
|
|
|
export function useCallbackToWatchForm<S extends FieldValues>(
|
|
callback: Cb<S>,
|
|
deps: React.DependencyList,
|
|
form: UseFormReturn<S, unknown>
|
|
): void;
|
|
|
|
/**
|
|
* This hook is an async friendly wrapper for useCallback that enables reacting to any form changes.
|
|
*
|
|
* The callback will be called on the first render, and whenever the form changes, with the current
|
|
* form values and the event info regarding the change (empty on first render). If the callback is
|
|
* async, or returns a promise, it will wait for the previous callback to finish before executing
|
|
* the next one. Any errors thrown by the callback will be ignored.
|
|
*
|
|
* @param callback - Callback to be called when form changes
|
|
* @param deps - Dependency list for the callback
|
|
* @param form - Form to watch. If not provided, it will be taken from the first element of the dependency list
|
|
*/
|
|
export function useCallbackToWatchForm<S extends FieldValues>(
|
|
callback: Cb<S>,
|
|
deps: React.DependencyList,
|
|
form?: UseFormReturn<S, unknown>
|
|
): void {
|
|
if (form == null) form = deps[0] as UseFormReturn<S, unknown>;
|
|
if (form == null) throw new Error('Form is not provided');
|
|
const { getValues, watch } = form;
|
|
if (typeof getValues !== 'function' || typeof watch !== 'function')
|
|
throw new Error('Form is not provided');
|
|
|
|
// Create a promise chain to make sure async callbacks are called in order
|
|
const chain = useRef<Promise<true | void>>(Promise.resolve(true));
|
|
|
|
// Disable lint warning because this hook is a wrapper for useCallback
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
const onWatch = useCallback(callback, deps);
|
|
|
|
useEffect(() => {
|
|
chain.current = chain.current
|
|
// If this is the first time, we don't need to wait for a form change
|
|
.then((initCheck) => initCheck && onWatch(getValues(), {}))
|
|
.finally(noop);
|
|
|
|
return watch((_, info) => {
|
|
chain.current = chain.current.then(() => onWatch(getValues(), info)).finally(noop);
|
|
}).unsubscribe;
|
|
}, [watch, onWatch, getValues]);
|
|
}
|