payaza-storefront-layouts 1.1.76 → 1.1.78
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/editor/payaza-form/EditorCanvasPreview.d.ts +38 -0
- package/dist/editor/payaza-form/EditorCanvasPreview.d.ts.map +1 -0
- package/dist/editor/payaza-form/EditorCanvasPreview.js +55 -0
- package/dist/editor/payaza-form/IframePreviewMessageBridge.d.ts +3 -4
- package/dist/editor/payaza-form/IframePreviewMessageBridge.d.ts.map +1 -1
- package/dist/editor/payaza-form/IframePreviewMessageBridge.js +11 -81
- package/dist/editor/payaza-form/PayazaFormEditor.d.ts.map +1 -1
- package/dist/editor/payaza-form/PayazaFormEditor.js +109 -68
- package/dist/editor/payaza-form/preview-message-handler.d.ts +18 -0
- package/dist/editor/payaza-form/preview-message-handler.d.ts.map +1 -0
- package/dist/editor/payaza-form/preview-message-handler.js +84 -0
- package/dist/editor/shared/InlineCanvasPreview.d.ts +34 -0
- package/dist/editor/shared/InlineCanvasPreview.d.ts.map +1 -0
- package/dist/editor/shared/InlineCanvasPreview.js +145 -0
- package/dist/editor/shared/index.d.ts +1 -0
- package/dist/editor/shared/index.d.ts.map +1 -1
- package/dist/editor/shared/index.js +1 -0
- package/dist/lib/utils/mobile-editor.d.ts +2 -0
- package/dist/lib/utils/mobile-editor.d.ts.map +1 -1
- package/dist/lib/utils/mobile-editor.js +4 -0
- package/dist/preview/canvas/PreviewCanvasEnhancer.d.ts +3 -1
- package/dist/preview/canvas/PreviewCanvasEnhancer.d.ts.map +1 -1
- package/dist/preview/canvas/PreviewCanvasEnhancer.js +27 -19
- package/dist/preview/canvas/PreviewCanvasStyles.d.ts +4 -0
- package/dist/preview/canvas/PreviewCanvasStyles.d.ts.map +1 -0
- package/dist/preview/canvas/PreviewCanvasStyles.js +51 -0
- package/package.json +1 -1
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { PreviewZoom } from '../shared/preview-viewport';
|
|
3
|
+
import { StoreConfig } from '../../lib/store-types';
|
|
4
|
+
import type { InteractionMode } from '../document/types';
|
|
5
|
+
import type { PayazaInlineFieldCommitPayload } from './IframePreviewMessageBridge';
|
|
6
|
+
import type { PreviewElementFocusPayload } from '../../preview/canvas/preview-messages';
|
|
7
|
+
export interface EditorCanvasPreviewProps {
|
|
8
|
+
layoutId: string;
|
|
9
|
+
config: StoreConfig;
|
|
10
|
+
activePageId: string;
|
|
11
|
+
viewMode: 'desktop' | 'tablet' | 'mobile';
|
|
12
|
+
selectedSection?: string | null;
|
|
13
|
+
focusedField?: {
|
|
14
|
+
sectionKey: string;
|
|
15
|
+
fieldPath: string[];
|
|
16
|
+
elementKind: string;
|
|
17
|
+
} | null;
|
|
18
|
+
interactionMode?: InteractionMode;
|
|
19
|
+
slideIndexSync?: {
|
|
20
|
+
sectionKey: string;
|
|
21
|
+
arrayField: string;
|
|
22
|
+
index: number;
|
|
23
|
+
} | null;
|
|
24
|
+
flushRequestId?: number;
|
|
25
|
+
previewZoom?: PreviewZoom;
|
|
26
|
+
editorContext: {
|
|
27
|
+
layoutId: string;
|
|
28
|
+
activePageId: string;
|
|
29
|
+
};
|
|
30
|
+
onSectionSelected: (sectionKey: string) => void;
|
|
31
|
+
onFieldCommit: (payload: PayazaInlineFieldCommitPayload) => void;
|
|
32
|
+
onSectionReorder: (sectionKey: string, direction: 'up' | 'down') => void;
|
|
33
|
+
onFocusSidebarSection: (sectionKey: string) => void;
|
|
34
|
+
onPreviewElementFocus?: (payload: Omit<PreviewElementFocusPayload, 'type'>) => void;
|
|
35
|
+
onRouteChange?: (route: string) => void;
|
|
36
|
+
}
|
|
37
|
+
export declare function EditorCanvasPreview({ layoutId, config, activePageId, viewMode, selectedSection, focusedField, interactionMode, slideIndexSync, flushRequestId, previewZoom, editorContext, onSectionSelected, onFieldCommit, onSectionReorder, onFocusSidebarSection, onPreviewElementFocus, onRouteChange, }: EditorCanvasPreviewProps): React.JSX.Element;
|
|
38
|
+
//# sourceMappingURL=EditorCanvasPreview.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EditorCanvasPreview.d.ts","sourceRoot":"","sources":["../../../src/editor/payaza-form/EditorCanvasPreview.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAsB,MAAM,OAAO,CAAC;AAG3C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAC9D,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACpD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAIzD,OAAO,KAAK,EAAE,8BAA8B,EAAE,MAAM,8BAA8B,CAAC;AACnF,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,uCAAuC,CAAC;AAExF,MAAM,WAAW,wBAAwB;IACvC,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,WAAW,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,SAAS,GAAG,QAAQ,GAAG,QAAQ,CAAC;IAC1C,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,YAAY,CAAC,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,EAAE,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IACvF,eAAe,CAAC,EAAE,eAAe,CAAC;IAClC,cAAc,CAAC,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAClF,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,aAAa,EAAE;QACb,QAAQ,EAAE,MAAM,CAAC;QACjB,YAAY,EAAE,MAAM,CAAC;KACtB,CAAC;IACF,iBAAiB,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IAChD,aAAa,EAAE,CAAC,OAAO,EAAE,8BAA8B,KAAK,IAAI,CAAC;IACjE,gBAAgB,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,GAAG,MAAM,KAAK,IAAI,CAAC;IACzE,qBAAqB,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IACpD,qBAAqB,CAAC,EAAE,CAAC,OAAO,EAAE,IAAI,CAAC,0BAA0B,EAAE,MAAM,CAAC,KAAK,IAAI,CAAC;IACpF,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACzC;AAED,wBAAgB,mBAAmB,CAAC,EAClC,QAAQ,EACR,MAAM,EACN,YAAY,EACZ,QAAQ,EACR,eAAe,EACf,YAAY,EACZ,eAAe,EACf,cAAc,EACd,cAAc,EACd,WAAW,EACX,aAAa,EACb,iBAAiB,EACjB,aAAa,EACb,gBAAgB,EAChB,qBAAqB,EACrB,qBAAqB,EACrB,aAAa,GACd,EAAE,wBAAwB,qBA6D1B"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { useCallback } from 'react';
|
|
4
|
+
import { IframePreview } from '../shared/IframePreview.js';
|
|
5
|
+
import { InlineCanvasPreview } from '../shared/InlineCanvasPreview.js';
|
|
6
|
+
import { shouldUseInlineEditorPreview } from '../../lib/utils/mobile-editor.js';
|
|
7
|
+
import { useAssetSelection } from './AssetSelectionContext.js';
|
|
8
|
+
import { processPreviewMessage } from './preview-message-handler.js';
|
|
9
|
+
export function EditorCanvasPreview({ layoutId, config, activePageId, viewMode, selectedSection, focusedField, interactionMode, slideIndexSync, flushRequestId, previewZoom, editorContext, onSectionSelected, onFieldCommit, onSectionReorder, onFocusSidebarSection, onPreviewElementFocus, onRouteChange, }) {
|
|
10
|
+
const useInline = shouldUseInlineEditorPreview();
|
|
11
|
+
const { onOpenAssetSelect } = useAssetSelection();
|
|
12
|
+
const handlePreviewEvent = useCallback((payload) => {
|
|
13
|
+
processPreviewMessage(payload, {
|
|
14
|
+
editorContext,
|
|
15
|
+
onSectionSelected,
|
|
16
|
+
onFieldCommit,
|
|
17
|
+
onSectionReorder,
|
|
18
|
+
onFocusSidebarSection,
|
|
19
|
+
onPreviewElementFocus,
|
|
20
|
+
onRouteChange,
|
|
21
|
+
onOpenAssetSelect,
|
|
22
|
+
});
|
|
23
|
+
}, [
|
|
24
|
+
editorContext,
|
|
25
|
+
onFieldCommit,
|
|
26
|
+
onFocusSidebarSection,
|
|
27
|
+
onOpenAssetSelect,
|
|
28
|
+
onPreviewElementFocus,
|
|
29
|
+
onRouteChange,
|
|
30
|
+
onSectionReorder,
|
|
31
|
+
onSectionSelected,
|
|
32
|
+
]);
|
|
33
|
+
const handleInlineReady = useCallback(() => {
|
|
34
|
+
if (typeof window !== 'undefined') {
|
|
35
|
+
window.postMessage({ type: 'PREVIEW_READY' }, '*');
|
|
36
|
+
}
|
|
37
|
+
}, []);
|
|
38
|
+
const previewViewMode = useInline ? 'mobile' : viewMode;
|
|
39
|
+
const commonProps = {
|
|
40
|
+
layoutId,
|
|
41
|
+
config,
|
|
42
|
+
activePageId,
|
|
43
|
+
viewMode: previewViewMode,
|
|
44
|
+
selectedSection,
|
|
45
|
+
focusedField,
|
|
46
|
+
interactionMode,
|
|
47
|
+
slideIndexSync,
|
|
48
|
+
flushRequestId,
|
|
49
|
+
previewZoom,
|
|
50
|
+
};
|
|
51
|
+
if (useInline) {
|
|
52
|
+
return (_jsx(InlineCanvasPreview, { ...commonProps, onPreviewEvent: handlePreviewEvent, onReady: handleInlineReady }));
|
|
53
|
+
}
|
|
54
|
+
return _jsx(IframePreview, { ...commonProps });
|
|
55
|
+
}
|
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
import { type PreviewElementFocusPayload, type PreviewFieldCommitPayload } from '../../preview/canvas/preview-messages';
|
|
2
1
|
export interface PayazaInlineFieldCommitPayload {
|
|
3
2
|
sectionKey: string;
|
|
4
3
|
fieldPath: string[];
|
|
5
4
|
valueText: string;
|
|
6
|
-
richText?: PreviewFieldCommitPayload['richText'];
|
|
7
|
-
elementKind?: PreviewFieldCommitPayload['elementKind'];
|
|
5
|
+
richText?: import('../../preview/canvas/preview-messages').PreviewFieldCommitPayload['richText'];
|
|
6
|
+
elementKind?: import('../../preview/canvas/preview-messages').PreviewFieldCommitPayload['elementKind'];
|
|
8
7
|
}
|
|
9
8
|
export interface IframePreviewMessageBridgeProps {
|
|
10
9
|
/** Active editor layout id + overlay page — commits must match. */
|
|
@@ -16,7 +15,7 @@ export interface IframePreviewMessageBridgeProps {
|
|
|
16
15
|
onFieldCommit: (payload: PayazaInlineFieldCommitPayload) => void;
|
|
17
16
|
onSectionReorder: (sectionKey: string, direction: 'up' | 'down') => void;
|
|
18
17
|
onFocusSidebarSection: (sectionKey: string) => void;
|
|
19
|
-
onPreviewElementFocus?: (payload: Omit<PreviewElementFocusPayload, 'type'>) => void;
|
|
18
|
+
onPreviewElementFocus?: (payload: Omit<import('../../preview/canvas/preview-messages').PreviewElementFocusPayload, 'type'>) => void;
|
|
20
19
|
/** Called when the preview navigates to a new route so the editor can sync its activePageId. */
|
|
21
20
|
onRouteChange?: (route: string) => void;
|
|
22
21
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"IframePreviewMessageBridge.d.ts","sourceRoot":"","sources":["../../../src/editor/payaza-form/IframePreviewMessageBridge.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"IframePreviewMessageBridge.d.ts","sourceRoot":"","sources":["../../../src/editor/payaza-form/IframePreviewMessageBridge.tsx"],"names":[],"mappings":"AAOA,MAAM,WAAW,8BAA8B;IAC7C,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,uCAAuC,EAAE,yBAAyB,CAAC,UAAU,CAAC,CAAC;IACjG,WAAW,CAAC,EAAE,OAAO,uCAAuC,EAAE,yBAAyB,CAAC,aAAa,CAAC,CAAC;CACxG;AAED,MAAM,WAAW,+BAA+B;IAC9C,mEAAmE;IACnE,aAAa,EAAE;QACb,QAAQ,EAAE,MAAM,CAAC;QACjB,YAAY,EAAE,MAAM,CAAC;KACtB,CAAC;IACF,iBAAiB,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IAChD,aAAa,EAAE,CAAC,OAAO,EAAE,8BAA8B,KAAK,IAAI,CAAC;IACjE,gBAAgB,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,GAAG,MAAM,KAAK,IAAI,CAAC;IACzE,qBAAqB,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IACpD,qBAAqB,CAAC,EAAE,CAAC,OAAO,EAAE,IAAI,CAAC,OAAO,uCAAuC,EAAE,0BAA0B,EAAE,MAAM,CAAC,KAAK,IAAI,CAAC;IACpI,gGAAgG;IAChG,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACzC;AAED;;;GAGG;AACH,wBAAgB,0BAA0B,CAAC,EACzC,aAAa,EACb,iBAAiB,EACjB,aAAa,EACb,gBAAgB,EAChB,qBAAqB,EACrB,qBAAqB,EACrB,aAAa,GACd,EAAE,+BAA+B,OAqCjC;AAED,+EAA+E;AAC/E,wBAAgB,qBAAqB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAElE"}
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { useEffect, useCallback } from 'react';
|
|
3
3
|
import { useAssetSelection } from './AssetSelectionContext.js';
|
|
4
|
-
import {
|
|
4
|
+
import { processPreviewMessage } from './preview-message-handler.js';
|
|
5
5
|
import { normalizeEditorLayoutId } from '../document/layout-id.js';
|
|
6
|
-
import { previewCommitsMatchEditorContext } from '../../preview/canvas/preview-isolation.js';
|
|
7
6
|
/**
|
|
8
7
|
* Handles postMessage from the layout preview iframe (field commit, image replace, reorder).
|
|
9
8
|
* Must render under AssetSelectionProvider for image replacement.
|
|
@@ -14,85 +13,16 @@ export function IframePreviewMessageBridge({ editorContext, onSectionSelected, o
|
|
|
14
13
|
const d = event.data;
|
|
15
14
|
if (!d || typeof d !== 'object')
|
|
16
15
|
return;
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
if (!ok)
|
|
28
|
-
return;
|
|
29
|
-
onPreviewElementFocus?.({
|
|
30
|
-
layoutId: payload.layoutId,
|
|
31
|
-
pageId: payload.pageId,
|
|
32
|
-
sectionKey: payload.sectionKey,
|
|
33
|
-
fieldPath: payload.fieldPath,
|
|
34
|
-
elementKind: payload.elementKind,
|
|
35
|
-
});
|
|
36
|
-
return;
|
|
37
|
-
}
|
|
38
|
-
if (d.type === PREVIEW_MSG.FIELD_COMMIT) {
|
|
39
|
-
const payload = d;
|
|
40
|
-
const ok = previewCommitsMatchEditorContext({ layoutId: payload.layoutId, pageId: payload.pageId }, { layoutId: editorContext.layoutId, pageId: editorContext.activePageId });
|
|
41
|
-
if (!ok)
|
|
42
|
-
return;
|
|
43
|
-
onFieldCommit({
|
|
44
|
-
sectionKey: payload.sectionKey,
|
|
45
|
-
fieldPath: payload.fieldPath,
|
|
46
|
-
valueText: String(payload.value ?? ''),
|
|
47
|
-
richText: payload.richText,
|
|
48
|
-
elementKind: payload.elementKind,
|
|
49
|
-
});
|
|
50
|
-
return;
|
|
51
|
-
}
|
|
52
|
-
if (d.type === PREVIEW_MSG.SECTION_REORDER) {
|
|
53
|
-
const { sectionKey, direction, layoutId, pageId } = d;
|
|
54
|
-
const ok = layoutId &&
|
|
55
|
-
pageId &&
|
|
56
|
-
previewCommitsMatchEditorContext({ layoutId, pageId }, { layoutId: editorContext.layoutId, pageId: editorContext.activePageId });
|
|
57
|
-
if (!ok)
|
|
58
|
-
return;
|
|
59
|
-
if (sectionKey && (direction === 'up' || direction === 'down')) {
|
|
60
|
-
onSectionReorder(sectionKey, direction);
|
|
61
|
-
}
|
|
62
|
-
return;
|
|
63
|
-
}
|
|
64
|
-
if (d.type === PREVIEW_MSG.IMAGE_ACTIVATE) {
|
|
65
|
-
const { sectionKey, fieldPath, layoutId, pageId } = d;
|
|
66
|
-
const ok = layoutId &&
|
|
67
|
-
pageId &&
|
|
68
|
-
previewCommitsMatchEditorContext({ layoutId, pageId }, { layoutId: editorContext.layoutId, pageId: editorContext.activePageId });
|
|
69
|
-
if (!ok)
|
|
70
|
-
return;
|
|
71
|
-
if (sectionKey && Array.isArray(fieldPath)) {
|
|
72
|
-
onOpenAssetSelect((url) => {
|
|
73
|
-
onFieldCommit({
|
|
74
|
-
sectionKey,
|
|
75
|
-
fieldPath,
|
|
76
|
-
valueText: url,
|
|
77
|
-
elementKind: 'image',
|
|
78
|
-
});
|
|
79
|
-
});
|
|
80
|
-
}
|
|
81
|
-
return;
|
|
82
|
-
}
|
|
83
|
-
if (d.type === 'PREVIEW_FOCUS_SIDEBAR') {
|
|
84
|
-
const sk = d.sectionKey;
|
|
85
|
-
if (typeof sk === 'string' && sk) {
|
|
86
|
-
onFocusSidebarSection(sk);
|
|
87
|
-
}
|
|
88
|
-
return;
|
|
89
|
-
}
|
|
90
|
-
if (d.type === 'ROUTE_CHANGED') {
|
|
91
|
-
const route = d.route;
|
|
92
|
-
if (typeof route === 'string' && route) {
|
|
93
|
-
onRouteChange?.(route);
|
|
94
|
-
}
|
|
95
|
-
}
|
|
16
|
+
processPreviewMessage(d, {
|
|
17
|
+
editorContext,
|
|
18
|
+
onSectionSelected,
|
|
19
|
+
onFieldCommit,
|
|
20
|
+
onSectionReorder,
|
|
21
|
+
onFocusSidebarSection,
|
|
22
|
+
onPreviewElementFocus,
|
|
23
|
+
onRouteChange,
|
|
24
|
+
onOpenAssetSelect,
|
|
25
|
+
});
|
|
96
26
|
}, [
|
|
97
27
|
editorContext.activePageId,
|
|
98
28
|
editorContext.layoutId,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PayazaFormEditor.d.ts","sourceRoot":"","sources":["../../../src/editor/payaza-form/PayazaFormEditor.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA6E,MAAM,OAAO,CAAC;AAClG,OAAO,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"PayazaFormEditor.d.ts","sourceRoot":"","sources":["../../../src/editor/payaza-form/PayazaFormEditor.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA6E,MAAM,OAAO,CAAC;AAClG,OAAO,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC;AAkB/C,OAAO,EAA4B,eAAe,EAAgB,MAAM,mBAAmB,CAAC;AA2D5F,MAAM,WAAW,qBAAsB,SAAQ,mBAAmB;IAChE;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;CACjD;AAED,eAAO,MAAM,gBAAgB,EAAE,KAAK,CAAC,EAAE,CAAC,qBAAqB,CAoxD5D,CAAC"}
|
|
@@ -3,7 +3,6 @@ import { useState, useMemo, useEffect, useLayoutEffect, useRef, useCallback } fr
|
|
|
3
3
|
import { previewRouteToPageId } from '../../preview/canvas/preview-route.js';
|
|
4
4
|
import { EditorHeader } from '../shared/EditorHeader.js';
|
|
5
5
|
import { EditorNavigator } from '../shared/EditorNavigator.js';
|
|
6
|
-
import { IframePreview } from '../shared/IframePreview.js';
|
|
7
6
|
import { ResizableSidebar } from '../shared/ResizableSidebar.js';
|
|
8
7
|
import { moveSectionKeyInPageOrder, normalizeEditorLayoutId, resolveSectionKeyOrderForPage, storeConfigToEnvelope, } from '../document/index.js';
|
|
9
8
|
import { payazaSectionStyleKey, getPayazaSectionStyleEntries } from '../../lib/payaza-section-styles.js';
|
|
@@ -19,6 +18,7 @@ import { AIGenerateModal } from '../shared/AIGenerateModal.js';
|
|
|
19
18
|
import { useAlertModal } from '../../components/ui/alert-modal.js';
|
|
20
19
|
import { AssetSelectionProvider } from './AssetSelectionContext.js';
|
|
21
20
|
import { IframePreviewMessageBridge } from './IframePreviewMessageBridge.js';
|
|
21
|
+
import { EditorCanvasPreview } from './EditorCanvasPreview.js';
|
|
22
22
|
import { BlockStylesInspector } from './components/BlockStylesInspector.js';
|
|
23
23
|
import { CanvasGranularInspector } from './components/CanvasGranularInspector.js';
|
|
24
24
|
import { SectionSchemaInspector } from './components/SectionSchemaInspector.js';
|
|
@@ -27,7 +27,34 @@ import { resolveCanvasInspectorLeaf } from '../alignment-schemas/resolve-canvas-
|
|
|
27
27
|
import { granularPathForArrayItem, granularPathForBlockFirstAttr, outlineTreeForSectionPayload, } from '../blocks/nav-outline-utils.js';
|
|
28
28
|
import { ActiveArrayFocusProvider, } from './ActiveArrayFocusContext.js';
|
|
29
29
|
import { EditorLayoutProvider } from './EditorLayoutContext.js';
|
|
30
|
-
import { isMobileEditorViewport } from '../../lib/utils/mobile-editor.js';
|
|
30
|
+
import { isMobileEditorViewport, shouldUseInlineEditorPreview } from '../../lib/utils/mobile-editor.js';
|
|
31
|
+
/** Lightweight fingerprint for undo history on mobile — avoids JSON.stringify on large configs. */
|
|
32
|
+
function lightweightConfigFingerprint(config) {
|
|
33
|
+
try {
|
|
34
|
+
const layoutConfig = config.layoutConfig;
|
|
35
|
+
const pages = layoutConfig?.pages;
|
|
36
|
+
if (Array.isArray(pages)) {
|
|
37
|
+
return pages
|
|
38
|
+
.map((page) => {
|
|
39
|
+
const p = page;
|
|
40
|
+
const sections = p.sections;
|
|
41
|
+
if (!Array.isArray(sections))
|
|
42
|
+
return '';
|
|
43
|
+
return sections
|
|
44
|
+
.map((s) => {
|
|
45
|
+
const sec = s;
|
|
46
|
+
return String(sec.key ?? sec.id ?? '');
|
|
47
|
+
})
|
|
48
|
+
.join(',');
|
|
49
|
+
})
|
|
50
|
+
.join('|');
|
|
51
|
+
}
|
|
52
|
+
return String(config.layout ?? '');
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
return '';
|
|
56
|
+
}
|
|
57
|
+
}
|
|
31
58
|
export const PayazaFormEditor = ({ layoutId, initialData, inventory, onChange, onSave, onPublish, onBack, onBackToSettings, onOpenAssets, onBackToTheme, title, className = '', customWidgets, storeName, storeDescription, assets, publishButtonText, onEditorDocumentChange, initialDataIsPublished, onEditorHydrated, preloadedBaseRequirement, catalogOverlay, }) => {
|
|
32
59
|
const [activePageId, setActivePageId] = useState('home');
|
|
33
60
|
const [data, setData] = useState(initialData);
|
|
@@ -40,7 +67,8 @@ export const PayazaFormEditor = ({ layoutId, initialData, inventory, onChange, o
|
|
|
40
67
|
const [history, setHistory] = useState([initialData]);
|
|
41
68
|
const [historyIndex, setHistoryIndex] = useState(0);
|
|
42
69
|
const isInternalChange = useRef(false);
|
|
43
|
-
const
|
|
70
|
+
const useInlinePreview = shouldUseInlineEditorPreview();
|
|
71
|
+
const MAX_HISTORY = useInlinePreview ? 8 : 50;
|
|
44
72
|
// Track last published data to disable publish button if no changes.
|
|
45
73
|
// When initialDataIsPublished is explicitly false (a draft was loaded), start with null
|
|
46
74
|
// so hasChangesSincePublish is true immediately — the draft IS an unpublished change.
|
|
@@ -175,7 +203,11 @@ export const PayazaFormEditor = ({ layoutId, initialData, inventory, onChange, o
|
|
|
175
203
|
setHistory(prev => {
|
|
176
204
|
const newHistory = prev.slice(0, historyIndex + 1);
|
|
177
205
|
// Only add if data is different from the last entry
|
|
178
|
-
|
|
206
|
+
const lastEntry = newHistory[newHistory.length - 1];
|
|
207
|
+
const isDuplicate = useInlinePreview
|
|
208
|
+
? lightweightConfigFingerprint(lastEntry) === lightweightConfigFingerprint(data)
|
|
209
|
+
: JSON.stringify(lastEntry) === JSON.stringify(data);
|
|
210
|
+
if (!isDuplicate) {
|
|
179
211
|
const updatedHistory = [...newHistory, data];
|
|
180
212
|
if (updatedHistory.length > MAX_HISTORY) {
|
|
181
213
|
return updatedHistory.slice(1);
|
|
@@ -189,7 +221,7 @@ export const PayazaFormEditor = ({ layoutId, initialData, inventory, onChange, o
|
|
|
189
221
|
setHistoryIndex(prev => prev + 1);
|
|
190
222
|
}
|
|
191
223
|
isInternalChange.current = false;
|
|
192
|
-
}, [data]);
|
|
224
|
+
}, [data, historyIndex, MAX_HISTORY, useInlinePreview]);
|
|
193
225
|
// Fix the history index after history update
|
|
194
226
|
useEffect(() => {
|
|
195
227
|
if (history.length > 0 && historyIndex >= history.length) {
|
|
@@ -947,6 +979,76 @@ export const PayazaFormEditor = ({ layoutId, initialData, inventory, onChange, o
|
|
|
947
979
|
// but it helps prevent state updates if the user closes the modal or navigates away.
|
|
948
980
|
// In a real scenario, we might want to use AbortController.
|
|
949
981
|
};
|
|
982
|
+
const previewEditorContext = useMemo(() => ({
|
|
983
|
+
layoutId: normalizedLayoutType ?? String(layoutId),
|
|
984
|
+
activePageId,
|
|
985
|
+
}), [normalizedLayoutType, layoutId, activePageId]);
|
|
986
|
+
const handlePreviewRouteChange = useCallback((route) => {
|
|
987
|
+
const editorLayoutId = normalizedLayoutType ?? String(layoutId);
|
|
988
|
+
const nextPageId = previewRouteToPageId(route, editorLayoutId);
|
|
989
|
+
if (nextPageId &&
|
|
990
|
+
nextPageId !== activePageId &&
|
|
991
|
+
isLayoutPageEditable(editorLayoutId, nextPageId)) {
|
|
992
|
+
setActivePageId(nextPageId);
|
|
993
|
+
setSelectedSection(null);
|
|
994
|
+
setCanvasElementFocus(null);
|
|
995
|
+
setActiveArrayFocus(null);
|
|
996
|
+
}
|
|
997
|
+
}, [normalizedLayoutType, layoutId, activePageId]);
|
|
998
|
+
const handlePreviewSectionSelected = useCallback((sectionKey) => {
|
|
999
|
+
setSelectedSection(sectionKey);
|
|
1000
|
+
requestAnimationFrame(() => {
|
|
1001
|
+
document
|
|
1002
|
+
.querySelector(`[data-section-key="${sectionKey}"]`)
|
|
1003
|
+
?.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
|
1004
|
+
});
|
|
1005
|
+
}, []);
|
|
1006
|
+
const handlePreviewFieldCommit = useCallback((payload) => {
|
|
1007
|
+
let value = payload.richText ?? payload.valueText;
|
|
1008
|
+
if (payload.elementKind === 'rating') {
|
|
1009
|
+
const parsed = Number(payload.valueText);
|
|
1010
|
+
value = Number.isFinite(parsed)
|
|
1011
|
+
? Math.min(5, Math.max(1, Math.round(parsed)))
|
|
1012
|
+
: 5;
|
|
1013
|
+
}
|
|
1014
|
+
handleFieldChange(payload.sectionKey, payload.fieldPath, value);
|
|
1015
|
+
},
|
|
1016
|
+
// handleFieldChange is a stable-enough plain function defined above in this component.
|
|
1017
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
1018
|
+
[]);
|
|
1019
|
+
const handlePreviewElementFocus = useCallback((p) => {
|
|
1020
|
+
setCanvasElementFocus(p);
|
|
1021
|
+
setSelectedSection(p.sectionKey);
|
|
1022
|
+
setBlockSubTab('settings');
|
|
1023
|
+
if (p.fieldPath[0] === 'items' && /^\d+$/.test(p.fieldPath[1] ?? '')) {
|
|
1024
|
+
setActiveArrayFocus({
|
|
1025
|
+
sectionKey: p.sectionKey,
|
|
1026
|
+
fieldKey: 'items',
|
|
1027
|
+
index: parseInt(p.fieldPath[1], 10),
|
|
1028
|
+
});
|
|
1029
|
+
}
|
|
1030
|
+
else if (p.fieldPath[0] === 'sliders' && /^\d+$/.test(p.fieldPath[1] ?? '')) {
|
|
1031
|
+
setActiveArrayFocus({
|
|
1032
|
+
sectionKey: p.sectionKey,
|
|
1033
|
+
fieldKey: 'sliders',
|
|
1034
|
+
index: parseInt(p.fieldPath[1], 10),
|
|
1035
|
+
});
|
|
1036
|
+
}
|
|
1037
|
+
requestAnimationFrame(() => {
|
|
1038
|
+
document
|
|
1039
|
+
.querySelector(`[data-section-key="${p.sectionKey}"]`)
|
|
1040
|
+
?.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
|
1041
|
+
});
|
|
1042
|
+
}, []);
|
|
1043
|
+
const handlePreviewFocusSidebarSection = useCallback((sectionKey) => {
|
|
1044
|
+
setSelectedSection(sectionKey);
|
|
1045
|
+
setBlockSubTab('settings');
|
|
1046
|
+
requestAnimationFrame(() => {
|
|
1047
|
+
document
|
|
1048
|
+
.querySelector(`[data-section-key="${sectionKey}"]`)
|
|
1049
|
+
?.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
|
1050
|
+
});
|
|
1051
|
+
}, []);
|
|
950
1052
|
if (loading) {
|
|
951
1053
|
return (_jsxs("div", { className: "flex h-full flex-col overflow-hidden bg-[#F7F5F0] font-sans", children: [_jsxs("div", { className: "flex min-h-[72px] shrink-0 items-center justify-between border-b border-[#e6e9ee] bg-white/95 px-4 py-2 md:px-5", children: [_jsxs("div", { className: "flex items-center gap-4", children: [_jsx("div", { className: "h-10 w-10 animate-pulse rounded-xl bg-slate-100" }), _jsxs("div", { className: "space-y-2", children: [_jsx("div", { className: "h-3 w-28 animate-pulse rounded bg-slate-100" }), _jsx("div", { className: "h-2 w-20 animate-pulse rounded bg-slate-100" })] })] }), _jsxs("div", { className: "flex gap-3", children: [_jsx("div", { className: "h-10 w-24 animate-pulse rounded-xl bg-slate-100" }), _jsx("div", { className: "h-10 w-28 animate-pulse rounded-xl bg-slate-100" })] })] }), _jsxs("div", { className: "flex min-h-0 flex-1", children: [_jsx("div", { className: "flex flex-1 items-center justify-center bg-[#e2e4e7] p-8", children: _jsx("div", { className: "h-full min-h-[200px] w-full max-w-4xl animate-pulse rounded-lg bg-white/60 shadow-inner ring-1 ring-[#e8e8e8]" }) }), _jsxs("div", { className: "w-[380px] space-y-8 border-l border-[#dcdcde] bg-white p-6", children: [_jsxs("div", { className: "space-y-4", children: [_jsx("div", { className: "w-32 h-4 bg-slate-50 animate-pulse rounded" }), _jsx("div", { className: "w-full h-12 bg-slate-50 animate-pulse rounded-xl" })] }), _jsx("div", { className: "space-y-6", children: [1, 2, 3, 4].map(i => (_jsx("div", { className: "w-full h-20 bg-slate-50 animate-pulse rounded-2xl" }, i))) })] })] })] }));
|
|
952
1054
|
}
|
|
@@ -963,68 +1065,7 @@ export const PayazaFormEditor = ({ layoutId, initialData, inventory, onChange, o
|
|
|
963
1065
|
handleFieldChange(canvasElementFocus.sectionKey, [...canvasElementFocus.fieldPath, 'attributes', 'payazaStyle'], next);
|
|
964
1066
|
}
|
|
965
1067
|
} })) : (_jsxs(_Fragment, { children: [granularInspectorActive && (_jsx("div", { className: "border-b border-[#e8e9ec] bg-[#fafafa] px-4 py-2.5", children: _jsxs("p", { className: "text-[11px] text-[#787c82]", children: ["Styles apply to the ", _jsx("strong", { className: "font-medium text-[#1b0029]", children: selectedSectionLabel ?? 'section' }), " containing this element."] }) })), _jsx(BlockStylesInspector, { supports: selectedSectionStyleSupports, value: selectedBlockStyleEntries, onChange: (next) => selectedSection && handleBlockStylesChange(selectedSection, next) })] }))) : canvasElementFocus?.elementKind === 'group' ? (_jsxs("div", { className: "px-4 py-6", children: [_jsxs("div", { className: "mb-4 flex items-center gap-2", children: [_jsx(Layers, { className: "h-4 w-4 shrink-0 text-[#440066]", strokeWidth: 2, "aria-hidden": true }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsx("p", { className: "text-[13px] font-semibold text-[#1b0029]", children: "Group" }), _jsx("p", { className: "truncate text-[11px] text-[#787c82]", children: canvasElementFocus.fieldPath.join(' › ') })] })] }), _jsxs("p", { className: "text-[12px] text-[#646970]", children: ["Switch to the ", _jsx("strong", { className: "font-medium text-[#1b0029]", children: "Styles" }), " tab to edit group layout, spacing, and colors."] })] })) : granularInspectorActive && canvasElementFocus && layoutJson && pageSchema ? (_jsxs(_Fragment, { children: [granularBreadcrumbLabel ? (_jsxs("div", { className: "border-b border-[#e8e9ec] bg-[#fafafa] px-4 py-2.5", children: [_jsx("p", { className: "text-[10px] font-semibold uppercase tracking-wider text-[#1b0029]/40", children: "Editing" }), _jsx("p", { className: "mt-0.5 truncate text-[13px] font-semibold text-[#1b0029]", children: granularBreadcrumbLabel })] })) : null, _jsx(CanvasGranularInspector, { layoutJson: layoutJson, activePageId: activePageId, sectionKey: canvasElementFocus.sectionKey, fieldPath: canvasElementFocus.fieldPath, elementKind: canvasElementFocus.elementKind, pageSchemaRecord: pageSchema.schema, sectionData: pageSchema.data[canvasElementFocus.sectionKey], onChange: (sk, fp, val) => handleFieldChange(sk, fp, val) })] })) : selectedSection && pageSchema?.schema[selectedSection] ? (_jsx(SectionSchemaInspector, { sectionKey: selectedSection, sectionSchema: pageSchema.schema[selectedSection], sectionData: pageSchema.data[selectedSection], onFieldChange: (sk, fp, val) => handleFieldChange(sk, fp, val) })) : (_jsx("div", { className: "flex flex-col items-center justify-center px-5 py-12 text-center", children: _jsx("p", { className: "text-[13px] text-[#646970]", children: "Select a section in the List View or click the canvas to begin editing." }) })) })] }));
|
|
966
|
-
return (_jsx(EditorLayoutProvider, { value: { layoutId: normalizedLayoutType ?? String(layoutId) }, children: _jsxs(AssetSelectionProvider, { onOpenAssets: onOpenAssets, assets: assets, children: [_jsx(IframePreviewMessageBridge, { editorContext: {
|
|
967
|
-
layoutId: normalizedLayoutType ?? String(layoutId),
|
|
968
|
-
activePageId,
|
|
969
|
-
}, onRouteChange: (route) => {
|
|
970
|
-
const editorLayoutId = normalizedLayoutType ?? String(layoutId);
|
|
971
|
-
const nextPageId = previewRouteToPageId(route, editorLayoutId);
|
|
972
|
-
if (nextPageId &&
|
|
973
|
-
nextPageId !== activePageId &&
|
|
974
|
-
isLayoutPageEditable(editorLayoutId, nextPageId)) {
|
|
975
|
-
setActivePageId(nextPageId);
|
|
976
|
-
setSelectedSection(null);
|
|
977
|
-
setCanvasElementFocus(null);
|
|
978
|
-
setActiveArrayFocus(null);
|
|
979
|
-
}
|
|
980
|
-
}, onSectionSelected: (sectionKey) => {
|
|
981
|
-
setSelectedSection(sectionKey);
|
|
982
|
-
requestAnimationFrame(() => {
|
|
983
|
-
document
|
|
984
|
-
.querySelector(`[data-section-key="${sectionKey}"]`)
|
|
985
|
-
?.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
|
986
|
-
});
|
|
987
|
-
}, onFieldCommit: (payload) => {
|
|
988
|
-
let value = payload.richText ?? payload.valueText;
|
|
989
|
-
if (payload.elementKind === 'rating') {
|
|
990
|
-
const parsed = Number(payload.valueText);
|
|
991
|
-
value = Number.isFinite(parsed)
|
|
992
|
-
? Math.min(5, Math.max(1, Math.round(parsed)))
|
|
993
|
-
: 5;
|
|
994
|
-
}
|
|
995
|
-
handleFieldChange(payload.sectionKey, payload.fieldPath, value);
|
|
996
|
-
}, onSectionReorder: handleReorderSection, onPreviewElementFocus: (p) => {
|
|
997
|
-
setCanvasElementFocus(p);
|
|
998
|
-
setSelectedSection(p.sectionKey);
|
|
999
|
-
setBlockSubTab('settings');
|
|
1000
|
-
if (p.fieldPath[0] === 'items' && /^\d+$/.test(p.fieldPath[1] ?? '')) {
|
|
1001
|
-
setActiveArrayFocus({
|
|
1002
|
-
sectionKey: p.sectionKey,
|
|
1003
|
-
fieldKey: 'items',
|
|
1004
|
-
index: parseInt(p.fieldPath[1], 10),
|
|
1005
|
-
});
|
|
1006
|
-
}
|
|
1007
|
-
else if (p.fieldPath[0] === 'sliders' && /^\d+$/.test(p.fieldPath[1] ?? '')) {
|
|
1008
|
-
setActiveArrayFocus({
|
|
1009
|
-
sectionKey: p.sectionKey,
|
|
1010
|
-
fieldKey: 'sliders',
|
|
1011
|
-
index: parseInt(p.fieldPath[1], 10),
|
|
1012
|
-
});
|
|
1013
|
-
}
|
|
1014
|
-
requestAnimationFrame(() => {
|
|
1015
|
-
document
|
|
1016
|
-
.querySelector(`[data-section-key="${p.sectionKey}"]`)
|
|
1017
|
-
?.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
|
1018
|
-
});
|
|
1019
|
-
}, onFocusSidebarSection: (sectionKey) => {
|
|
1020
|
-
setSelectedSection(sectionKey);
|
|
1021
|
-
setBlockSubTab('settings');
|
|
1022
|
-
requestAnimationFrame(() => {
|
|
1023
|
-
document
|
|
1024
|
-
.querySelector(`[data-section-key="${sectionKey}"]`)
|
|
1025
|
-
?.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
|
1026
|
-
});
|
|
1027
|
-
} }), _jsx(ActiveArrayFocusProvider, { sectionKey: selectedSection, focus: activeArrayFocus, onFocusChange: handleActiveArrayFocusChange, onBeforeIndexChange: flushPreviewEdits, children: _jsxs("div", { className: `flex h-full min-h-0 flex-col bg-[#F7F5F0] ${className} font-sans antialiased text-[#1b0029]`, children: [_jsx(EditorHeader, { layoutName: layoutJson.layoutName || layoutId, storeName: storeName, storeLogo: initialData?.branding?.logo, activePage: activePageId, pages: pages, onPageSwitch: setActivePageId, showPageSwitcher: false, showPageContextCard: false, currentPageLabel: currentPageLabel, onSave: handleSave, onPublish: onPublish && hasChangesSincePublish ? handlePublish : undefined, onBack: onBack, onBackToSettings: onBackToSettings, onOpenAssets: onOpenAssets, onBackToTheme: onBackToTheme, onUndo: handleUndo, onRedo: handleRedo, canUndo: historyIndex > 0, canRedo: historyIndex < history.length - 1, viewMode: viewMode, onViewModeChange: setViewMode, previewZoom: previewZoom, onPreviewZoomChange: setPreviewZoom, editorType: "payaza-form", isSaving: isSaving, isPublishing: isPublishing, onGenerateAI: () => setIsAIModalOpen(true), isGeneratingAI: isGeneratingAI, publishButtonText: publishButtonText, centerTemplateLabel: centerTemplateLabel, outlinePanelOpen: isMobileView ? mobilePanelView === 'outline' : outlinePanelOpen, onToggleOutlinePanel: handleToggleOutlinePanel, interactionMode: interactionMode, onInteractionModeChange: setInteractionMode, isMobileChrome: isMobileView }), _jsx(AIGenerateModal, { isOpen: isAIModalOpen, onClose: () => setIsAIModalOpen(false), onGenerate: handleAIGenerate, initialContext: {
|
|
1068
|
+
return (_jsx(EditorLayoutProvider, { value: { layoutId: normalizedLayoutType ?? String(layoutId) }, children: _jsxs(AssetSelectionProvider, { onOpenAssets: onOpenAssets, assets: assets, children: [!useInlinePreview ? (_jsx(IframePreviewMessageBridge, { editorContext: previewEditorContext, onRouteChange: handlePreviewRouteChange, onSectionSelected: handlePreviewSectionSelected, onFieldCommit: handlePreviewFieldCommit, onSectionReorder: handleReorderSection, onPreviewElementFocus: handlePreviewElementFocus, onFocusSidebarSection: handlePreviewFocusSidebarSection })) : null, _jsx(ActiveArrayFocusProvider, { sectionKey: selectedSection, focus: activeArrayFocus, onFocusChange: handleActiveArrayFocusChange, onBeforeIndexChange: flushPreviewEdits, children: _jsxs("div", { className: `flex h-full min-h-0 flex-col bg-[#F7F5F0] ${className} font-sans antialiased text-[#1b0029]`, children: [_jsx(EditorHeader, { layoutName: layoutJson.layoutName || layoutId, storeName: storeName, storeLogo: initialData?.branding?.logo, activePage: activePageId, pages: pages, onPageSwitch: setActivePageId, showPageSwitcher: false, showPageContextCard: false, currentPageLabel: currentPageLabel, onSave: handleSave, onPublish: onPublish && hasChangesSincePublish ? handlePublish : undefined, onBack: onBack, onBackToSettings: onBackToSettings, onOpenAssets: onOpenAssets, onBackToTheme: onBackToTheme, onUndo: handleUndo, onRedo: handleRedo, canUndo: historyIndex > 0, canRedo: historyIndex < history.length - 1, viewMode: viewMode, onViewModeChange: setViewMode, previewZoom: previewZoom, onPreviewZoomChange: setPreviewZoom, editorType: "payaza-form", isSaving: isSaving, isPublishing: isPublishing, onGenerateAI: () => setIsAIModalOpen(true), isGeneratingAI: isGeneratingAI, publishButtonText: publishButtonText, centerTemplateLabel: centerTemplateLabel, outlinePanelOpen: isMobileView ? mobilePanelView === 'outline' : outlinePanelOpen, onToggleOutlinePanel: handleToggleOutlinePanel, interactionMode: interactionMode, onInteractionModeChange: setInteractionMode, isMobileChrome: isMobileView }), _jsx(AIGenerateModal, { isOpen: isAIModalOpen, onClose: () => setIsAIModalOpen(false), onGenerate: handleAIGenerate, initialContext: {
|
|
1028
1069
|
storeName: storeName || data?.name || '',
|
|
1029
1070
|
storeDescription: storeDescription || data?.description || '',
|
|
1030
1071
|
assets: assets || [],
|
|
@@ -1070,7 +1111,7 @@ export const PayazaFormEditor = ({ layoutId, initialData, inventory, onChange, o
|
|
|
1070
1111
|
? 'bg-white text-[#440066] shadow-sm'
|
|
1071
1112
|
: 'text-[#5b6470]'}`, children: [_jsx(Pencil, { className: "h-3 w-3", strokeWidth: 2 }), "Edit"] }), _jsxs("button", { type: "button", onClick: () => setInteractionMode('preview'), "aria-pressed": interactionMode === 'preview', "aria-label": "Preview mode", className: `flex h-7 items-center gap-1 rounded-md px-2.5 text-[11px] font-medium transition-colors ${interactionMode === 'preview'
|
|
1072
1113
|
? 'bg-white text-[#440066] shadow-sm'
|
|
1073
|
-
: 'text-[#5b6470]'}`, children: [_jsx(Eye, { className: "h-3 w-3", strokeWidth: 2 }), "Preview"] })] }), _jsxs("div", { className: "flex items-center gap-1.5", children: [_jsx(Smartphone, { className: "h-3.5 w-3.5 text-[#440066]", strokeWidth: 2, "aria-hidden": true }), _jsx("span", { className: "rounded-full bg-[#f3f0f7] px-2.5 py-0.5 text-[10px] font-semibold text-[#440066]", children: "Mobile" })] })] })), _jsxs("div", { className: "relative min-h-0 flex-1 overflow-hidden px-1", children: [_jsx(
|
|
1114
|
+
: 'text-[#5b6470]'}`, children: [_jsx(Eye, { className: "h-3 w-3", strokeWidth: 2 }), "Preview"] })] }), _jsxs("div", { className: "flex items-center gap-1.5", children: [_jsx(Smartphone, { className: "h-3.5 w-3.5 text-[#440066]", strokeWidth: 2, "aria-hidden": true }), _jsx("span", { className: "rounded-full bg-[#f3f0f7] px-2.5 py-0.5 text-[10px] font-semibold text-[#440066]", children: "Mobile" })] })] })), _jsxs("div", { className: "relative min-h-0 flex-1 overflow-hidden px-1", children: [_jsx(EditorCanvasPreview, { layoutId: layoutId, config: debouncedData, activePageId: activePageId, viewMode: viewMode, previewZoom: previewZoom, selectedSection: selectedSection, focusedField: canvasElementFocus, interactionMode: interactionMode, slideIndexSync: slideIndexSync, flushRequestId: flushRequestId, editorContext: previewEditorContext, onRouteChange: handlePreviewRouteChange, onSectionSelected: handlePreviewSectionSelected, onFieldCommit: handlePreviewFieldCommit, onSectionReorder: handleReorderSection, onPreviewElementFocus: handlePreviewElementFocus, onFocusSidebarSection: handlePreviewFocusSidebarSection }), selectedSectionLabel && interactionMode === 'edit' && (_jsx("div", { className: "pointer-events-none absolute bottom-4 left-1/2 z-30 max-w-[min(100%-2rem,360px)] -translate-x-1/2", children: _jsxs("div", { className: "pointer-events-auto flex items-center gap-2 rounded-sm border border-[#dcdcde] bg-white px-2.5 py-1.5 shadow-sm", children: [_jsx(Box, { className: "h-3.5 w-3.5 shrink-0 text-[#1b0029]/45", strokeWidth: 2, "aria-hidden": true }), _jsx("span", { className: "truncate text-[12px] text-[#1b0029]", children: selectedSectionLabel })] }) }))] }), !isMobileView && (_jsxs("div", { className: "flex shrink-0 flex-wrap items-center gap-x-1 gap-y-1 border-t border-[#dcdcde] bg-[#eef0f3] px-3 py-2.5 text-[12px]", style: { contain: 'layout style' }, "aria-label": "Editing context", children: [_jsx("span", { className: "rounded-full border border-[#dcdcde] bg-white px-2 py-0.5 text-[10px] font-semibold uppercase tracking-[0.08em] text-[#646970]", children: "Editing" }), _jsx("span", { className: "truncate font-medium text-[#1b0029]", children: currentPageLabel }), selectedSectionLabel && (_jsxs(_Fragment, { children: [_jsx("span", { className: "text-[#1b0029]/25", "aria-hidden": true, children: "/" }), _jsx("span", { className: "max-w-[min(60vw,280px)] truncate text-[#1b0029]/72", children: selectedSectionLabel })] })), activeSlideBreadcrumbLabel && (_jsxs(_Fragment, { children: [_jsx("span", { className: "text-[#1b0029]/25", "aria-hidden": true, children: "/" }), _jsx("span", { className: "max-w-[min(40vw,160px)] truncate font-medium text-[#440066]", children: activeSlideBreadcrumbLabel })] })), canvasElementFocus?.fieldPath?.length ? (_jsxs(_Fragment, { children: [_jsx("span", { className: "text-[#1b0029]/25", "aria-hidden": true, children: "/" }), _jsx("span", { className: "max-w-[min(72vw,360px)] truncate font-medium text-[#440066]", title: granularBreadcrumbLabel ?? canvasElementFocus.fieldPath.join(' › '), children: granularBreadcrumbLabel ?? canvasElementFocus.fieldPath.join(' › ') })] })) : null, canvasElementFocus?.elementKind && canvasElementFocus.elementKind !== 'section' ? (_jsxs(_Fragment, { children: [_jsx("span", { className: "text-[#1b0029]/25", "aria-hidden": true, children: "/" }), _jsx("span", { className: "truncate text-[11px] text-[#1b0029]/45", children: canvasElementFocus.elementKind === 'richHtml'
|
|
1074
1115
|
? 'Rich text'
|
|
1075
1116
|
: canvasElementFocus.elementKind === 'image'
|
|
1076
1117
|
? 'Image'
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { type PreviewElementFocusPayload } from '../../preview/canvas/preview-messages';
|
|
2
|
+
import type { PayazaInlineFieldCommitPayload } from './IframePreviewMessageBridge';
|
|
3
|
+
export interface PreviewMessageHandlerContext {
|
|
4
|
+
editorContext: {
|
|
5
|
+
layoutId: string;
|
|
6
|
+
activePageId: string;
|
|
7
|
+
};
|
|
8
|
+
onSectionSelected: (sectionKey: string) => void;
|
|
9
|
+
onFieldCommit: (payload: PayazaInlineFieldCommitPayload) => void;
|
|
10
|
+
onSectionReorder: (sectionKey: string, direction: 'up' | 'down') => void;
|
|
11
|
+
onFocusSidebarSection: (sectionKey: string) => void;
|
|
12
|
+
onPreviewElementFocus?: (payload: Omit<PreviewElementFocusPayload, 'type'>) => void;
|
|
13
|
+
onRouteChange?: (route: string) => void;
|
|
14
|
+
onOpenAssetSelect?: (callback: (url: string) => void) => void;
|
|
15
|
+
}
|
|
16
|
+
/** Shared handler for iframe postMessage and inline preview events. */
|
|
17
|
+
export declare function processPreviewMessage(d: Record<string, unknown>, ctx: PreviewMessageHandlerContext): void;
|
|
18
|
+
//# sourceMappingURL=preview-message-handler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"preview-message-handler.d.ts","sourceRoot":"","sources":["../../../src/editor/payaza-form/preview-message-handler.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,0BAA0B,EAEhC,MAAM,uCAAuC,CAAC;AAE/C,OAAO,KAAK,EAAE,8BAA8B,EAAE,MAAM,8BAA8B,CAAC;AAEnF,MAAM,WAAW,4BAA4B;IAC3C,aAAa,EAAE;QACb,QAAQ,EAAE,MAAM,CAAC;QACjB,YAAY,EAAE,MAAM,CAAC;KACtB,CAAC;IACF,iBAAiB,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IAChD,aAAa,EAAE,CAAC,OAAO,EAAE,8BAA8B,KAAK,IAAI,CAAC;IACjE,gBAAgB,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,GAAG,MAAM,KAAK,IAAI,CAAC;IACzE,qBAAqB,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IACpD,qBAAqB,CAAC,EAAE,CAAC,OAAO,EAAE,IAAI,CAAC,0BAA0B,EAAE,MAAM,CAAC,KAAK,IAAI,CAAC;IACpF,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,iBAAiB,CAAC,EAAE,CAAC,QAAQ,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,KAAK,IAAI,CAAC;CAC/D;AAED,uEAAuE;AACvE,wBAAgB,qBAAqB,CACnC,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC1B,GAAG,EAAE,4BAA4B,GAChC,IAAI,CA0GN"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { PREVIEW_MSG, } from '../../preview/canvas/preview-messages.js';
|
|
2
|
+
import { previewCommitsMatchEditorContext } from '../../preview/canvas/preview-isolation.js';
|
|
3
|
+
/** Shared handler for iframe postMessage and inline preview events. */
|
|
4
|
+
export function processPreviewMessage(d, ctx) {
|
|
5
|
+
if (d.type === 'SECTION_SELECTED') {
|
|
6
|
+
const sectionKey = d.section || d.sectionKey;
|
|
7
|
+
if (typeof sectionKey === 'string' && sectionKey) {
|
|
8
|
+
ctx.onSectionSelected(sectionKey);
|
|
9
|
+
}
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
if (d.type === PREVIEW_MSG.ELEMENT_FOCUS) {
|
|
13
|
+
const payload = d;
|
|
14
|
+
const ok = previewCommitsMatchEditorContext({ layoutId: payload.layoutId, pageId: payload.pageId }, { layoutId: ctx.editorContext.layoutId, pageId: ctx.editorContext.activePageId });
|
|
15
|
+
if (!ok)
|
|
16
|
+
return;
|
|
17
|
+
ctx.onPreviewElementFocus?.({
|
|
18
|
+
layoutId: payload.layoutId,
|
|
19
|
+
pageId: payload.pageId,
|
|
20
|
+
sectionKey: payload.sectionKey,
|
|
21
|
+
fieldPath: payload.fieldPath,
|
|
22
|
+
elementKind: payload.elementKind,
|
|
23
|
+
});
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
if (d.type === PREVIEW_MSG.FIELD_COMMIT) {
|
|
27
|
+
const payload = d;
|
|
28
|
+
const ok = previewCommitsMatchEditorContext({ layoutId: payload.layoutId, pageId: payload.pageId }, { layoutId: ctx.editorContext.layoutId, pageId: ctx.editorContext.activePageId });
|
|
29
|
+
if (!ok)
|
|
30
|
+
return;
|
|
31
|
+
ctx.onFieldCommit({
|
|
32
|
+
sectionKey: payload.sectionKey,
|
|
33
|
+
fieldPath: payload.fieldPath,
|
|
34
|
+
valueText: String(payload.value ?? ''),
|
|
35
|
+
richText: payload.richText,
|
|
36
|
+
elementKind: payload.elementKind,
|
|
37
|
+
});
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
if (d.type === PREVIEW_MSG.SECTION_REORDER) {
|
|
41
|
+
const { sectionKey, direction, layoutId, pageId } = d;
|
|
42
|
+
const ok = layoutId &&
|
|
43
|
+
pageId &&
|
|
44
|
+
previewCommitsMatchEditorContext({ layoutId, pageId }, { layoutId: ctx.editorContext.layoutId, pageId: ctx.editorContext.activePageId });
|
|
45
|
+
if (!ok)
|
|
46
|
+
return;
|
|
47
|
+
if (sectionKey && (direction === 'up' || direction === 'down')) {
|
|
48
|
+
ctx.onSectionReorder(sectionKey, direction);
|
|
49
|
+
}
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
if (d.type === PREVIEW_MSG.IMAGE_ACTIVATE) {
|
|
53
|
+
const { sectionKey, fieldPath, layoutId, pageId } = d;
|
|
54
|
+
const ok = layoutId &&
|
|
55
|
+
pageId &&
|
|
56
|
+
previewCommitsMatchEditorContext({ layoutId, pageId }, { layoutId: ctx.editorContext.layoutId, pageId: ctx.editorContext.activePageId });
|
|
57
|
+
if (!ok)
|
|
58
|
+
return;
|
|
59
|
+
if (sectionKey && Array.isArray(fieldPath)) {
|
|
60
|
+
ctx.onOpenAssetSelect?.((url) => {
|
|
61
|
+
ctx.onFieldCommit({
|
|
62
|
+
sectionKey,
|
|
63
|
+
fieldPath,
|
|
64
|
+
valueText: url,
|
|
65
|
+
elementKind: 'image',
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
if (d.type === 'PREVIEW_FOCUS_SIDEBAR') {
|
|
72
|
+
const sk = d.sectionKey;
|
|
73
|
+
if (typeof sk === 'string' && sk) {
|
|
74
|
+
ctx.onFocusSidebarSection(sk);
|
|
75
|
+
}
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
if (d.type === 'ROUTE_CHANGED') {
|
|
79
|
+
const route = d.route;
|
|
80
|
+
if (typeof route === 'string' && route) {
|
|
81
|
+
ctx.onRouteChange?.(route);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { StoreConfig } from '../../lib/store-types';
|
|
3
|
+
import type { InteractionMode } from '../document/types';
|
|
4
|
+
import { type PreviewZoom } from './preview-viewport';
|
|
5
|
+
interface InlineCanvasPreviewProps {
|
|
6
|
+
layoutId: string;
|
|
7
|
+
config: StoreConfig;
|
|
8
|
+
activePageId: string;
|
|
9
|
+
viewMode: 'desktop' | 'tablet' | 'mobile';
|
|
10
|
+
selectedSection?: string | null;
|
|
11
|
+
focusedField?: {
|
|
12
|
+
sectionKey: string;
|
|
13
|
+
fieldPath: string[];
|
|
14
|
+
elementKind: string;
|
|
15
|
+
} | null;
|
|
16
|
+
interactionMode?: InteractionMode;
|
|
17
|
+
slideIndexSync?: {
|
|
18
|
+
sectionKey: string;
|
|
19
|
+
arrayField: string;
|
|
20
|
+
index: number;
|
|
21
|
+
} | null;
|
|
22
|
+
flushRequestId?: number;
|
|
23
|
+
previewZoom?: PreviewZoom;
|
|
24
|
+
desktopCanvasWidth?: number;
|
|
25
|
+
className?: string;
|
|
26
|
+
onPreviewEvent?: (payload: object) => void;
|
|
27
|
+
onReady?: () => void;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Same-document layout preview for mobile editors — avoids iframe memory overhead on WebKit.
|
|
31
|
+
*/
|
|
32
|
+
export declare const InlineCanvasPreview: React.FC<InlineCanvasPreviewProps>;
|
|
33
|
+
export {};
|
|
34
|
+
//# sourceMappingURL=InlineCanvasPreview.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"InlineCanvasPreview.d.ts","sourceRoot":"","sources":["../../../src/editor/shared/InlineCanvasPreview.tsx"],"names":[],"mappings":"AAEA,OAAO,KAA+C,MAAM,OAAO,CAAC;AACpE,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAOpD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,EAEL,KAAK,WAAW,EAEjB,MAAM,oBAAoB,CAAC;AAE5B,UAAU,wBAAwB;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,WAAW,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,SAAS,GAAG,QAAQ,GAAG,QAAQ,CAAC;IAC1C,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,YAAY,CAAC,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,EAAE,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IACvF,eAAe,CAAC,EAAE,eAAe,CAAC;IAClC,cAAc,CAAC,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAClF,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAC3C,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB;AAED;;GAEG;AACH,eAAO,MAAM,mBAAmB,EAAE,KAAK,CAAC,EAAE,CAAC,wBAAwB,CAkNlE,CAAC"}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useEffect, useMemo, useRef, useState } from 'react';
|
|
4
|
+
import { LayoutPreview } from '../../preview/LayoutPreview.js';
|
|
5
|
+
import { PreviewCanvasEnhancer } from '../../preview/canvas/PreviewCanvasEnhancer.js';
|
|
6
|
+
import { PreviewCanvasStyles } from '../../preview/canvas/PreviewCanvasStyles.js';
|
|
7
|
+
import { previewPageIdToRoute } from '../../preview/canvas/preview-route.js';
|
|
8
|
+
import { PREVIEW_MSG } from '../../preview/canvas/preview-messages.js';
|
|
9
|
+
import { normalizeEditorLayoutId } from '../document/layout-id.js';
|
|
10
|
+
import { DESKTOP_PREVIEW_WIDTH, resolvePreviewScale, } from './preview-viewport.js';
|
|
11
|
+
/**
|
|
12
|
+
* Same-document layout preview for mobile editors — avoids iframe memory overhead on WebKit.
|
|
13
|
+
*/
|
|
14
|
+
export const InlineCanvasPreview = ({ layoutId, config, activePageId, viewMode, selectedSection, focusedField = null, interactionMode = 'edit', slideIndexSync = null, flushRequestId = 0, previewZoom = 'fit', desktopCanvasWidth = DESKTOP_PREVIEW_WIDTH, className = '', onPreviewEvent, onReady, }) => {
|
|
15
|
+
const viewportContainerRef = useRef(null);
|
|
16
|
+
const [containerWidth, setContainerWidth] = useState(0);
|
|
17
|
+
const [currentRoute, setCurrentRoute] = useState('/');
|
|
18
|
+
const readyFiredRef = useRef(false);
|
|
19
|
+
const canonicalLayoutId = useMemo(() => normalizeEditorLayoutId(String(layoutId)) ?? String(layoutId), [layoutId]);
|
|
20
|
+
const route = useMemo(() => previewPageIdToRoute(layoutId, activePageId, config), [layoutId, activePageId, config]);
|
|
21
|
+
useEffect(() => {
|
|
22
|
+
setCurrentRoute(route);
|
|
23
|
+
}, [route]);
|
|
24
|
+
const previewContext = useMemo(() => ({
|
|
25
|
+
layoutId: canonicalLayoutId,
|
|
26
|
+
pageId: activePageId,
|
|
27
|
+
}), [canonicalLayoutId, activePageId]);
|
|
28
|
+
const previewData = useMemo(() => {
|
|
29
|
+
const base = {
|
|
30
|
+
...config,
|
|
31
|
+
isPreview: true,
|
|
32
|
+
headerConfig: {
|
|
33
|
+
...config.headerConfig,
|
|
34
|
+
show: config.headerConfig?.show ?? true,
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
if (typeof window !== 'undefined') {
|
|
38
|
+
window.__IS_PREVIEW__ = true;
|
|
39
|
+
}
|
|
40
|
+
return base;
|
|
41
|
+
}, [config]);
|
|
42
|
+
useEffect(() => {
|
|
43
|
+
if (readyFiredRef.current)
|
|
44
|
+
return;
|
|
45
|
+
readyFiredRef.current = true;
|
|
46
|
+
onReady?.();
|
|
47
|
+
}, [onReady]);
|
|
48
|
+
const lastPostedFocusRef = useRef(null);
|
|
49
|
+
useEffect(() => {
|
|
50
|
+
const key = focusedField
|
|
51
|
+
? `${focusedField.sectionKey}|${focusedField.fieldPath.join('|')}|${focusedField.elementKind}`
|
|
52
|
+
: null;
|
|
53
|
+
if (lastPostedFocusRef.current === key)
|
|
54
|
+
return;
|
|
55
|
+
lastPostedFocusRef.current = key;
|
|
56
|
+
window.postMessage({ type: PREVIEW_MSG.FIELD_SELECTED_SYNC, field: focusedField }, '*');
|
|
57
|
+
}, [focusedField]);
|
|
58
|
+
useEffect(() => {
|
|
59
|
+
window.postMessage({ type: 'SECTION_SELECTED_SYNC', section: selectedSection ?? null }, '*');
|
|
60
|
+
}, [selectedSection]);
|
|
61
|
+
const lastPostedSlideSyncRef = useRef(null);
|
|
62
|
+
useEffect(() => {
|
|
63
|
+
const key = slideIndexSync
|
|
64
|
+
? `${slideIndexSync.sectionKey}|${slideIndexSync.arrayField}|${slideIndexSync.index}`
|
|
65
|
+
: null;
|
|
66
|
+
if (lastPostedSlideSyncRef.current === key)
|
|
67
|
+
return;
|
|
68
|
+
lastPostedSlideSyncRef.current = key;
|
|
69
|
+
if (!slideIndexSync)
|
|
70
|
+
return;
|
|
71
|
+
const payload = {
|
|
72
|
+
type: PREVIEW_MSG.SLIDE_INDEX_SYNC,
|
|
73
|
+
sectionKey: slideIndexSync.sectionKey,
|
|
74
|
+
arrayField: slideIndexSync.arrayField,
|
|
75
|
+
index: slideIndexSync.index,
|
|
76
|
+
};
|
|
77
|
+
window.postMessage(payload, '*');
|
|
78
|
+
}, [slideIndexSync]);
|
|
79
|
+
const lastFlushRef = useRef(0);
|
|
80
|
+
useEffect(() => {
|
|
81
|
+
if (flushRequestId <= 0)
|
|
82
|
+
return;
|
|
83
|
+
if (lastFlushRef.current === flushRequestId)
|
|
84
|
+
return;
|
|
85
|
+
lastFlushRef.current = flushRequestId;
|
|
86
|
+
window.postMessage({ type: PREVIEW_MSG.FLUSH_EDITS }, '*');
|
|
87
|
+
}, [flushRequestId]);
|
|
88
|
+
useEffect(() => {
|
|
89
|
+
if (viewMode !== 'desktop')
|
|
90
|
+
return;
|
|
91
|
+
const el = viewportContainerRef.current;
|
|
92
|
+
if (!el)
|
|
93
|
+
return;
|
|
94
|
+
const updateWidth = () => setContainerWidth(el.clientWidth);
|
|
95
|
+
updateWidth();
|
|
96
|
+
const observer = new ResizeObserver(updateWidth);
|
|
97
|
+
observer.observe(el);
|
|
98
|
+
return () => observer.disconnect();
|
|
99
|
+
}, [viewMode]);
|
|
100
|
+
const desktopScale = useMemo(() => {
|
|
101
|
+
if (viewMode !== 'desktop')
|
|
102
|
+
return 1;
|
|
103
|
+
return resolvePreviewScale(previewZoom, containerWidth, desktopCanvasWidth);
|
|
104
|
+
}, [viewMode, previewZoom, containerWidth, desktopCanvasWidth]);
|
|
105
|
+
const scaledDesktopHeight = useMemo(() => {
|
|
106
|
+
if (viewMode !== 'desktop')
|
|
107
|
+
return 900;
|
|
108
|
+
const parent = viewportContainerRef.current?.parentElement;
|
|
109
|
+
const availableHeight = parent?.clientHeight ?? 0;
|
|
110
|
+
if (availableHeight <= 0)
|
|
111
|
+
return 900;
|
|
112
|
+
return Math.max(480, availableHeight / Math.max(desktopScale, 0.01));
|
|
113
|
+
}, [viewMode, desktopScale]);
|
|
114
|
+
const deviceDimensions = useMemo(() => {
|
|
115
|
+
switch (viewMode) {
|
|
116
|
+
case 'mobile':
|
|
117
|
+
return { width: 390, height: 844, rounded: 'rounded-[3.5rem]', border: 'border-[14px]' };
|
|
118
|
+
case 'tablet':
|
|
119
|
+
return { width: 768, height: 1024, rounded: 'rounded-2xl', border: 'border-[8px]' };
|
|
120
|
+
case 'desktop':
|
|
121
|
+
default:
|
|
122
|
+
return { width: '100%', height: '100%', rounded: '', border: '' };
|
|
123
|
+
}
|
|
124
|
+
}, [viewMode]);
|
|
125
|
+
const previewNode = (_jsx(PreviewCanvasEnhancer, { enabled: true, interactionMode: interactionMode, previewContext: previewContext, onPreviewEvent: onPreviewEvent, children: _jsx(LayoutPreview, { layout: layoutId, config: previewData, interactive: true, initialRoute: currentRoute, onRouteChange: (nextRoute) => {
|
|
126
|
+
setCurrentRoute(nextRoute);
|
|
127
|
+
onPreviewEvent?.({ type: 'ROUTE_CHANGED', route: nextRoute });
|
|
128
|
+
} }) }));
|
|
129
|
+
const chrome = (_jsxs(_Fragment, { children: [_jsx(PreviewCanvasStyles, {}), previewNode] }));
|
|
130
|
+
if (viewMode === 'desktop') {
|
|
131
|
+
return (_jsx("div", { ref: viewportContainerRef, className: `relative h-full w-full overflow-auto bg-[#e2e4e7] p-3 md:p-4 ${className}`, style: { WebkitOverflowScrolling: 'touch' }, children: _jsx("div", { className: "flex min-h-full justify-center py-1", children: _jsx("div", { className: "shrink-0 overflow-hidden rounded-lg bg-white shadow-[0_1px_2px_rgba(15,23,42,0.04),0_12px_32px_-8px_rgba(15,23,42,0.1)] transition-transform duration-200 ease-out", style: {
|
|
132
|
+
width: desktopCanvasWidth,
|
|
133
|
+
height: scaledDesktopHeight,
|
|
134
|
+
minHeight: 480,
|
|
135
|
+
transform: `scale(${desktopScale})`,
|
|
136
|
+
transformOrigin: 'top center',
|
|
137
|
+
}, children: _jsx("div", { className: "relative h-full w-full overflow-hidden rounded-lg", children: chrome }) }) }) }));
|
|
138
|
+
}
|
|
139
|
+
return (_jsx("div", { className: `relative flex h-full w-full items-start justify-center bg-[#dcdcde] p-2 ${className}`, children: _jsx("div", { className: `flex flex-col overflow-hidden bg-white shadow-2xl transition-all duration-500 ease-in-out ${deviceDimensions.rounded} ${deviceDimensions.border} border-[#c3c4c7]`, style: {
|
|
140
|
+
width: `${deviceDimensions.width}px`,
|
|
141
|
+
height: `${deviceDimensions.height}px`,
|
|
142
|
+
maxWidth: '100%',
|
|
143
|
+
maxHeight: '100%',
|
|
144
|
+
}, children: _jsx("div", { className: "relative min-h-0 flex-1 overflow-hidden bg-white", children: chrome }) }) }));
|
|
145
|
+
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/editor/shared/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,mBAAmB,CAAC;AAClC,cAAc,iBAAiB,CAAC;AAChC,cAAc,kBAAkB,CAAC;AACjC,cAAc,YAAY,CAAC;AAC3B,cAAc,oBAAoB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/editor/shared/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,mBAAmB,CAAC;AAClC,cAAc,iBAAiB,CAAC;AAChC,cAAc,uBAAuB,CAAC;AACtC,cAAc,kBAAkB,CAAC;AACjC,cAAc,YAAY,CAAC;AAC3B,cAAc,oBAAoB,CAAC"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export * from './EditorHeader.js';
|
|
2
2
|
export * from './EditorNavigator.js';
|
|
3
3
|
export * from './IframePreview.js';
|
|
4
|
+
export * from './InlineCanvasPreview.js';
|
|
4
5
|
export * from './LayoutRenderer.js';
|
|
5
6
|
export * from './PageTabs.js';
|
|
6
7
|
export * from './ResizableSidebar.js';
|
|
@@ -3,4 +3,6 @@
|
|
|
3
3
|
* Real phones stay in mobile mode in landscape — viewport width alone is unreliable (e.g. iPhone ~844px wide).
|
|
4
4
|
*/
|
|
5
5
|
export declare function isMobileEditorViewport(): boolean;
|
|
6
|
+
/** Inline same-document preview — avoids iframe double-runtime on mobile WebKit. */
|
|
7
|
+
export declare function shouldUseInlineEditorPreview(): boolean;
|
|
6
8
|
//# sourceMappingURL=mobile-editor.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mobile-editor.d.ts","sourceRoot":"","sources":["../../../src/lib/utils/mobile-editor.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,wBAAgB,sBAAsB,IAAI,OAAO,CAUhD"}
|
|
1
|
+
{"version":3,"file":"mobile-editor.d.ts","sourceRoot":"","sources":["../../../src/lib/utils/mobile-editor.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,wBAAgB,sBAAsB,IAAI,OAAO,CAUhD;AAED,oFAAoF;AACpF,wBAAgB,4BAA4B,IAAI,OAAO,CAEtD"}
|
|
@@ -5,6 +5,8 @@ export interface PreviewCanvasEnhancerProps {
|
|
|
5
5
|
interactionMode: 'edit' | 'preview';
|
|
6
6
|
children: React.ReactNode;
|
|
7
7
|
previewContext?: PayazaPreviewContext | null;
|
|
8
|
+
/** When set (inline mobile preview), dispatch events directly instead of postMessage to parent. */
|
|
9
|
+
onPreviewEvent?: (payload: object) => void;
|
|
8
10
|
}
|
|
9
|
-
export declare function PreviewCanvasEnhancer({ enabled, interactionMode, children, previewContext, }: PreviewCanvasEnhancerProps): React.JSX.Element;
|
|
11
|
+
export declare function PreviewCanvasEnhancer({ enabled, interactionMode, children, previewContext, onPreviewEvent, }: PreviewCanvasEnhancerProps): React.JSX.Element;
|
|
10
12
|
//# sourceMappingURL=PreviewCanvasEnhancer.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PreviewCanvasEnhancer.d.ts","sourceRoot":"","sources":["../../../src/preview/canvas/PreviewCanvasEnhancer.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAmD,MAAM,OAAO,CAAC;AAIxE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAShE,MAAM,WAAW,0BAA0B;IACzC,OAAO,EAAE,OAAO,CAAC;IACjB,eAAe,EAAE,MAAM,GAAG,SAAS,CAAC;IACpC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,cAAc,CAAC,EAAE,oBAAoB,GAAG,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"PreviewCanvasEnhancer.d.ts","sourceRoot":"","sources":["../../../src/preview/canvas/PreviewCanvasEnhancer.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAmD,MAAM,OAAO,CAAC;AAIxE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAShE,MAAM,WAAW,0BAA0B;IACzC,OAAO,EAAE,OAAO,CAAC;IACjB,eAAe,EAAE,MAAM,GAAG,SAAS,CAAC;IACpC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,cAAc,CAAC,EAAE,oBAAoB,GAAG,IAAI,CAAC;IAC7C,mGAAmG;IACnG,cAAc,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CAC5C;AAeD,wBAAgB,qBAAqB,CAAC,EACpC,OAAO,EACP,eAAe,EACf,QAAQ,EACR,cAAqB,EACrB,cAAc,GACf,EAAE,0BAA0B,qBAstB5B"}
|
|
@@ -18,7 +18,7 @@ function postToParent(payload) {
|
|
|
18
18
|
window.parent.postMessage(payload, '*');
|
|
19
19
|
}
|
|
20
20
|
}
|
|
21
|
-
export function PreviewCanvasEnhancer({ enabled, interactionMode, children, previewContext = null, }) {
|
|
21
|
+
export function PreviewCanvasEnhancer({ enabled, interactionMode, children, previewContext = null, onPreviewEvent, }) {
|
|
22
22
|
const [toolbarVisible, setToolbarVisible] = useState(false);
|
|
23
23
|
const [toolbarRect, setToolbarRect] = useState(null);
|
|
24
24
|
const [toolbarMode, setToolbarMode] = useState('text');
|
|
@@ -36,6 +36,14 @@ export function PreviewCanvasEnhancer({ enabled, interactionMode, children, prev
|
|
|
36
36
|
next;
|
|
37
37
|
}
|
|
38
38
|
}, [previewContext]);
|
|
39
|
+
const dispatchPreviewEvent = useCallback((payload) => {
|
|
40
|
+
if (onPreviewEvent) {
|
|
41
|
+
onPreviewEvent(payload);
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
postToParent(payload);
|
|
45
|
+
}
|
|
46
|
+
}, [onPreviewEvent]);
|
|
39
47
|
const resolveCtx = useCallback(() => {
|
|
40
48
|
if (previewCtxRef.current?.layoutId && previewCtxRef.current.pageId)
|
|
41
49
|
return previewCtxRef.current;
|
|
@@ -84,7 +92,7 @@ export function PreviewCanvasEnhancer({ enabled, interactionMode, children, prev
|
|
|
84
92
|
const ctx = resolveCtx();
|
|
85
93
|
if (!ctx)
|
|
86
94
|
return;
|
|
87
|
-
|
|
95
|
+
dispatchPreviewEvent({
|
|
88
96
|
type: PREVIEW_MSG.ELEMENT_FOCUS,
|
|
89
97
|
layoutId: ctx.layoutId,
|
|
90
98
|
pageId: ctx.pageId,
|
|
@@ -113,7 +121,7 @@ export function PreviewCanvasEnhancer({ enabled, interactionMode, children, prev
|
|
|
113
121
|
setToolbarEditableActive(false);
|
|
114
122
|
if (rich) {
|
|
115
123
|
const payload = buildPayazaRichCommitFromEditorHtml(inner, { keepRaw: true });
|
|
116
|
-
|
|
124
|
+
dispatchPreviewEvent({
|
|
117
125
|
type: PREVIEW_MSG.FIELD_COMMIT,
|
|
118
126
|
layoutId: ctx.layoutId,
|
|
119
127
|
pageId: ctx.pageId,
|
|
@@ -126,7 +134,7 @@ export function PreviewCanvasEnhancer({ enabled, interactionMode, children, prev
|
|
|
126
134
|
return;
|
|
127
135
|
}
|
|
128
136
|
const value = extractEditablePlainText(t);
|
|
129
|
-
|
|
137
|
+
dispatchPreviewEvent({
|
|
130
138
|
type: PREVIEW_MSG.FIELD_COMMIT,
|
|
131
139
|
layoutId: ctx.layoutId,
|
|
132
140
|
pageId: ctx.pageId,
|
|
@@ -213,12 +221,12 @@ export function PreviewCanvasEnhancer({ enabled, interactionMode, children, prev
|
|
|
213
221
|
const parsedIcon = iconKey ? parsePayazaFieldKey(iconKey) : null;
|
|
214
222
|
if (parsedIcon && ctx) {
|
|
215
223
|
postElementFocus(parsedIcon.sectionKey, parsedIcon.fieldPath, 'icon');
|
|
216
|
-
|
|
224
|
+
dispatchPreviewEvent({ type: 'SECTION_SELECTED', section: parsedIcon.sectionKey, sectionKey: parsedIcon.sectionKey });
|
|
217
225
|
}
|
|
218
226
|
else {
|
|
219
227
|
const iconSk = schemaSectionKeyFromElement(iconEl);
|
|
220
228
|
if (iconSk)
|
|
221
|
-
|
|
229
|
+
dispatchPreviewEvent({ type: 'SECTION_SELECTED', section: iconSk, sectionKey: iconSk });
|
|
222
230
|
}
|
|
223
231
|
return;
|
|
224
232
|
}
|
|
@@ -240,7 +248,7 @@ export function PreviewCanvasEnhancer({ enabled, interactionMode, children, prev
|
|
|
240
248
|
const parsedRating = ratingKey ? parsePayazaFieldKey(ratingKey) : null;
|
|
241
249
|
const ratingSk = schemaSectionKeyFromElement(ratingEl);
|
|
242
250
|
if (ratingSk) {
|
|
243
|
-
|
|
251
|
+
dispatchPreviewEvent({ type: 'SECTION_SELECTED', section: ratingSk, sectionKey: ratingSk });
|
|
244
252
|
}
|
|
245
253
|
if (parsedRating && ctx) {
|
|
246
254
|
postElementFocus(parsedRating.sectionKey, parsedRating.fieldPath, 'rating');
|
|
@@ -248,7 +256,7 @@ export function PreviewCanvasEnhancer({ enabled, interactionMode, children, prev
|
|
|
248
256
|
? Number(ratingStarEl.getAttribute('data-payaza-rating-star'))
|
|
249
257
|
: NaN;
|
|
250
258
|
if (Number.isFinite(starValue) && starValue >= 1 && starValue <= 5) {
|
|
251
|
-
|
|
259
|
+
dispatchPreviewEvent({
|
|
252
260
|
type: PREVIEW_MSG.FIELD_COMMIT,
|
|
253
261
|
layoutId: ctx.layoutId,
|
|
254
262
|
pageId: ctx.pageId,
|
|
@@ -283,7 +291,7 @@ export function PreviewCanvasEnhancer({ enabled, interactionMode, children, prev
|
|
|
283
291
|
setToolbarVisible(true);
|
|
284
292
|
const imgSk = schemaSectionKeyFromElement(imgEl);
|
|
285
293
|
if (imgSk)
|
|
286
|
-
|
|
294
|
+
dispatchPreviewEvent({ type: 'SECTION_SELECTED', section: imgSk, sectionKey: imgSk });
|
|
287
295
|
return;
|
|
288
296
|
}
|
|
289
297
|
if (textEl) {
|
|
@@ -303,7 +311,7 @@ export function PreviewCanvasEnhancer({ enabled, interactionMode, children, prev
|
|
|
303
311
|
const parsed = key ? parsePayazaFieldKey(key) : null;
|
|
304
312
|
const sk = schemaSectionKeyFromElement(textEl);
|
|
305
313
|
if (sk)
|
|
306
|
-
|
|
314
|
+
dispatchPreviewEvent({ type: 'SECTION_SELECTED', section: sk, sectionKey: sk });
|
|
307
315
|
if (parsed && ctx) {
|
|
308
316
|
postElementFocus(parsed.sectionKey, parsed.fieldPath, richFmt ? 'richHtml' : 'plainText');
|
|
309
317
|
}
|
|
@@ -330,12 +338,12 @@ export function PreviewCanvasEnhancer({ enabled, interactionMode, children, prev
|
|
|
330
338
|
const parsedGroup = groupKey ? parsePayazaFieldKey(groupKey) : null;
|
|
331
339
|
if (parsedGroup && ctx) {
|
|
332
340
|
postElementFocus(parsedGroup.sectionKey, parsedGroup.fieldPath, 'group');
|
|
333
|
-
|
|
341
|
+
dispatchPreviewEvent({ type: 'SECTION_SELECTED', section: parsedGroup.sectionKey, sectionKey: parsedGroup.sectionKey });
|
|
334
342
|
}
|
|
335
343
|
else {
|
|
336
344
|
const gs = schemaSectionKeyFromElement(groupEl);
|
|
337
345
|
if (gs)
|
|
338
|
-
|
|
346
|
+
dispatchPreviewEvent({ type: 'SECTION_SELECTED', section: gs, sectionKey: gs });
|
|
339
347
|
}
|
|
340
348
|
return;
|
|
341
349
|
}
|
|
@@ -353,7 +361,7 @@ export function PreviewCanvasEnhancer({ enabled, interactionMode, children, prev
|
|
|
353
361
|
setToolbarVisible(true);
|
|
354
362
|
const ss = schemaSectionKeyFromElement(sectionEl);
|
|
355
363
|
if (ss) {
|
|
356
|
-
|
|
364
|
+
dispatchPreviewEvent({ type: 'SECTION_SELECTED', section: ss, sectionKey: ss });
|
|
357
365
|
if (ctx)
|
|
358
366
|
postElementFocus(ss, [], 'section');
|
|
359
367
|
}
|
|
@@ -454,7 +462,7 @@ export function PreviewCanvasEnhancer({ enabled, interactionMode, children, prev
|
|
|
454
462
|
const sk = schemaSectionKeyFromElement(selectedElRef.current);
|
|
455
463
|
if (!sk)
|
|
456
464
|
return;
|
|
457
|
-
|
|
465
|
+
dispatchPreviewEvent({
|
|
458
466
|
type: PREVIEW_MSG.SECTION_REORDER,
|
|
459
467
|
layoutId: ctx.layoutId,
|
|
460
468
|
pageId: ctx.pageId,
|
|
@@ -469,7 +477,7 @@ export function PreviewCanvasEnhancer({ enabled, interactionMode, children, prev
|
|
|
469
477
|
const sk = schemaSectionKeyFromElement(selectedElRef.current);
|
|
470
478
|
if (!sk)
|
|
471
479
|
return;
|
|
472
|
-
|
|
480
|
+
dispatchPreviewEvent({
|
|
473
481
|
type: PREVIEW_MSG.SECTION_REORDER,
|
|
474
482
|
layoutId: ctx.layoutId,
|
|
475
483
|
pageId: ctx.pageId,
|
|
@@ -482,7 +490,7 @@ export function PreviewCanvasEnhancer({ enabled, interactionMode, children, prev
|
|
|
482
490
|
if (!imageFieldRef.current || !ctx?.layoutId)
|
|
483
491
|
return;
|
|
484
492
|
const { sectionKey, fieldPath } = imageFieldRef.current;
|
|
485
|
-
|
|
493
|
+
dispatchPreviewEvent({
|
|
486
494
|
type: PREVIEW_MSG.IMAGE_ACTIVATE,
|
|
487
495
|
layoutId: ctx.layoutId,
|
|
488
496
|
pageId: ctx.pageId,
|
|
@@ -492,10 +500,10 @@ export function PreviewCanvasEnhancer({ enabled, interactionMode, children, prev
|
|
|
492
500
|
}, [resolveCtx]);
|
|
493
501
|
const onMore = useCallback(() => {
|
|
494
502
|
const sk = schemaSectionKeyFromElement(selectedElRef.current);
|
|
495
|
-
if (sk
|
|
496
|
-
|
|
503
|
+
if (sk) {
|
|
504
|
+
dispatchPreviewEvent({ type: 'PREVIEW_FOCUS_SIDEBAR', sectionKey: sk });
|
|
497
505
|
}
|
|
498
|
-
}, []);
|
|
506
|
+
}, [dispatchPreviewEvent]);
|
|
499
507
|
// Sync canvas selection when List View clicks a section or block element.
|
|
500
508
|
// Refs and setState setters are stable so empty deps is correct.
|
|
501
509
|
useEffect(() => {
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
/** Section highlight styles shared by iframe preview and inline mobile canvas. */
|
|
2
|
+
export declare const PREVIEW_CANVAS_STYLES = "\n [data-section] {\n position: relative;\n cursor: pointer !important;\n }\n [data-section-hover=\"true\"]:not([data-section-selected=\"true\"])::after {\n content: '';\n position: absolute;\n inset: 0;\n border: 1px dashed rgba(68, 0, 102, 0.35);\n pointer-events: none;\n z-index: 50;\n background: rgba(68, 0, 102, 0.02);\n border-radius: 2px;\n }\n [data-section-selected=\"true\"]::after {\n content: '';\n position: absolute;\n inset: 0;\n border: 1px solid #3858e9;\n pointer-events: none;\n z-index: 51;\n background: rgba(56, 88, 233, 0.04);\n box-shadow: inset 0 0 0 1px rgba(56, 88, 233, 0.12);\n border-radius: 2px;\n }\n [data-section-selected=\"true\"]::before {\n content: attr(data-section);\n position: absolute;\n top: -24px;\n left: 0;\n background: #1e1e1e;\n color: #f0f0f0;\n font-size: 11px;\n font-weight: 600;\n padding: 2px 8px;\n border-radius: 2px;\n text-transform: none;\n z-index: 52;\n max-width: 200px;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n";
|
|
3
|
+
export declare function PreviewCanvasStyles(): import("react").JSX.Element;
|
|
4
|
+
//# sourceMappingURL=PreviewCanvasStyles.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PreviewCanvasStyles.d.ts","sourceRoot":"","sources":["../../../src/preview/canvas/PreviewCanvasStyles.tsx"],"names":[],"mappings":"AAEA,kFAAkF;AAClF,eAAO,MAAM,qBAAqB,0mCA4CjC,CAAC;AAEF,wBAAgB,mBAAmB,gCAElC"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
/** Section highlight styles shared by iframe preview and inline mobile canvas. */
|
|
4
|
+
export const PREVIEW_CANVAS_STYLES = `
|
|
5
|
+
[data-section] {
|
|
6
|
+
position: relative;
|
|
7
|
+
cursor: pointer !important;
|
|
8
|
+
}
|
|
9
|
+
[data-section-hover="true"]:not([data-section-selected="true"])::after {
|
|
10
|
+
content: '';
|
|
11
|
+
position: absolute;
|
|
12
|
+
inset: 0;
|
|
13
|
+
border: 1px dashed rgba(68, 0, 102, 0.35);
|
|
14
|
+
pointer-events: none;
|
|
15
|
+
z-index: 50;
|
|
16
|
+
background: rgba(68, 0, 102, 0.02);
|
|
17
|
+
border-radius: 2px;
|
|
18
|
+
}
|
|
19
|
+
[data-section-selected="true"]::after {
|
|
20
|
+
content: '';
|
|
21
|
+
position: absolute;
|
|
22
|
+
inset: 0;
|
|
23
|
+
border: 1px solid #3858e9;
|
|
24
|
+
pointer-events: none;
|
|
25
|
+
z-index: 51;
|
|
26
|
+
background: rgba(56, 88, 233, 0.04);
|
|
27
|
+
box-shadow: inset 0 0 0 1px rgba(56, 88, 233, 0.12);
|
|
28
|
+
border-radius: 2px;
|
|
29
|
+
}
|
|
30
|
+
[data-section-selected="true"]::before {
|
|
31
|
+
content: attr(data-section);
|
|
32
|
+
position: absolute;
|
|
33
|
+
top: -24px;
|
|
34
|
+
left: 0;
|
|
35
|
+
background: #1e1e1e;
|
|
36
|
+
color: #f0f0f0;
|
|
37
|
+
font-size: 11px;
|
|
38
|
+
font-weight: 600;
|
|
39
|
+
padding: 2px 8px;
|
|
40
|
+
border-radius: 2px;
|
|
41
|
+
text-transform: none;
|
|
42
|
+
z-index: 52;
|
|
43
|
+
max-width: 200px;
|
|
44
|
+
overflow: hidden;
|
|
45
|
+
text-overflow: ellipsis;
|
|
46
|
+
white-space: nowrap;
|
|
47
|
+
}
|
|
48
|
+
`;
|
|
49
|
+
export function PreviewCanvasStyles() {
|
|
50
|
+
return _jsx("style", { dangerouslySetInnerHTML: { __html: PREVIEW_CANVAS_STYLES } });
|
|
51
|
+
}
|