cms-renderer 0.6.12 → 0.6.13
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/lib/block-renderer.d.ts +16 -12
- package/dist/lib/block-renderer.js +64 -1
- package/dist/lib/block-renderer.js.map +1 -1
- package/dist/lib/custom-schemas.js.map +1 -1
- package/dist/lib/docs-markdown.d.ts +2 -2
- package/dist/lib/parametric-route.d.ts +15 -2
- package/dist/lib/parametric-route.js +94 -6
- package/dist/lib/parametric-route.js.map +1 -1
- package/dist/lib/renderer.d.ts +12 -3
- package/dist/lib/renderer.js +105 -6
- package/dist/lib/renderer.js.map +1 -1
- package/package.json +4 -4
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import * as
|
|
1
|
+
import * as react from 'react';
|
|
2
2
|
import { ReactNode } from 'react';
|
|
3
3
|
|
|
4
4
|
interface DocsMarkdownProps {
|
|
@@ -13,6 +13,6 @@ interface DocsMarkdownProps {
|
|
|
13
13
|
}
|
|
14
14
|
declare function markdownStartsWithHeading(markdown: string): boolean;
|
|
15
15
|
declare function initMarkdown(): Promise<void>;
|
|
16
|
-
declare function DocsMarkdown({ content, className, renderImage, }: DocsMarkdownProps): Promise<
|
|
16
|
+
declare function DocsMarkdown({ content, className, renderImage, }: DocsMarkdownProps): Promise<react.JSX.Element>;
|
|
17
17
|
|
|
18
18
|
export { DocsMarkdown, type DocsMarkdownProps, initMarkdown, markdownStartsWithHeading };
|
|
@@ -25,6 +25,19 @@ type ParametricRouteProps = CmsConfig & {
|
|
|
25
25
|
};
|
|
26
26
|
registry?: Partial<BlockComponentRegistry>;
|
|
27
27
|
};
|
|
28
|
+
/**
|
|
29
|
+
* Render-time options that are NOT part of the page props surface. `preview` is
|
|
30
|
+
* supplied only by the dedicated preview page wrapper (`ParametricRoutePreviewPage`),
|
|
31
|
+
* never by query params, so the production page can never accidentally opt into
|
|
32
|
+
* edit overlays or draft content.
|
|
33
|
+
*/
|
|
34
|
+
type RenderParametricRouteOptions = {
|
|
35
|
+
/**
|
|
36
|
+
* Renders the preview experience: forces the edit-mode overlay/hovers and pulls
|
|
37
|
+
* block content from `draft_content` instead of `published_content`.
|
|
38
|
+
*/
|
|
39
|
+
preview?: boolean;
|
|
40
|
+
};
|
|
28
41
|
type ParametricRouteResult = {
|
|
29
42
|
status: 'ok';
|
|
30
43
|
node: ReactNode;
|
|
@@ -40,6 +53,6 @@ declare function getWebsiteId(providedWebsiteId?: string): string;
|
|
|
40
53
|
* Renders CMS-backed blocks for a multi-segment path. Maps NOT_FOUND-style API
|
|
41
54
|
* outcomes to `{ status: 'not_found' }` instead of throwing.
|
|
42
55
|
*/
|
|
43
|
-
declare function renderParametricRoute({ params, searchParams, registry, apiKey, cmsUrl, websiteId: providedWebsiteId, }: ParametricRouteProps): Promise<ParametricRouteResult>;
|
|
56
|
+
declare function renderParametricRoute({ params, searchParams, registry, apiKey, cmsUrl, websiteId: providedWebsiteId, }: ParametricRouteProps, { preview }?: RenderParametricRouteOptions): Promise<ParametricRouteResult>;
|
|
44
57
|
|
|
45
|
-
export { type ParametricRouteProps, type ParametricRouteResult, getWebsiteId, renderParametricRoute };
|
|
58
|
+
export { type ParametricRouteProps, type ParametricRouteResult, type RenderParametricRouteOptions, getWebsiteId, renderParametricRoute };
|
|
@@ -414,7 +414,7 @@ function generateCmsOverlayScript(cmsParentOrigin) {
|
|
|
414
414
|
pointer-events: none;
|
|
415
415
|
z-index: 99998;
|
|
416
416
|
}
|
|
417
|
-
#cms-overlay-root >
|
|
417
|
+
#cms-overlay-root > *:not(.cms-block-toolbar) {
|
|
418
418
|
pointer-events: none;
|
|
419
419
|
}
|
|
420
420
|
.cms-block-outline {
|
|
@@ -511,9 +511,69 @@ function generateCmsOverlayScript(cmsParentOrigin) {
|
|
|
511
511
|
blockEl.setAttribute('data-cms-block', '');
|
|
512
512
|
blockEl.setAttribute('data-block-id', blockId);
|
|
513
513
|
blockEl.setAttribute('data-block-type', blockType);
|
|
514
|
+
|
|
515
|
+
injectEditableSpans(
|
|
516
|
+
blockEl,
|
|
517
|
+
blockId,
|
|
518
|
+
blockType,
|
|
519
|
+
sentinel.getAttribute('data-content-entries')
|
|
520
|
+
);
|
|
514
521
|
});
|
|
515
522
|
}
|
|
516
523
|
|
|
524
|
+
function injectEditableSpans(blockEl, blockId, blockType, rawEntries) {
|
|
525
|
+
if (!rawEntries || blockEl.querySelector('[data-cms-editable][data-content-path]')) return;
|
|
526
|
+
|
|
527
|
+
var entries;
|
|
528
|
+
try {
|
|
529
|
+
entries = JSON.parse(rawEntries);
|
|
530
|
+
} catch (_) {
|
|
531
|
+
return;
|
|
532
|
+
}
|
|
533
|
+
if (!Array.isArray(entries) || entries.length === 0) return;
|
|
534
|
+
|
|
535
|
+
var used = {};
|
|
536
|
+
var walker = document.createTreeWalker(blockEl, NodeFilter.SHOW_TEXT, null);
|
|
537
|
+
var textNodes = [];
|
|
538
|
+
var node = walker.nextNode();
|
|
539
|
+
while (node !== null) {
|
|
540
|
+
if (node.nodeValue && node.nodeValue.trim()) {
|
|
541
|
+
textNodes.push(node);
|
|
542
|
+
}
|
|
543
|
+
node = walker.nextNode();
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
for (var i = 0; i < textNodes.length; i++) {
|
|
547
|
+
var textNode = textNodes[i];
|
|
548
|
+
var parentEl = textNode.parentElement;
|
|
549
|
+
if (!parentEl || parentEl.closest('svg') || parentEl.closest('[data-cms-editable]')) {
|
|
550
|
+
continue;
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
var text = textNode.nodeValue;
|
|
554
|
+
if (!text) continue;
|
|
555
|
+
|
|
556
|
+
for (var j = 0; j < entries.length; j++) {
|
|
557
|
+
var entry = entries[j];
|
|
558
|
+
if (!entry || typeof entry.v !== 'string' || typeof entry.p !== 'string' || used[entry.p]) {
|
|
559
|
+
continue;
|
|
560
|
+
}
|
|
561
|
+
if (text.trim() !== entry.v.trim()) continue;
|
|
562
|
+
|
|
563
|
+
used[entry.p] = true;
|
|
564
|
+
var span = document.createElement('span');
|
|
565
|
+
span.setAttribute('data-cms-editable', '');
|
|
566
|
+
span.setAttribute('data-block-id', blockId);
|
|
567
|
+
span.setAttribute('data-block-type', blockType);
|
|
568
|
+
span.setAttribute('data-content-path', entry.p);
|
|
569
|
+
span.setAttribute('contenteditable', 'true');
|
|
570
|
+
parentEl.insertBefore(span, textNode);
|
|
571
|
+
span.appendChild(textNode);
|
|
572
|
+
break;
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
|
|
517
577
|
stampBlockElements();
|
|
518
578
|
|
|
519
579
|
var stampObserver = new MutationObserver(function(mutations) {
|
|
@@ -859,6 +919,27 @@ function getCmsParentTargetOrigin(preferredCmsUrl, explicitParentOrigin) {
|
|
|
859
919
|
|
|
860
920
|
// lib/block-renderer.tsx
|
|
861
921
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
922
|
+
function extractContentValues(content, basePath = []) {
|
|
923
|
+
const map = /* @__PURE__ */ new Map();
|
|
924
|
+
function walk(obj, path) {
|
|
925
|
+
if (typeof obj === "string" && obj.trim() !== "") {
|
|
926
|
+
const contentPath = path.join(".");
|
|
927
|
+
const existing = map.get(obj) || [];
|
|
928
|
+
existing.push({ contentPath, value: obj });
|
|
929
|
+
map.set(obj, existing);
|
|
930
|
+
} else if (Array.isArray(obj)) {
|
|
931
|
+
for (let index = 0; index < obj.length; index++) {
|
|
932
|
+
walk(obj[index], [...path, String(index)]);
|
|
933
|
+
}
|
|
934
|
+
} else if (obj && typeof obj === "object") {
|
|
935
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
936
|
+
walk(value, [...path, key]);
|
|
937
|
+
}
|
|
938
|
+
}
|
|
939
|
+
}
|
|
940
|
+
walk(content, basePath);
|
|
941
|
+
return map;
|
|
942
|
+
}
|
|
862
943
|
function CmsEditableInit({
|
|
863
944
|
cmsUrl,
|
|
864
945
|
cmsParentOrigin
|
|
@@ -907,6 +988,7 @@ function BlockRenderer({
|
|
|
907
988
|
block,
|
|
908
989
|
registry,
|
|
909
990
|
disableEditable,
|
|
991
|
+
enableContentEditable,
|
|
910
992
|
routeParams,
|
|
911
993
|
path
|
|
912
994
|
}) {
|
|
@@ -922,6 +1004,7 @@ function BlockRenderer({
|
|
|
922
1004
|
if (disableEditable) {
|
|
923
1005
|
return component;
|
|
924
1006
|
}
|
|
1007
|
+
const contentEntries = enableContentEditable ? [...extractContentValues(block.content).values()].flat().map(({ value, contentPath }) => ({ v: value, p: contentPath })) : void 0;
|
|
925
1008
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
926
1009
|
/* @__PURE__ */ jsx(
|
|
927
1010
|
"span",
|
|
@@ -929,6 +1012,7 @@ function BlockRenderer({
|
|
|
929
1012
|
"data-cms-sentinel": "",
|
|
930
1013
|
"data-block-id": block.id,
|
|
931
1014
|
"data-block-type": block.type,
|
|
1015
|
+
"data-content-entries": contentEntries ? JSON.stringify(contentEntries) : void 0,
|
|
932
1016
|
style: { display: "none" },
|
|
933
1017
|
"aria-hidden": "true"
|
|
934
1018
|
}
|
|
@@ -1010,7 +1094,7 @@ async function renderParametricRoute({
|
|
|
1010
1094
|
apiKey,
|
|
1011
1095
|
cmsUrl,
|
|
1012
1096
|
websiteId: providedWebsiteId
|
|
1013
|
-
}) {
|
|
1097
|
+
}, { preview = false } = {}) {
|
|
1014
1098
|
const websiteId = getWebsiteId(providedWebsiteId);
|
|
1015
1099
|
const { slug } = "then" in params ? await params : params;
|
|
1016
1100
|
const resolvedSearchParams = searchParams && "then" in searchParams ? await searchParams : searchParams;
|
|
@@ -1025,10 +1109,11 @@ async function renderParametricRoute({
|
|
|
1025
1109
|
}
|
|
1026
1110
|
}
|
|
1027
1111
|
}
|
|
1028
|
-
const editModeParam = resolvedSearchParams?.edit_mode;
|
|
1029
|
-
const editMode = editModeParam === true || editModeParam === "true" || editModeParam === "1";
|
|
1030
1112
|
const cmsParentOriginParam = resolvedSearchParams?.cms_parent_origin;
|
|
1031
1113
|
const cmsParentOrigin = typeof cmsParentOriginParam === "boolean" ? void 0 : Array.isArray(cmsParentOriginParam) ? cmsParentOriginParam[0] : cmsParentOriginParam;
|
|
1114
|
+
const previewMode = preview === true;
|
|
1115
|
+
const editModeParam = resolvedSearchParams?.edit_mode;
|
|
1116
|
+
const editMode = previewMode || editModeParam === true || editModeParam === "true" || editModeParam === "1";
|
|
1032
1117
|
const rawPath = `/${slug.join("/")}`;
|
|
1033
1118
|
const path = normalizePath(rawPath);
|
|
1034
1119
|
if (/\.[a-zA-Z0-9]+$/.test(path)) {
|
|
@@ -1068,7 +1153,9 @@ async function renderParametricRoute({
|
|
|
1068
1153
|
]);
|
|
1069
1154
|
const blocks = [];
|
|
1070
1155
|
for (const block of blockResults) {
|
|
1071
|
-
if (!block
|
|
1156
|
+
if (!block) continue;
|
|
1157
|
+
const blockContent = previewMode ? block.draft_content : block.published_content;
|
|
1158
|
+
if (blockContent == null) continue;
|
|
1072
1159
|
let content = null;
|
|
1073
1160
|
if (aiPreviewIndex !== null) {
|
|
1074
1161
|
const generatedBlock = generatedBlocks[block.id];
|
|
@@ -1078,7 +1165,7 @@ async function renderParametricRoute({
|
|
|
1078
1165
|
content = variants[variantIndex].content;
|
|
1079
1166
|
}
|
|
1080
1167
|
}
|
|
1081
|
-
content = content ??
|
|
1168
|
+
content = content ?? blockContent;
|
|
1082
1169
|
if (!content) continue;
|
|
1083
1170
|
if (block.schema_name === "article") {
|
|
1084
1171
|
const article = normalizeArticleContent(content);
|
|
@@ -1126,6 +1213,7 @@ async function renderParametricRoute({
|
|
|
1126
1213
|
block,
|
|
1127
1214
|
registry: registry ?? {},
|
|
1128
1215
|
disableEditable: !editMode,
|
|
1216
|
+
enableContentEditable: previewMode,
|
|
1129
1217
|
routeParams,
|
|
1130
1218
|
path
|
|
1131
1219
|
},
|