cms-renderer 0.5.0 → 0.5.1
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 +12 -5
- package/dist/lib/block-renderer.js +162 -142
- package/dist/lib/block-renderer.js.map +1 -1
- package/dist/lib/client-editable-block.js +2 -0
- package/dist/lib/client-editable-block.js.map +1 -1
- package/dist/lib/renderer.js +176 -154
- package/dist/lib/renderer.js.map +1 -1
- package/package.json +1 -1
package/dist/lib/renderer.js
CHANGED
|
@@ -245,13 +245,27 @@ import { notFound } from "next/navigation";
|
|
|
245
245
|
import React from "react";
|
|
246
246
|
import { BlockToolbar } from "./block-toolbar.js";
|
|
247
247
|
import { ClientEditableBlock } from "./client-editable-block.js";
|
|
248
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
248
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
249
|
+
var SKIP_SPAN_PARENTS = /* @__PURE__ */ new Set([
|
|
250
|
+
// SVG text-bearing elements — spans are not valid SVG children
|
|
251
|
+
"text",
|
|
252
|
+
"tspan",
|
|
253
|
+
"textPath",
|
|
254
|
+
"desc",
|
|
255
|
+
// Form elements whose text content must not be interrupted
|
|
256
|
+
"option",
|
|
257
|
+
"optgroup",
|
|
258
|
+
// Non-rendered elements
|
|
259
|
+
"script",
|
|
260
|
+
"style",
|
|
261
|
+
"noscript"
|
|
262
|
+
]);
|
|
249
263
|
function walkReactNode(node, visitors, ctx = {}) {
|
|
250
264
|
const path = ctx.path ?? [];
|
|
251
265
|
if (node == null || typeof node === "boolean") return node;
|
|
252
266
|
if (typeof node === "string" || typeof node === "number") {
|
|
253
267
|
const value = String(node);
|
|
254
|
-
return visitors.onText ? visitors.onText({ value, path, parentType: ctx.parentType, key: ctx.key }) : node;
|
|
268
|
+
return visitors.onText ? visitors.onText({ value, path, parentType: ctx.parentType, key: ctx.key, inSvg: ctx.inSvg }) : node;
|
|
255
269
|
}
|
|
256
270
|
if (Array.isArray(node)) {
|
|
257
271
|
return node.map((child, i) => {
|
|
@@ -259,7 +273,8 @@ function walkReactNode(node, visitors, ctx = {}) {
|
|
|
259
273
|
const result = walkReactNode(child, visitors, {
|
|
260
274
|
path: [...path, i],
|
|
261
275
|
parentType: ctx.parentType,
|
|
262
|
-
key: childKey
|
|
276
|
+
key: childKey,
|
|
277
|
+
inSvg: ctx.inSvg
|
|
263
278
|
});
|
|
264
279
|
if (React.isValidElement(result) && result.key == null) {
|
|
265
280
|
return React.cloneElement(result, { key: childKey ?? `arr-${path.join("-")}-${i}` });
|
|
@@ -270,13 +285,15 @@ function walkReactNode(node, visitors, ctx = {}) {
|
|
|
270
285
|
if (React.isValidElement(node)) {
|
|
271
286
|
const el = node;
|
|
272
287
|
const elProps = el.props;
|
|
288
|
+
const nextInSvg = ctx.inSvg || el.type === "svg";
|
|
273
289
|
const hasChildren = elProps && "children" in elProps;
|
|
274
290
|
const nextChildren = hasChildren ? React.Children.map(elProps.children, (child, i) => {
|
|
275
291
|
const childKey = child?.key ?? null;
|
|
276
292
|
const result = walkReactNode(child, visitors, {
|
|
277
293
|
path: [...path, "children", i],
|
|
278
294
|
parentType: el.type,
|
|
279
|
-
key: childKey
|
|
295
|
+
key: childKey,
|
|
296
|
+
inSvg: nextInSvg
|
|
280
297
|
});
|
|
281
298
|
if (React.isValidElement(result) && result.key == null) {
|
|
282
299
|
return React.cloneElement(result, { key: childKey ?? `child-${path.join("-")}-${i}` });
|
|
@@ -309,6 +326,140 @@ function extractContentValues(content, basePath = []) {
|
|
|
309
326
|
walk(content, basePath);
|
|
310
327
|
return map;
|
|
311
328
|
}
|
|
329
|
+
var CMS_EDITABLE_STYLES = `
|
|
330
|
+
.cms-block-toolbar {
|
|
331
|
+
position: fixed;
|
|
332
|
+
transform: translateX(-50%);
|
|
333
|
+
display: flex;
|
|
334
|
+
gap: 4px;
|
|
335
|
+
background: #1f2937;
|
|
336
|
+
border-radius: 6px;
|
|
337
|
+
padding: 4px;
|
|
338
|
+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
|
|
339
|
+
opacity: 0;
|
|
340
|
+
pointer-events: none;
|
|
341
|
+
transition: opacity 0.15s ease;
|
|
342
|
+
z-index: 9999;
|
|
343
|
+
}
|
|
344
|
+
.cms-block-toolbar button {
|
|
345
|
+
display: flex;
|
|
346
|
+
align-items: center;
|
|
347
|
+
justify-content: center;
|
|
348
|
+
width: 28px;
|
|
349
|
+
height: 28px;
|
|
350
|
+
border: none;
|
|
351
|
+
background: transparent;
|
|
352
|
+
color: #9ca3af;
|
|
353
|
+
border-radius: 4px;
|
|
354
|
+
cursor: pointer;
|
|
355
|
+
transition: background 0.15s ease, color 0.15s ease;
|
|
356
|
+
}
|
|
357
|
+
.cms-block-toolbar button:hover {
|
|
358
|
+
background: #374151;
|
|
359
|
+
color: #fff;
|
|
360
|
+
}
|
|
361
|
+
.cms-block-toolbar button.delete:hover {
|
|
362
|
+
background: #dc2626;
|
|
363
|
+
color: #fff;
|
|
364
|
+
}
|
|
365
|
+
.cms-block-toolbar button:disabled {
|
|
366
|
+
opacity: 0.4;
|
|
367
|
+
cursor: not-allowed;
|
|
368
|
+
}
|
|
369
|
+
.cms-block-toolbar button:disabled:hover {
|
|
370
|
+
background: transparent;
|
|
371
|
+
color: #9ca3af;
|
|
372
|
+
}
|
|
373
|
+
.cms-block-toolbar svg {
|
|
374
|
+
width: 16px;
|
|
375
|
+
height: 16px;
|
|
376
|
+
}
|
|
377
|
+
`;
|
|
378
|
+
var CMS_EDITABLE_SCRIPT = `
|
|
379
|
+
(function() {
|
|
380
|
+
if (!window.__cmsEditableInitialized) {
|
|
381
|
+
window.__cmsEditableInitialized = true;
|
|
382
|
+
var _ab = null;
|
|
383
|
+
|
|
384
|
+
function _tb(bid) {
|
|
385
|
+
return document.querySelector('.cms-block-toolbar[data-block-id="' + bid + '"]');
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
function _show(bid, target) {
|
|
389
|
+
var tb = _tb(bid);
|
|
390
|
+
if (tb && target) {
|
|
391
|
+
var r = target.getBoundingClientRect();
|
|
392
|
+
tb.style.left = Math.round(r.left + r.width / 2) + 'px';
|
|
393
|
+
tb.style.top = Math.round(r.bottom + 8) + 'px';
|
|
394
|
+
tb.style.opacity = '1';
|
|
395
|
+
tb.style.pointerEvents = 'auto';
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
function _hide(bid) {
|
|
400
|
+
var tb = _tb(bid);
|
|
401
|
+
if (tb) { tb.style.opacity = '0'; tb.style.pointerEvents = 'none'; }
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
document.addEventListener('mouseover', function(e) {
|
|
405
|
+
if (e.target.closest('.cms-block-toolbar')) return;
|
|
406
|
+
var bel = e.target.closest('[data-cms-block]');
|
|
407
|
+
var bid = bel ? bel.getAttribute('data-block-id') : null;
|
|
408
|
+
if (bid === _ab) return;
|
|
409
|
+
if (_ab) _hide(_ab);
|
|
410
|
+
_ab = bid;
|
|
411
|
+
if (bid) _show(bid, e.target);
|
|
412
|
+
});
|
|
413
|
+
|
|
414
|
+
document.addEventListener('click', function(e) {
|
|
415
|
+
if (e.target.closest('.cms-block-toolbar')) return;
|
|
416
|
+
|
|
417
|
+
var path = e.composedPath ? e.composedPath() : [e.target];
|
|
418
|
+
var et = null;
|
|
419
|
+
for (var i = 0; i < path.length; i++) {
|
|
420
|
+
var n = path[i];
|
|
421
|
+
if (n.nodeType === 1 && n.hasAttribute && n.hasAttribute('data-cms-editable')) { et = n; break; }
|
|
422
|
+
}
|
|
423
|
+
if (!et) et = e.target.closest && e.target.closest('[data-cms-editable]');
|
|
424
|
+
|
|
425
|
+
if (et) {
|
|
426
|
+
if (window.parent && window.parent !== window) {
|
|
427
|
+
window.parent.postMessage({
|
|
428
|
+
type: 'cms-editable-click',
|
|
429
|
+
blockId: et.getAttribute('data-block-id'),
|
|
430
|
+
blockType: et.getAttribute('data-block-type'),
|
|
431
|
+
contentPath: et.getAttribute('data-content-path')
|
|
432
|
+
}, '*');
|
|
433
|
+
}
|
|
434
|
+
return;
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
var bt = e.target.closest && e.target.closest('[data-cms-block]');
|
|
438
|
+
if (bt) {
|
|
439
|
+
if (window.parent && window.parent !== window) {
|
|
440
|
+
window.parent.postMessage({
|
|
441
|
+
type: 'cms-editable-click',
|
|
442
|
+
blockId: bt.getAttribute('data-block-id'),
|
|
443
|
+
blockType: bt.getAttribute('data-block-type'),
|
|
444
|
+
contentPath: null
|
|
445
|
+
}, '*');
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
});
|
|
449
|
+
}
|
|
450
|
+
})();
|
|
451
|
+
`;
|
|
452
|
+
function CmsEditableInit() {
|
|
453
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
454
|
+
/* @__PURE__ */ jsx("style", { children: CMS_EDITABLE_STYLES }),
|
|
455
|
+
/* @__PURE__ */ jsx(
|
|
456
|
+
"script",
|
|
457
|
+
{
|
|
458
|
+
dangerouslySetInnerHTML: { __html: CMS_EDITABLE_SCRIPT }
|
|
459
|
+
}
|
|
460
|
+
)
|
|
461
|
+
] });
|
|
462
|
+
}
|
|
312
463
|
function pathMatchesPattern(path, pattern) {
|
|
313
464
|
const pathSegs = path.split("/").filter(Boolean);
|
|
314
465
|
const patternSegs = pattern.split("/").filter(Boolean);
|
|
@@ -398,7 +549,11 @@ function BlockRenderer({
|
|
|
398
549
|
if (isWalkable) {
|
|
399
550
|
const usedPaths = /* @__PURE__ */ new Set();
|
|
400
551
|
renderedComponent = walkReactNode(renderedTree, {
|
|
401
|
-
onText: ({ value, key, path: path2 }) => {
|
|
552
|
+
onText: ({ value, key, path: path2, inSvg, parentType }) => {
|
|
553
|
+
if (inSvg) return value;
|
|
554
|
+
if (parentType && typeof parentType === "string" && SKIP_SPAN_PARENTS.has(parentType)) {
|
|
555
|
+
return value;
|
|
556
|
+
}
|
|
402
557
|
const matches = contentValueMap.get(value);
|
|
403
558
|
if (!matches || matches.length === 0) return value;
|
|
404
559
|
const match = matches.find((m) => !usedPaths.has(m.contentPath)) ?? matches[0];
|
|
@@ -412,6 +567,7 @@ function BlockRenderer({
|
|
|
412
567
|
"data-block-id": block.id,
|
|
413
568
|
"data-block-type": block.type,
|
|
414
569
|
"data-content-path": match.contentPath,
|
|
570
|
+
style: { display: "contents" },
|
|
415
571
|
children: value
|
|
416
572
|
},
|
|
417
573
|
spanKey
|
|
@@ -431,143 +587,6 @@ function BlockRenderer({
|
|
|
431
587
|
"data-block-type": block.type,
|
|
432
588
|
style: { display: "contents" },
|
|
433
589
|
children: [
|
|
434
|
-
/* @__PURE__ */ jsx("style", { children: `
|
|
435
|
-
[data-cms-block] {
|
|
436
|
-
display: contents;
|
|
437
|
-
}
|
|
438
|
-
[data-cms-editable] {
|
|
439
|
-
display: contents;
|
|
440
|
-
cursor: pointer;
|
|
441
|
-
}
|
|
442
|
-
.cms-block-toolbar {
|
|
443
|
-
position: fixed;
|
|
444
|
-
transform: translateX(-50%);
|
|
445
|
-
display: flex;
|
|
446
|
-
gap: 4px;
|
|
447
|
-
background: #1f2937;
|
|
448
|
-
border-radius: 6px;
|
|
449
|
-
padding: 4px;
|
|
450
|
-
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
|
|
451
|
-
opacity: 0;
|
|
452
|
-
pointer-events: none;
|
|
453
|
-
transition: opacity 0.15s ease;
|
|
454
|
-
z-index: 9999;
|
|
455
|
-
}
|
|
456
|
-
.cms-block-toolbar button {
|
|
457
|
-
display: flex;
|
|
458
|
-
align-items: center;
|
|
459
|
-
justify-content: center;
|
|
460
|
-
width: 28px;
|
|
461
|
-
height: 28px;
|
|
462
|
-
border: none;
|
|
463
|
-
background: transparent;
|
|
464
|
-
color: #9ca3af;
|
|
465
|
-
border-radius: 4px;
|
|
466
|
-
cursor: pointer;
|
|
467
|
-
transition: background 0.15s ease, color 0.15s ease;
|
|
468
|
-
}
|
|
469
|
-
.cms-block-toolbar button:hover {
|
|
470
|
-
background: #374151;
|
|
471
|
-
color: #fff;
|
|
472
|
-
}
|
|
473
|
-
.cms-block-toolbar button.delete:hover {
|
|
474
|
-
background: #dc2626;
|
|
475
|
-
color: #fff;
|
|
476
|
-
}
|
|
477
|
-
.cms-block-toolbar button:disabled {
|
|
478
|
-
opacity: 0.4;
|
|
479
|
-
cursor: not-allowed;
|
|
480
|
-
}
|
|
481
|
-
.cms-block-toolbar button:disabled:hover {
|
|
482
|
-
background: transparent;
|
|
483
|
-
color: #9ca3af;
|
|
484
|
-
}
|
|
485
|
-
.cms-block-toolbar svg {
|
|
486
|
-
width: 16px;
|
|
487
|
-
height: 16px;
|
|
488
|
-
}
|
|
489
|
-
` }),
|
|
490
|
-
/* @__PURE__ */ jsx(
|
|
491
|
-
"script",
|
|
492
|
-
{
|
|
493
|
-
dangerouslySetInnerHTML: {
|
|
494
|
-
__html: `
|
|
495
|
-
(function() {
|
|
496
|
-
if (!window.__cmsEditableInitialized) {
|
|
497
|
-
window.__cmsEditableInitialized = true;
|
|
498
|
-
var _ab = null;
|
|
499
|
-
|
|
500
|
-
function _tb(bid) {
|
|
501
|
-
return document.querySelector('.cms-block-toolbar[data-block-id="' + bid + '"]');
|
|
502
|
-
}
|
|
503
|
-
|
|
504
|
-
function _show(bid, target) {
|
|
505
|
-
var tb = _tb(bid);
|
|
506
|
-
if (tb && target) {
|
|
507
|
-
var r = target.getBoundingClientRect();
|
|
508
|
-
tb.style.left = Math.round(r.left + r.width / 2) + 'px';
|
|
509
|
-
tb.style.top = Math.round(r.bottom + 8) + 'px';
|
|
510
|
-
tb.style.opacity = '1';
|
|
511
|
-
tb.style.pointerEvents = 'auto';
|
|
512
|
-
}
|
|
513
|
-
}
|
|
514
|
-
|
|
515
|
-
function _hide(bid) {
|
|
516
|
-
var tb = _tb(bid);
|
|
517
|
-
if (tb) { tb.style.opacity = '0'; tb.style.pointerEvents = 'none'; }
|
|
518
|
-
}
|
|
519
|
-
|
|
520
|
-
document.addEventListener('mouseover', function(e) {
|
|
521
|
-
if (e.target.closest('.cms-block-toolbar')) return;
|
|
522
|
-
var bel = e.target.closest('[data-cms-block]');
|
|
523
|
-
var bid = bel ? bel.getAttribute('data-block-id') : null;
|
|
524
|
-
if (bid === _ab) return;
|
|
525
|
-
if (_ab) _hide(_ab);
|
|
526
|
-
_ab = bid;
|
|
527
|
-
if (bid) _show(bid, e.target);
|
|
528
|
-
});
|
|
529
|
-
|
|
530
|
-
document.addEventListener('click', function(e) {
|
|
531
|
-
if (e.target.closest('.cms-block-toolbar')) return;
|
|
532
|
-
|
|
533
|
-
var path = e.composedPath ? e.composedPath() : [e.target];
|
|
534
|
-
var et = null;
|
|
535
|
-
for (var i = 0; i < path.length; i++) {
|
|
536
|
-
var n = path[i];
|
|
537
|
-
if (n.nodeType === 1 && n.hasAttribute && n.hasAttribute('data-cms-editable')) { et = n; break; }
|
|
538
|
-
}
|
|
539
|
-
if (!et) et = e.target.closest && e.target.closest('[data-cms-editable]');
|
|
540
|
-
|
|
541
|
-
if (et) {
|
|
542
|
-
if (window.parent && window.parent !== window) {
|
|
543
|
-
window.parent.postMessage({
|
|
544
|
-
type: 'cms-editable-click',
|
|
545
|
-
blockId: et.getAttribute('data-block-id'),
|
|
546
|
-
blockType: et.getAttribute('data-block-type'),
|
|
547
|
-
contentPath: et.getAttribute('data-content-path')
|
|
548
|
-
}, '*');
|
|
549
|
-
}
|
|
550
|
-
return;
|
|
551
|
-
}
|
|
552
|
-
|
|
553
|
-
var bt = e.target.closest && e.target.closest('[data-cms-block]');
|
|
554
|
-
if (bt) {
|
|
555
|
-
if (window.parent && window.parent !== window) {
|
|
556
|
-
window.parent.postMessage({
|
|
557
|
-
type: 'cms-editable-click',
|
|
558
|
-
blockId: bt.getAttribute('data-block-id'),
|
|
559
|
-
blockType: bt.getAttribute('data-block-type'),
|
|
560
|
-
contentPath: null
|
|
561
|
-
}, '*');
|
|
562
|
-
}
|
|
563
|
-
}
|
|
564
|
-
});
|
|
565
|
-
}
|
|
566
|
-
})();
|
|
567
|
-
`
|
|
568
|
-
}
|
|
569
|
-
}
|
|
570
|
-
),
|
|
571
590
|
needsClientSideSpans && contentEntries.length > 0 ? /* @__PURE__ */ jsx(
|
|
572
591
|
ClientEditableBlock,
|
|
573
592
|
{
|
|
@@ -624,7 +643,7 @@ function getCmsClient(options) {
|
|
|
624
643
|
}
|
|
625
644
|
|
|
626
645
|
// lib/renderer.tsx
|
|
627
|
-
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
646
|
+
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
628
647
|
function getWebsiteId(providedWebsiteId) {
|
|
629
648
|
const websiteId = providedWebsiteId ?? process.env.NEXT_PUBLIC_WEBSITE_ID ?? process.env.WEBSITE_ID ?? process.env.CMS_WEBSITE_ID;
|
|
630
649
|
if (!websiteId) {
|
|
@@ -743,17 +762,20 @@ async function ParametricRoutePage({
|
|
|
743
762
|
}
|
|
744
763
|
])
|
|
745
764
|
) : void 0;
|
|
746
|
-
return /* @__PURE__ */
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
765
|
+
return /* @__PURE__ */ jsxs2("main", { children: [
|
|
766
|
+
editMode && /* @__PURE__ */ jsx2(CmsEditableInit, {}),
|
|
767
|
+
blocks.map((block) => /* @__PURE__ */ jsx2(
|
|
768
|
+
BlockRenderer,
|
|
769
|
+
{
|
|
770
|
+
block,
|
|
771
|
+
registry: registry ?? {},
|
|
772
|
+
disableEditable: !editMode,
|
|
773
|
+
routeParams,
|
|
774
|
+
path
|
|
775
|
+
},
|
|
776
|
+
block.id
|
|
777
|
+
))
|
|
778
|
+
] });
|
|
757
779
|
} catch (error) {
|
|
758
780
|
console.error(`Route fetch error for path: ${path}`, error);
|
|
759
781
|
const errorCode = error instanceof Error && "data" in error ? error.data?.code : error instanceof Error && "code" in error ? error.code : void 0;
|