feat: live updates
This commit is contained in:
parent
7601111424
commit
5046dc1558
@ -25,7 +25,7 @@
|
||||
"prepublishOnly": "yarn build ",
|
||||
"prepack": "cp ../../README.md ./",
|
||||
"postpack": "rm ./README.md",
|
||||
"serve": "webpack serve",
|
||||
"serve": "webpack serve --config-name configMain",
|
||||
"test": "cross-env NODE_ENV=test jest",
|
||||
"test:integration": "cross-env NODE_ENV=test jest -c jest.config.integration.js",
|
||||
"test:ci": "cross-env NODE_ENV=test jest --maxWorkers=2 --coverage",
|
||||
|
@ -212,7 +212,6 @@ const Editor: FC<TranslatedProps<EditorProps>> = ({
|
||||
}, [collection, createBackup, entryDraft.entry, hasChanged]);
|
||||
|
||||
useEntryCallback({
|
||||
hasChanged,
|
||||
collection,
|
||||
slug,
|
||||
callback: () => {
|
||||
|
@ -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 },
|
||||
});
|
||||
}
|
||||
}, []);
|
||||
|
||||
|
@ -1 +0,0 @@
|
||||
export * from './live';
|
@ -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';
|
||||
|
@ -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]);
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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}</>;
|
||||
};
|
||||
|
@ -12,8 +12,7 @@ function moduleNameToPath(libName) {
|
||||
return path.resolve(__dirname, '..', '..', 'node_modules', libName);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
entry: './src/index.ts',
|
||||
const config = {
|
||||
mode: isProduction ? 'production' : 'development',
|
||||
devtool: 'source-map',
|
||||
externals: isProduction
|
||||
@ -107,15 +106,6 @@ module.exports = {
|
||||
STATIC_CMS_CORE_VERSION: JSON.stringify(`${pkg.version}${isProduction ? '' : '-dev'}`),
|
||||
}),
|
||||
].filter(Boolean),
|
||||
output: {
|
||||
publicPath: '',
|
||||
path: path.resolve(__dirname, 'dist'),
|
||||
filename: 'static-cms-core.js',
|
||||
library: {
|
||||
name: 'StaticCmsCore',
|
||||
type: 'umd',
|
||||
},
|
||||
},
|
||||
devServer: {
|
||||
static: {
|
||||
directory: './dev-test',
|
||||
@ -126,3 +116,33 @@ module.exports = {
|
||||
hot: true,
|
||||
},
|
||||
};
|
||||
|
||||
const configLive = Object.assign({}, config, {
|
||||
name: "configLive",
|
||||
entry: './src/live/index.ts',
|
||||
output: {
|
||||
publicPath: '',
|
||||
path: path.resolve(__dirname, 'dist'),
|
||||
filename: 'live.js',
|
||||
library: {
|
||||
name: 'StaticCmsCoreLive',
|
||||
type: 'umd',
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
const configMain = Object.assign({}, config, {
|
||||
name: "configMain",
|
||||
entry: './src/index.ts',
|
||||
output: {
|
||||
publicPath: '',
|
||||
path: path.resolve(__dirname, 'dist'),
|
||||
filename: 'static-cms-core.js',
|
||||
library: {
|
||||
name: 'StaticCmsCore',
|
||||
type: 'umd',
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = [configMain, configLive]
|
||||
|
Loading…
x
Reference in New Issue
Block a user