feat: live updates

This commit is contained in:
Daniel Lautzenheiser
2023-07-19 16:15:46 -04:00
parent 7601111424
commit 5046dc1558
10 changed files with 58 additions and 39 deletions

View File

@ -212,7 +212,6 @@ const Editor: FC<TranslatedProps<EditorProps>> = ({
}, [collection, createBackup, entryDraft.entry, hasChanged]);
useEntryCallback({
hasChanged,
collection,
slug,
callback: () => {

View File

@ -186,7 +186,10 @@ const EditorPreviewPane = (props: TranslatedProps<EditorPreviewPaneProps>) => {
const livePreviewIframe = useRef<HTMLIFrameElement>(null);
const passEventToIframe = useCallback((event: DataUpdateEvent) => {
if (livePreviewIframe.current) {
livePreviewIframe.current.contentWindow?.postMessage(event);
livePreviewIframe.current.contentWindow?.postMessage({
message: 'data:update',
value: { fieldPath: event.detail.fieldPath, value: event.detail.value },
});
}
}, []);

View File

@ -1 +0,0 @@
export * from './live';

View File

@ -16,7 +16,6 @@ import Registry from './lib/registry';
export * from './backends';
export * from './interface';
export * from './components';
export * from './lib';
export { default as locales } from './locales';
export * from './widgets';

View File

@ -1,23 +1,29 @@
import { useCallback, useEffect, useState } from 'react';
import { useSearchParams } from 'react-router-dom';
import { useCallback, useEffect, useMemo, useState } from 'react';
import type { ValueOrNestedValue } from '@staticcms/core/interface';
import type DataUpdateEvent from '../util/events/DataEvent';
export default function useData(value: ValueOrNestedValue, path: string) {
const [data, setData] = useState(value);
const [searchParams] = useSearchParams();
const isCms = searchParams.get('useCmsData') === 'true';
const isCms = useMemo(() => {
if (!window) {
return false;
}
const searchParams = new URLSearchParams(window.location.search);
return searchParams.get('useCmsData') === 'true';
}, []);
const onDataChange = useCallback(
(event: DataUpdateEvent) => {
if (!isCms) {
(event: MessageEvent) => {
if (!isCms || event.data.message !== 'data:update') {
return;
}
if (event.detail.fieldPath === path) {
setData(event.detail.value);
const { fieldPath, value } = event.data.value;
if (fieldPath === path) {
setData(value);
}
},
[isCms, path],
@ -28,10 +34,10 @@ export default function useData(value: ValueOrNestedValue, path: string) {
return;
}
window.addEventListener('data:update', onDataChange);
window?.addEventListener('message', onDataChange);
return () => {
window.removeEventListener('data:update', onDataChange);
window?.removeEventListener('message', onDataChange);
};
}, [isCms, onDataChange]);

View File

@ -63,18 +63,12 @@ async function handleChange(
}
interface EntryCallbackProps {
hasChanged: boolean;
collection: Collection;
slug: string | undefined;
callback: () => void;
}
export default function useEntryCallback({
hasChanged,
slug,
collection,
callback,
}: EntryCallbackProps) {
export default function useEntryCallback({ slug, collection, callback }: EntryCallbackProps) {
const dispatch = useAppDispatch();
const entry = useAppSelector(selectEditingDraft);
@ -85,7 +79,7 @@ export default function useEntryCallback({
return;
}
if (hasChanged && entry) {
if (entry) {
const file = fileForEntry(collection, slug);
let updatedEntryData = entry.data;
@ -121,9 +115,9 @@ export default function useEntryCallback({
setLastEntryData(entry?.data);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [entry, hasChanged]);
}, [entry]);
const debouncedRunUpdateCheck = useDebouncedCallback(runUpdateCheck, 500);
const debouncedRunUpdateCheck = useDebouncedCallback(runUpdateCheck, 200);
useEffect(() => {
debouncedRunUpdateCheck();

View File

@ -1,6 +1,6 @@
import React from 'react';
import { useData } from '@staticcms/core/lib';
import useData from '@staticcms/core/lib/hooks/useData';
import type { ValueOrNestedValue } from '@staticcms/core/interface';
import type { FC } from 'react';
@ -12,7 +12,6 @@ export interface DataProps {
const Data: FC<DataProps> = ({ path, value }) => {
const data = useData(value, path);
return <>{data}</>;
};