= (props) => {
)}
diff --git a/src/admin/components/views/collections/Edit/index.tsx b/src/admin/components/views/collections/Edit/index.tsx
index c28748e1e8..5db899b38a 100644
--- a/src/admin/components/views/collections/Edit/index.tsx
+++ b/src/admin/components/views/collections/Edit/index.tsx
@@ -16,7 +16,6 @@ import { Fields } from '../../../forms/Form/types';
import { usePreferences } from '../../../utilities/Preferences';
import { EditDepthContext } from '../../../utilities/EditDepth';
import { CollectionPermission } from '../../../../../auth';
-import { useFullscreenLoader } from '../../../utilities/FullscreenLoaderProvider';
const EditView: React.FC = (props) => {
const { collection: incomingCollection, isEditing } = props;
@@ -47,9 +46,6 @@ const EditView: React.FC = (props) => {
const { getVersions, preferencesKey, getDocPermissions, docPermissions } = useDocumentInfo();
const { getPreference } = usePreferences();
const { t } = useTranslation('general');
- const { setShowLoader } = useFullscreenLoader();
-
- const isLoading = !initialState || !docPermissions;
const onSave = useCallback(async (json: any) => {
getVersions();
@@ -71,8 +67,6 @@ const EditView: React.FC = (props) => {
const dataToRender = (locationState as Record)?.data || data;
useEffect(() => {
- if (isLoadingData) return;
-
const awaitInitialState = async () => {
setUpdatedAt(dataToRender?.updatedAt);
const state = await buildStateFromSchema({ fieldSchema: fields, data: dataToRender, user, operation: isEditing ? 'update' : 'create', id, locale, t });
@@ -89,10 +83,6 @@ const EditView: React.FC = (props) => {
}
}, [history, redirect]);
- useEffect(() => {
- setShowLoader(isLoading);
- }, [isLoading, setShowLoader]);
-
if (isError) {
return (
@@ -102,6 +92,7 @@ const EditView: React.FC = (props) => {
const apiURL = `${serverURL}${api}/${slug}/${id}${collection.versions.drafts ? '?draft=true' : ''}`;
const action = `${serverURL}${api}/${slug}${isEditing ? `/${id}` : ''}?locale=${locale}&depth=0&fallback-locale=null`;
const hasSavePermission = (isEditing && docPermissions?.update?.permission) || (!isEditing && (docPermissions as CollectionPermission)?.create?.permission);
+ const isLoading = !initialState || !docPermissions || isLoadingData;
return (
diff --git a/src/admin/hooks/useDelay.tsx b/src/admin/hooks/useDelay.tsx
index 4b6bd890f2..e18a529e5e 100644
--- a/src/admin/hooks/useDelay.tsx
+++ b/src/admin/hooks/useDelay.tsx
@@ -1,21 +1,19 @@
import * as React from 'react';
-type Result = [boolean, React.Dispatch>];
-export const useDelay = (delay: number, run = true): Result => {
+type Result = [boolean, () => void];
+export const useDelay = (delay: number): Result => {
const [hasDelayed, setHasDelayed] = React.useState(false);
- React.useEffect(() => {
- let delayTimeout: NodeJS.Timeout;
- if (run) {
- delayTimeout = setTimeout(() => {
- setHasDelayed(true);
- }, delay);
- }
+ const triggerDelay = React.useCallback(() => {
+ setHasDelayed(false);
+ const delayTimeout = setTimeout(() => {
+ setHasDelayed(true);
+ }, delay);
return () => {
clearTimeout(delayTimeout);
};
- }, [delay, run]);
+ }, [delay]);
- return [hasDelayed, setHasDelayed];
+ return [hasDelayed, triggerDelay];
};
diff --git a/src/admin/hooks/useSuspendedRender.ts b/src/admin/hooks/useSuspendedRender.ts
new file mode 100644
index 0000000000..558b2f241f
--- /dev/null
+++ b/src/admin/hooks/useSuspendedRender.ts
@@ -0,0 +1,61 @@
+import * as React from 'react';
+import { useDelay } from './useDelay';
+
+type TimeoutRenderProps = {
+ /** `true` starts the mount process.
+ * `false` starts the unmount process.
+ * */
+ show: boolean;
+ /** Time in ms to wait before "mounting" the component. */
+ timeout?: number;
+ /** Time in ms the `appear` phase of the animation. (enter transition time + appear time) */
+ appearTime?: number;
+ /** Time in ms the `exit` phase of the animation. */
+ exitTimeout?: number;
+ /** Time in ms to wait before actually unmounting the component. */
+ unmountTimeout?: number;
+};
+type useTimeoutRender = (props: TimeoutRenderProps) => {
+ /** `true` if the component has mounted after the timeout. */
+ isMounted: boolean;
+ /** `true` if the component is unmounting. */
+ isUnmounting: boolean;
+ /** Call this function to trigger the timeout delay before rendering. */
+ triggerRenderTimeout: () => void;
+};
+export const useTimeoutRender: useTimeoutRender = ({ show, timeout = 500, appearTime = 1250, exitTimeout = 500 }) => {
+ const [hasDelayed, triggerDelay] = useDelay(timeout);
+ const [isMounted, setIsMounted] = React.useState(false);
+ const [isUnmounting, setIsUnmounting] = React.useState(false);
+ const onMountTimestampRef = React.useRef(0);
+ const unmountTimeoutRef: React.MutableRefObject = React.useRef();
+
+ const unmount = React.useCallback(() => {
+ setIsUnmounting(true);
+ unmountTimeoutRef.current = setTimeout(() => {
+ setIsMounted(false);
+ setIsUnmounting(false);
+ }, exitTimeout);
+ }, [setIsUnmounting, exitTimeout]);
+
+ React.useEffect(() => {
+ const shouldMount = hasDelayed && !isMounted && show;
+ const shouldUnmount = isMounted && !show;
+
+ if (shouldMount) {
+ onMountTimestampRef.current = Date.now();
+ setIsMounted(true);
+ } else if (shouldUnmount) {
+ const totalTimeMounted = Date.now() - onMountTimestampRef.current;
+ const timeoutExtension = (appearTime + exitTimeout) - totalTimeMounted;
+ clearTimeout(unmountTimeoutRef.current);
+ unmountTimeoutRef.current = setTimeout(unmount, Math.max(0, timeoutExtension));
+ }
+ }, [isMounted, show, unmount, appearTime, exitTimeout, hasDelayed]);
+
+ return {
+ isMounted,
+ isUnmounting,
+ triggerRenderTimeout: triggerDelay,
+ };
+};
diff --git a/src/admin/index.tsx b/src/admin/index.tsx
index 79c1224920..bc6654a40e 100644
--- a/src/admin/index.tsx
+++ b/src/admin/index.tsx
@@ -18,7 +18,7 @@ import Routes from './components/Routes';
import { StepNavProvider } from './components/elements/StepNav';
import { ThemeProvider } from './components/utilities/Theme';
import { I18n } from './components/utilities/I18n';
-import { FullscreenLoaderProvider } from './components/utilities/FullscreenLoaderProvider';
+import { LoadingOverlayProvider } from './components/utilities/LoadingOverlay';
import './scss/app.scss';
@@ -46,11 +46,11 @@ const Index = () => (
-
+
-
+