feat: live preview iframe, pass data update event
This commit is contained in:
parent
2834f3535b
commit
ba27a456da
@ -173,7 +173,7 @@ export function applyDefaults<EF extends BaseField = UnknownField>(
|
||||
let collectionI18n = collection[I18N];
|
||||
|
||||
if (config.editor && !collection.editor) {
|
||||
collection.editor = { preview: config.editor.preview, frame: config.editor.frame };
|
||||
collection.editor = config.editor;
|
||||
}
|
||||
|
||||
collection.media_library = {
|
||||
@ -248,7 +248,7 @@ export function applyDefaults<EF extends BaseField = UnknownField>(
|
||||
}
|
||||
|
||||
if (collection.editor && !file.editor) {
|
||||
file.editor = { preview: collection.editor.preview, frame: collection.editor.frame };
|
||||
file.editor = collection.editor;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { ScrollSyncPane } from 'react-scroll-sync';
|
||||
|
||||
import { EDITOR_SIZE_COMPACT } from '@staticcms/core/constants/views';
|
||||
import { summaryFormatter } from '@staticcms/core/lib/formatters';
|
||||
import useBreadcrumbs from '@staticcms/core/lib/hooks/useBreadcrumbs';
|
||||
import { getI18nInfo, hasI18n } from '@staticcms/core/lib/i18n';
|
||||
import classNames from '@staticcms/core/lib/util/classNames.util';
|
||||
@ -10,6 +11,8 @@ import {
|
||||
selectEntryCollectionTitle,
|
||||
} from '@staticcms/core/lib/util/collection.util';
|
||||
import { customPathFromSlug } from '@staticcms/core/lib/util/nested.util';
|
||||
import { selectConfig } from '@staticcms/core/reducers/selectors/config';
|
||||
import { useAppSelector } from '@staticcms/core/store/hooks';
|
||||
import MainView from '../MainView';
|
||||
import EditorToolbar from './EditorToolbar';
|
||||
import EditorControlPane from './editor-control-pane/EditorControlPane';
|
||||
@ -95,6 +98,8 @@ const EditorInterface = ({
|
||||
submitted,
|
||||
slug,
|
||||
}: TranslatedProps<EditorInterfaceProps>) => {
|
||||
const config = useAppSelector(selectConfig);
|
||||
|
||||
const { locales, defaultLocale } = useMemo(() => getI18nInfo(collection), [collection]) ?? {};
|
||||
const translatedLocales = useMemo(
|
||||
() => locales?.filter(locale => locale !== defaultLocale) ?? [],
|
||||
@ -151,18 +156,37 @@ const EditorInterface = ({
|
||||
setSelectedLocale(locale);
|
||||
}, []);
|
||||
|
||||
const [showPreviewToggle, previewInFrame, editorSize] = useMemo(() => {
|
||||
let preview = collection.editor?.preview ?? true;
|
||||
let frame = collection.editor?.frame ?? true;
|
||||
const { livePreviewUrlTemplate, showPreviewToggle, previewInFrame, editorSize } = useMemo(() => {
|
||||
let livePreviewUrlTemplate =
|
||||
typeof collection.editor?.live_preview === 'string' ? collection.editor.live_preview : false;
|
||||
|
||||
let preview = true;
|
||||
let frame = true;
|
||||
let size = collection.editor?.size ?? EDITOR_SIZE_COMPACT;
|
||||
|
||||
if (collection.editor) {
|
||||
if ('preview' in collection.editor) {
|
||||
preview = collection.editor.preview ?? true;
|
||||
}
|
||||
|
||||
if ('frame' in collection.editor) {
|
||||
preview = collection.editor.frame ?? true;
|
||||
}
|
||||
}
|
||||
|
||||
if ('files' in collection) {
|
||||
const file = getFileFromSlug(collection, entry.slug);
|
||||
if (file?.editor?.preview !== undefined) {
|
||||
|
||||
if (file?.editor) {
|
||||
if (typeof file.editor.live_preview === 'string') {
|
||||
livePreviewUrlTemplate = file.editor.live_preview;
|
||||
}
|
||||
|
||||
if ('preview' in file.editor && file.editor.preview !== undefined) {
|
||||
preview = file.editor.preview;
|
||||
}
|
||||
|
||||
if (file?.editor?.frame !== undefined) {
|
||||
if ('frame' in file.editor && file.editor.frame !== undefined) {
|
||||
frame = file.editor.frame;
|
||||
}
|
||||
|
||||
@ -170,9 +194,17 @@ const EditorInterface = ({
|
||||
size = file.editor.size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return [preview, frame, size];
|
||||
}, [collection, entry.slug]);
|
||||
return {
|
||||
livePreviewUrlTemplate: livePreviewUrlTemplate
|
||||
? summaryFormatter(livePreviewUrlTemplate, entry, collection, config?.slug)
|
||||
: undefined,
|
||||
showPreviewToggle: preview,
|
||||
previewInFrame: frame,
|
||||
editorSize: size,
|
||||
};
|
||||
}, [collection, config?.slug, entry]);
|
||||
|
||||
const finalPreviewActive = useMemo(
|
||||
() => showPreviewToggle && previewActive,
|
||||
@ -318,6 +350,7 @@ const EditorInterface = ({
|
||||
<EditorPreviewPane
|
||||
collection={collection}
|
||||
previewInFrame={previewInFrame}
|
||||
livePreviewUrlTemplate={livePreviewUrlTemplate}
|
||||
entry={entry}
|
||||
fields={fields}
|
||||
editorSize={editorSize}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React, { useMemo } from 'react';
|
||||
import React, { useCallback, useMemo, useRef } from 'react';
|
||||
import { createPortal } from 'react-dom';
|
||||
import Frame from 'react-frame-component';
|
||||
import { translate } from 'react-polyglot';
|
||||
@ -8,6 +8,7 @@ import { EDITOR_SIZE_COMPACT } from '@staticcms/core/constants/views';
|
||||
import { getPreviewStyles, getPreviewTemplate } from '@staticcms/core/lib/registry';
|
||||
import classNames from '@staticcms/core/lib/util/classNames.util';
|
||||
import { selectTemplateName } from '@staticcms/core/lib/util/collection.util';
|
||||
import { useWindowEvent } from '@staticcms/core/lib/util/window.util';
|
||||
import { selectConfig } from '@staticcms/core/reducers/selectors/config';
|
||||
import { selectTheme } from '@staticcms/core/reducers/selectors/globalUI';
|
||||
import { useAppSelector } from '@staticcms/core/store/hooks';
|
||||
@ -25,6 +26,7 @@ import type {
|
||||
TemplatePreviewProps,
|
||||
TranslatedProps,
|
||||
} from '@staticcms/core/interface';
|
||||
import type DataUpdateEvent from '@staticcms/core/lib/util/events/DataEvent';
|
||||
import type { FC } from 'react';
|
||||
|
||||
const FrameGlobalStyles = `
|
||||
@ -110,12 +112,22 @@ export interface EditorPreviewPaneProps {
|
||||
fields: Field[];
|
||||
entry: Entry;
|
||||
previewInFrame: boolean;
|
||||
livePreviewUrlTemplate: string | undefined;
|
||||
editorSize: EditorSize;
|
||||
showMobilePreview: boolean;
|
||||
}
|
||||
|
||||
const EditorPreviewPane = (props: TranslatedProps<EditorPreviewPaneProps>) => {
|
||||
const { editorSize, entry, collection, fields, previewInFrame, showMobilePreview, t } = props;
|
||||
const {
|
||||
editorSize,
|
||||
entry,
|
||||
collection,
|
||||
fields,
|
||||
previewInFrame,
|
||||
livePreviewUrlTemplate,
|
||||
showMobilePreview,
|
||||
t,
|
||||
} = props;
|
||||
|
||||
const config = useAppSelector(selectConfig);
|
||||
|
||||
@ -171,6 +183,15 @@ const EditorPreviewPane = (props: TranslatedProps<EditorPreviewPaneProps>) => {
|
||||
[props, theme, widgetFor, widgetsFor],
|
||||
);
|
||||
|
||||
const livePreviewIframe = useRef<HTMLIFrameElement>(null);
|
||||
const passEventToIframe = useCallback((event: DataUpdateEvent) => {
|
||||
if (livePreviewIframe.current) {
|
||||
livePreviewIframe.current.contentWindow?.postMessage(event);
|
||||
}
|
||||
}, []);
|
||||
|
||||
useWindowEvent('data:update', passEventToIframe);
|
||||
|
||||
return useMemo(() => {
|
||||
if (!element) {
|
||||
return null;
|
||||
@ -196,7 +217,13 @@ const EditorPreviewPane = (props: TranslatedProps<EditorPreviewPaneProps>) => {
|
||||
)}
|
||||
>
|
||||
<ErrorBoundary config={config}>
|
||||
{previewInFrame ? (
|
||||
{livePreviewUrlTemplate ? (
|
||||
<iframe
|
||||
ref={livePreviewIframe}
|
||||
src={`${livePreviewUrlTemplate}?useCmsData=true`}
|
||||
className="w-full h-full"
|
||||
/>
|
||||
) : previewInFrame ? (
|
||||
<Frame
|
||||
key="preview-frame"
|
||||
id="preview-pane"
|
||||
@ -251,6 +278,7 @@ const EditorPreviewPane = (props: TranslatedProps<EditorPreviewPaneProps>) => {
|
||||
editorSize,
|
||||
element,
|
||||
initialFrameContent,
|
||||
livePreviewUrlTemplate,
|
||||
previewComponent,
|
||||
previewInFrame,
|
||||
previewProps,
|
||||
|
@ -190,12 +190,22 @@ export interface FileNameFilterRule {
|
||||
|
||||
export type FilterRule = FieldFilterRule | FileNameFilterRule;
|
||||
|
||||
export interface EditorConfig {
|
||||
preview?: boolean;
|
||||
frame?: boolean;
|
||||
export interface BaseEditorConfig {
|
||||
size?: EditorSize;
|
||||
}
|
||||
|
||||
export interface DefaultEditorConfig extends BaseEditorConfig {
|
||||
preview?: boolean;
|
||||
frame?: boolean;
|
||||
live_preview?: false;
|
||||
}
|
||||
|
||||
export interface LiveEditorConfig extends BaseEditorConfig {
|
||||
live_preview: string;
|
||||
}
|
||||
|
||||
export type EditorConfig = DefaultEditorConfig | LiveEditorConfig;
|
||||
|
||||
export interface CollectionFile<EF extends BaseField = UnknownField> {
|
||||
name: string;
|
||||
label: string;
|
||||
|
Loading…
x
Reference in New Issue
Block a user