cms-renderer 0.6.12 → 0.7.0
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 +137 -48
- 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 +167 -53
- package/dist/lib/parametric-route.js.map +1 -1
- package/dist/lib/renderer.d.ts +12 -3
- package/dist/lib/renderer.js +178 -53
- package/dist/lib/renderer.js.map +1 -1
- package/package.json +1 -1
package/dist/lib/renderer.js
CHANGED
|
@@ -474,7 +474,7 @@ function generateCmsOverlayScript(cmsParentOrigin) {
|
|
|
474
474
|
border-radius: 2px;
|
|
475
475
|
}
|
|
476
476
|
[data-cms-editable]:not([data-cms-block]):hover {
|
|
477
|
-
outline: 2px solid #
|
|
477
|
+
outline: 2px solid var(--component-accent, #A78BFA);
|
|
478
478
|
outline-offset: 2px;
|
|
479
479
|
}
|
|
480
480
|
#cms-overlay-root {
|
|
@@ -486,20 +486,43 @@ function generateCmsOverlayScript(cmsParentOrigin) {
|
|
|
486
486
|
pointer-events: none;
|
|
487
487
|
z-index: 99998;
|
|
488
488
|
}
|
|
489
|
-
#cms-overlay-root >
|
|
489
|
+
#cms-overlay-root > *:not(.cms-block-toolbar) {
|
|
490
490
|
pointer-events: none;
|
|
491
491
|
}
|
|
492
492
|
.cms-block-outline {
|
|
493
493
|
position: fixed;
|
|
494
|
-
|
|
494
|
+
box-sizing: border-box;
|
|
495
|
+
border: 4px solid var(--component-accent, #A78BFA);
|
|
495
496
|
border-radius: 4px;
|
|
496
497
|
pointer-events: none;
|
|
497
498
|
z-index: 99997;
|
|
498
499
|
transition: all 0.15s ease;
|
|
499
500
|
}
|
|
500
501
|
.cms-block-outline.cms-outline-selected {
|
|
501
|
-
border-color: #
|
|
502
|
-
border-width:
|
|
502
|
+
border-color: var(--component-accent, #A78BFA);
|
|
503
|
+
border-width: 4px;
|
|
504
|
+
}
|
|
505
|
+
.cms-block-label {
|
|
506
|
+
position: absolute;
|
|
507
|
+
top: 0;
|
|
508
|
+
left: 0;
|
|
509
|
+
display: none;
|
|
510
|
+
max-width: 240px;
|
|
511
|
+
padding: 2px 8px;
|
|
512
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
513
|
+
font-size: 12px;
|
|
514
|
+
font-weight: 600;
|
|
515
|
+
line-height: 1.4;
|
|
516
|
+
color: #fff;
|
|
517
|
+
background: var(--component-accent, #A78BFA);
|
|
518
|
+
border-radius: 4px 4px 4px 0;
|
|
519
|
+
white-space: nowrap;
|
|
520
|
+
overflow: hidden;
|
|
521
|
+
text-overflow: ellipsis;
|
|
522
|
+
pointer-events: none;
|
|
523
|
+
}
|
|
524
|
+
.cms-block-label.cms-label-visible {
|
|
525
|
+
display: block;
|
|
503
526
|
}
|
|
504
527
|
.cms-block-cursor {
|
|
505
528
|
position: fixed;
|
|
@@ -583,9 +606,69 @@ function generateCmsOverlayScript(cmsParentOrigin) {
|
|
|
583
606
|
blockEl.setAttribute('data-cms-block', '');
|
|
584
607
|
blockEl.setAttribute('data-block-id', blockId);
|
|
585
608
|
blockEl.setAttribute('data-block-type', blockType);
|
|
609
|
+
|
|
610
|
+
injectEditableSpans(
|
|
611
|
+
blockEl,
|
|
612
|
+
blockId,
|
|
613
|
+
blockType,
|
|
614
|
+
sentinel.getAttribute('data-content-entries')
|
|
615
|
+
);
|
|
586
616
|
});
|
|
587
617
|
}
|
|
588
618
|
|
|
619
|
+
function injectEditableSpans(blockEl, blockId, blockType, rawEntries) {
|
|
620
|
+
if (!rawEntries || blockEl.querySelector('[data-cms-editable][data-content-path]')) return;
|
|
621
|
+
|
|
622
|
+
var entries;
|
|
623
|
+
try {
|
|
624
|
+
entries = JSON.parse(rawEntries);
|
|
625
|
+
} catch (_) {
|
|
626
|
+
return;
|
|
627
|
+
}
|
|
628
|
+
if (!Array.isArray(entries) || entries.length === 0) return;
|
|
629
|
+
|
|
630
|
+
var used = {};
|
|
631
|
+
var walker = document.createTreeWalker(blockEl, NodeFilter.SHOW_TEXT, null);
|
|
632
|
+
var textNodes = [];
|
|
633
|
+
var node = walker.nextNode();
|
|
634
|
+
while (node !== null) {
|
|
635
|
+
if (node.nodeValue && node.nodeValue.trim()) {
|
|
636
|
+
textNodes.push(node);
|
|
637
|
+
}
|
|
638
|
+
node = walker.nextNode();
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
for (var i = 0; i < textNodes.length; i++) {
|
|
642
|
+
var textNode = textNodes[i];
|
|
643
|
+
var parentEl = textNode.parentElement;
|
|
644
|
+
if (!parentEl || parentEl.closest('svg') || parentEl.closest('[data-cms-editable]')) {
|
|
645
|
+
continue;
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
var text = textNode.nodeValue;
|
|
649
|
+
if (!text) continue;
|
|
650
|
+
|
|
651
|
+
for (var j = 0; j < entries.length; j++) {
|
|
652
|
+
var entry = entries[j];
|
|
653
|
+
if (!entry || typeof entry.v !== 'string' || typeof entry.p !== 'string' || used[entry.p]) {
|
|
654
|
+
continue;
|
|
655
|
+
}
|
|
656
|
+
if (text.trim() !== entry.v.trim()) continue;
|
|
657
|
+
|
|
658
|
+
used[entry.p] = true;
|
|
659
|
+
var span = document.createElement('span');
|
|
660
|
+
span.setAttribute('data-cms-editable', '');
|
|
661
|
+
span.setAttribute('data-block-id', blockId);
|
|
662
|
+
span.setAttribute('data-block-type', blockType);
|
|
663
|
+
span.setAttribute('data-content-path', entry.p);
|
|
664
|
+
span.setAttribute('contenteditable', 'true');
|
|
665
|
+
parentEl.insertBefore(span, textNode);
|
|
666
|
+
span.appendChild(textNode);
|
|
667
|
+
break;
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
|
|
589
672
|
stampBlockElements();
|
|
590
673
|
|
|
591
674
|
var stampObserver = new MutationObserver(function(mutations) {
|
|
@@ -604,15 +687,19 @@ function generateCmsOverlayScript(cmsParentOrigin) {
|
|
|
604
687
|
cursor.className = 'cms-block-cursor';
|
|
605
688
|
overlayRoot.appendChild(cursor);
|
|
606
689
|
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
690
|
+
function createOutline(extraClass) {
|
|
691
|
+
var el = document.createElement('div');
|
|
692
|
+
el.className = 'cms-block-outline' + (extraClass ? ' ' + extraClass : '');
|
|
693
|
+
el.style.display = 'none';
|
|
694
|
+
var label = document.createElement('span');
|
|
695
|
+
label.className = 'cms-block-label';
|
|
696
|
+
el.appendChild(label);
|
|
697
|
+
overlayRoot.appendChild(el);
|
|
698
|
+
return el;
|
|
699
|
+
}
|
|
611
700
|
|
|
612
|
-
var
|
|
613
|
-
selectedOutline
|
|
614
|
-
selectedOutline.style.display = 'none';
|
|
615
|
-
overlayRoot.appendChild(selectedOutline);
|
|
701
|
+
var outline = createOutline();
|
|
702
|
+
var selectedOutline = createOutline('cms-outline-selected');
|
|
616
703
|
|
|
617
704
|
var toolbar = document.createElement('div');
|
|
618
705
|
toolbar.className = 'cms-block-toolbar';
|
|
@@ -640,35 +727,19 @@ function generateCmsOverlayScript(cmsParentOrigin) {
|
|
|
640
727
|
var toolbarVisible = false;
|
|
641
728
|
var selectedBlockId = null;
|
|
642
729
|
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
}
|
|
657
|
-
|
|
658
|
-
function preserveEditParamsOnNavigation(e) {
|
|
659
|
-
if (e.defaultPrevented || e.button !== 0 || e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) {
|
|
660
|
-
return;
|
|
661
|
-
}
|
|
662
|
-
|
|
663
|
-
var anchor = e.target.closest('a[href]');
|
|
664
|
-
if (!anchor || (anchor.target && anchor.target !== '_self') || anchor.hasAttribute('download')) {
|
|
665
|
-
return;
|
|
666
|
-
}
|
|
667
|
-
|
|
668
|
-
var href = anchor.getAttribute('href');
|
|
669
|
-
var decorated = decoratePreviewUrl(href);
|
|
670
|
-
if (decorated && decorated !== href) {
|
|
671
|
-
anchor.setAttribute('href', decorated);
|
|
730
|
+
// In edit mode we hijack every link/button activation. Following a link or
|
|
731
|
+
// firing a button's own handler makes inline editing on that element
|
|
732
|
+
// impossible (the click navigates away or triggers an action instead of
|
|
733
|
+
// placing the caret). We block the default action and stop the event from
|
|
734
|
+
// reaching the element's own listeners, while still letting our selection /
|
|
735
|
+
// edit routing run below.
|
|
736
|
+
function blockInteractiveActivation(e) {
|
|
737
|
+
var interactive = e.target.closest(
|
|
738
|
+
'a[href], button, [role="button"], input[type="submit"], input[type="button"], input[type="reset"]'
|
|
739
|
+
);
|
|
740
|
+
if (interactive) {
|
|
741
|
+
e.preventDefault();
|
|
742
|
+
e.stopPropagation();
|
|
672
743
|
}
|
|
673
744
|
}
|
|
674
745
|
|
|
@@ -703,9 +774,18 @@ function generateCmsOverlayScript(cmsParentOrigin) {
|
|
|
703
774
|
return -1;
|
|
704
775
|
}
|
|
705
776
|
|
|
777
|
+
function formatBlockType(type) {
|
|
778
|
+
if (!type) return 'Block';
|
|
779
|
+
return type
|
|
780
|
+
.replace(/[-_]+/g, ' ')
|
|
781
|
+
.replace(/\\b\\w/g, function(c) { return c.toUpperCase(); });
|
|
782
|
+
}
|
|
783
|
+
|
|
706
784
|
function updateOutline(el, outlineEl) {
|
|
785
|
+
var label = outlineEl.querySelector('.cms-block-label');
|
|
707
786
|
if (!el) {
|
|
708
787
|
outlineEl.style.display = 'none';
|
|
788
|
+
if (label) label.classList.remove('cms-label-visible');
|
|
709
789
|
return;
|
|
710
790
|
}
|
|
711
791
|
var rect = el.getBoundingClientRect();
|
|
@@ -714,6 +794,10 @@ function generateCmsOverlayScript(cmsParentOrigin) {
|
|
|
714
794
|
outlineEl.style.left = rect.left + 'px';
|
|
715
795
|
outlineEl.style.width = rect.width + 'px';
|
|
716
796
|
outlineEl.style.height = rect.height + 'px';
|
|
797
|
+
if (label) {
|
|
798
|
+
label.textContent = formatBlockType(el.getAttribute('data-block-type'));
|
|
799
|
+
label.classList.add('cms-label-visible');
|
|
800
|
+
}
|
|
717
801
|
}
|
|
718
802
|
|
|
719
803
|
function positionToolbar(x, y) {
|
|
@@ -790,17 +874,19 @@ function generateCmsOverlayScript(cmsParentOrigin) {
|
|
|
790
874
|
});
|
|
791
875
|
|
|
792
876
|
document.addEventListener('click', function(e) {
|
|
793
|
-
|
|
877
|
+
// The floating toolbar is interactive (and its buttons are real <button>s);
|
|
878
|
+
// bail out before any blocking so its own handlers run.
|
|
879
|
+
if (e.target.closest('[data-cms-toolbar]')) return;
|
|
794
880
|
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
881
|
+
blockInteractiveActivation(e);
|
|
882
|
+
|
|
883
|
+
if (toolbarVisible) {
|
|
884
|
+
var activeBlock = e.target.closest('[data-cms-block]');
|
|
885
|
+
if (!activeBlock || activeBlock.getAttribute('data-block-id') !== currentBlockId) {
|
|
798
886
|
hideToolbar();
|
|
799
887
|
}
|
|
800
888
|
}
|
|
801
889
|
|
|
802
|
-
if (e.target.closest('[data-cms-toolbar]')) return;
|
|
803
|
-
|
|
804
890
|
var editable = e.target.closest('[data-cms-editable]');
|
|
805
891
|
if (editable) {
|
|
806
892
|
postToParent({
|
|
@@ -931,6 +1017,27 @@ function getCmsParentTargetOrigin(preferredCmsUrl, explicitParentOrigin) {
|
|
|
931
1017
|
|
|
932
1018
|
// lib/block-renderer.tsx
|
|
933
1019
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
1020
|
+
function extractContentValues(content, basePath = []) {
|
|
1021
|
+
const map = /* @__PURE__ */ new Map();
|
|
1022
|
+
function walk(obj, path) {
|
|
1023
|
+
if (typeof obj === "string" && obj.trim() !== "") {
|
|
1024
|
+
const contentPath = path.join(".");
|
|
1025
|
+
const existing = map.get(obj) || [];
|
|
1026
|
+
existing.push({ contentPath, value: obj });
|
|
1027
|
+
map.set(obj, existing);
|
|
1028
|
+
} else if (Array.isArray(obj)) {
|
|
1029
|
+
for (let index = 0; index < obj.length; index++) {
|
|
1030
|
+
walk(obj[index], [...path, String(index)]);
|
|
1031
|
+
}
|
|
1032
|
+
} else if (obj && typeof obj === "object") {
|
|
1033
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
1034
|
+
walk(value, [...path, key]);
|
|
1035
|
+
}
|
|
1036
|
+
}
|
|
1037
|
+
}
|
|
1038
|
+
walk(content, basePath);
|
|
1039
|
+
return map;
|
|
1040
|
+
}
|
|
934
1041
|
function CmsEditableInit({
|
|
935
1042
|
cmsUrl,
|
|
936
1043
|
cmsParentOrigin
|
|
@@ -979,6 +1086,7 @@ function BlockRenderer({
|
|
|
979
1086
|
block,
|
|
980
1087
|
registry,
|
|
981
1088
|
disableEditable,
|
|
1089
|
+
enableContentEditable,
|
|
982
1090
|
routeParams,
|
|
983
1091
|
path
|
|
984
1092
|
}) {
|
|
@@ -994,6 +1102,7 @@ function BlockRenderer({
|
|
|
994
1102
|
if (disableEditable) {
|
|
995
1103
|
return component;
|
|
996
1104
|
}
|
|
1105
|
+
const contentEntries = enableContentEditable ? [...extractContentValues(block.content).values()].flat().map(({ value, contentPath }) => ({ v: value, p: contentPath })) : void 0;
|
|
997
1106
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
998
1107
|
/* @__PURE__ */ jsx(
|
|
999
1108
|
"span",
|
|
@@ -1001,6 +1110,7 @@ function BlockRenderer({
|
|
|
1001
1110
|
"data-cms-sentinel": "",
|
|
1002
1111
|
"data-block-id": block.id,
|
|
1003
1112
|
"data-block-type": block.type,
|
|
1113
|
+
"data-content-entries": contentEntries ? JSON.stringify(contentEntries) : void 0,
|
|
1004
1114
|
style: { display: "none" },
|
|
1005
1115
|
"aria-hidden": "true"
|
|
1006
1116
|
}
|
|
@@ -1034,7 +1144,7 @@ async function renderParametricRoute({
|
|
|
1034
1144
|
apiKey,
|
|
1035
1145
|
cmsUrl,
|
|
1036
1146
|
websiteId: providedWebsiteId
|
|
1037
|
-
}) {
|
|
1147
|
+
}, { preview = false } = {}) {
|
|
1038
1148
|
const websiteId = getWebsiteId(providedWebsiteId);
|
|
1039
1149
|
const { slug } = "then" in params ? await params : params;
|
|
1040
1150
|
const resolvedSearchParams = searchParams && "then" in searchParams ? await searchParams : searchParams;
|
|
@@ -1049,10 +1159,11 @@ async function renderParametricRoute({
|
|
|
1049
1159
|
}
|
|
1050
1160
|
}
|
|
1051
1161
|
}
|
|
1052
|
-
const editModeParam = resolvedSearchParams?.edit_mode;
|
|
1053
|
-
const editMode = editModeParam === true || editModeParam === "true" || editModeParam === "1";
|
|
1054
1162
|
const cmsParentOriginParam = resolvedSearchParams?.cms_parent_origin;
|
|
1055
1163
|
const cmsParentOrigin = typeof cmsParentOriginParam === "boolean" ? void 0 : Array.isArray(cmsParentOriginParam) ? cmsParentOriginParam[0] : cmsParentOriginParam;
|
|
1164
|
+
const previewMode = preview === true;
|
|
1165
|
+
const editModeParam = resolvedSearchParams?.edit_mode;
|
|
1166
|
+
const editMode = previewMode || editModeParam === true || editModeParam === "true" || editModeParam === "1";
|
|
1056
1167
|
const rawPath = `/${slug.join("/")}`;
|
|
1057
1168
|
const path = normalizePath(rawPath);
|
|
1058
1169
|
if (/\.[a-zA-Z0-9]+$/.test(path)) {
|
|
@@ -1092,7 +1203,9 @@ async function renderParametricRoute({
|
|
|
1092
1203
|
]);
|
|
1093
1204
|
const blocks = [];
|
|
1094
1205
|
for (const block of blockResults) {
|
|
1095
|
-
if (!block
|
|
1206
|
+
if (!block) continue;
|
|
1207
|
+
const blockContent = previewMode ? block.draft_content : block.published_content;
|
|
1208
|
+
if (blockContent == null) continue;
|
|
1096
1209
|
let content = null;
|
|
1097
1210
|
if (aiPreviewIndex !== null) {
|
|
1098
1211
|
const generatedBlock = generatedBlocks[block.id];
|
|
@@ -1102,7 +1215,7 @@ async function renderParametricRoute({
|
|
|
1102
1215
|
content = variants[variantIndex].content;
|
|
1103
1216
|
}
|
|
1104
1217
|
}
|
|
1105
|
-
content = content ??
|
|
1218
|
+
content = content ?? blockContent;
|
|
1106
1219
|
if (!content) continue;
|
|
1107
1220
|
if (block.schema_name === "article") {
|
|
1108
1221
|
const article = normalizeArticleContent(content);
|
|
@@ -1150,6 +1263,7 @@ async function renderParametricRoute({
|
|
|
1150
1263
|
block,
|
|
1151
1264
|
registry: registry ?? {},
|
|
1152
1265
|
disableEditable: !editMode,
|
|
1266
|
+
enableContentEditable: previewMode,
|
|
1153
1267
|
routeParams,
|
|
1154
1268
|
path
|
|
1155
1269
|
},
|
|
@@ -1178,6 +1292,16 @@ async function ParametricRoutePage(props) {
|
|
|
1178
1292
|
}
|
|
1179
1293
|
return result.node;
|
|
1180
1294
|
}
|
|
1295
|
+
async function ParametricRoutePreviewPage(props) {
|
|
1296
|
+
const result = await renderParametricRoute(props, { preview: true });
|
|
1297
|
+
if (result.status === "not_found") {
|
|
1298
|
+
notFound();
|
|
1299
|
+
}
|
|
1300
|
+
if (result.status === "error") {
|
|
1301
|
+
throw result.error;
|
|
1302
|
+
}
|
|
1303
|
+
return result.node;
|
|
1304
|
+
}
|
|
1181
1305
|
async function generateMetadata({
|
|
1182
1306
|
params,
|
|
1183
1307
|
apiKey,
|
|
@@ -1204,6 +1328,7 @@ async function generateMetadata({
|
|
|
1204
1328
|
}
|
|
1205
1329
|
}
|
|
1206
1330
|
export {
|
|
1331
|
+
ParametricRoutePreviewPage,
|
|
1207
1332
|
ParametricRoutePage as default,
|
|
1208
1333
|
generateMetadata
|
|
1209
1334
|
};
|