@cmssy/react 9.2.0 → 9.4.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/block-error-boundary.cjs +90 -0
- package/dist/block-error-boundary.d.cts +22 -0
- package/dist/block-error-boundary.d.ts +22 -0
- package/dist/block-error-boundary.js +88 -0
- package/dist/client.cjs +155 -32
- package/dist/client.js +155 -32
- package/dist/index.cjs +213 -48
- package/dist/index.d.cts +6 -3
- package/dist/index.d.ts +6 -3
- package/dist/index.js +214 -49
- package/package.json +7 -2
package/dist/client.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { createContext, useState, useRef, useEffect, useMemo, useContext, useCallback, createElement } from 'react';
|
|
3
3
|
import { fields, resolveInitialTarget, buildBlockContext, postToEditor, PROTOCOL_VERSION, parseEditorMessage, getBlockContentForLanguage, asBucket, toMinorUnits, formatPrice } from '@cmssy/core';
|
|
4
4
|
export { formatPrice, fractionDigits, fromMinorUnits, toMinorUnits } from '@cmssy/core';
|
|
5
|
+
import { BlockErrorBoundary } from '@cmssy/react/block-error-boundary';
|
|
5
6
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
6
7
|
|
|
7
8
|
// src/registry.ts
|
|
@@ -114,6 +115,15 @@ function useEditBridge(page, config) {
|
|
|
114
115
|
"[cmssy] editorOrigin '*' disables origin checks - dev only, do not use in production"
|
|
115
116
|
);
|
|
116
117
|
}
|
|
118
|
+
const postSafe = (message) => {
|
|
119
|
+
try {
|
|
120
|
+
postToEditor(window.parent, postTarget, message);
|
|
121
|
+
} catch (error) {
|
|
122
|
+
if (typeof console !== "undefined") {
|
|
123
|
+
console.debug("[cmssy] post to editor failed", message.type, error);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
};
|
|
117
127
|
const sendReady = () => {
|
|
118
128
|
try {
|
|
119
129
|
const rects = collectRects();
|
|
@@ -202,20 +212,24 @@ function useEditBridge(page, config) {
|
|
|
202
212
|
const target = event.target;
|
|
203
213
|
const el = target?.closest?.("[data-block-id]");
|
|
204
214
|
const id = el?.getAttribute("data-block-id");
|
|
205
|
-
if (!id || !el)
|
|
215
|
+
if (!id || !el) {
|
|
216
|
+
if (!selectedIdRef.current) return;
|
|
217
|
+
if (target?.closest?.("a[href],button")) return;
|
|
218
|
+
selectedIdRef.current = null;
|
|
219
|
+
setSelected(null);
|
|
220
|
+
postSafe({ type: "cmssy:deselect" });
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
206
223
|
selectedIdRef.current = id;
|
|
207
224
|
if (target?.closest?.("a[href]")) event.preventDefault();
|
|
208
225
|
const r = el.getBoundingClientRect();
|
|
209
226
|
const layoutPosition = el.getAttribute("data-layout-position");
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
});
|
|
217
|
-
} catch {
|
|
218
|
-
}
|
|
227
|
+
postSafe({
|
|
228
|
+
type: "cmssy:click",
|
|
229
|
+
blockId: id,
|
|
230
|
+
rect: { x: r.x, y: r.y, width: r.width, height: r.height },
|
|
231
|
+
...layoutPosition !== null ? { layoutPosition } : {}
|
|
232
|
+
});
|
|
219
233
|
};
|
|
220
234
|
let boundsRaf = 0;
|
|
221
235
|
let boundsPending = false;
|
|
@@ -230,14 +244,11 @@ function useEditBridge(page, config) {
|
|
|
230
244
|
const el = findBlockEl(id);
|
|
231
245
|
if (!el) return;
|
|
232
246
|
const r = el.getBoundingClientRect();
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
});
|
|
239
|
-
} catch {
|
|
240
|
-
}
|
|
247
|
+
postSafe({
|
|
248
|
+
type: "cmssy:bounds",
|
|
249
|
+
blockId: id,
|
|
250
|
+
rect: { x: r.x, y: r.y, width: r.width, height: r.height }
|
|
251
|
+
});
|
|
241
252
|
});
|
|
242
253
|
};
|
|
243
254
|
window.addEventListener("message", handler);
|
|
@@ -420,13 +431,85 @@ function useDragAgent(config) {
|
|
|
420
431
|
}, [config.editorOrigin]);
|
|
421
432
|
return { dropY };
|
|
422
433
|
}
|
|
434
|
+
|
|
435
|
+
// src/components/block-error.ts
|
|
436
|
+
var BLOCK_ERROR_KEY = "__cmssyBlockError";
|
|
437
|
+
var SOURCES = [
|
|
438
|
+
"loader",
|
|
439
|
+
"render",
|
|
440
|
+
"unregistered"
|
|
441
|
+
];
|
|
442
|
+
function unregisteredBlockError(type) {
|
|
443
|
+
return {
|
|
444
|
+
source: "unregistered",
|
|
445
|
+
message: `Block type "${type}" is not registered in this site's blocks array.`
|
|
446
|
+
};
|
|
447
|
+
}
|
|
448
|
+
function readBlockError(value) {
|
|
449
|
+
if (typeof value !== "object" || value === null) return void 0;
|
|
450
|
+
const marked = value[BLOCK_ERROR_KEY];
|
|
451
|
+
if (typeof marked !== "object" || marked === null) return void 0;
|
|
452
|
+
const { message, source } = marked;
|
|
453
|
+
if (typeof message !== "string") return void 0;
|
|
454
|
+
if (!SOURCES.includes(source)) return void 0;
|
|
455
|
+
return { message, source };
|
|
456
|
+
}
|
|
457
|
+
var SOURCE_LABELS = {
|
|
458
|
+
loader: "loader failed",
|
|
459
|
+
render: "render failed",
|
|
460
|
+
unregistered: "type not registered"
|
|
461
|
+
};
|
|
462
|
+
var cardStyle = {
|
|
463
|
+
boxSizing: "border-box",
|
|
464
|
+
margin: "8px 0",
|
|
465
|
+
padding: "12px 16px",
|
|
466
|
+
border: "1px dashed #ef4444",
|
|
467
|
+
borderRadius: "8px",
|
|
468
|
+
background: "rgba(239, 68, 68, 0.08)",
|
|
469
|
+
color: "#ef4444",
|
|
470
|
+
fontFamily: "ui-monospace, SFMono-Regular, Menlo, Consolas, 'Liberation Mono', monospace",
|
|
471
|
+
fontSize: "13px",
|
|
472
|
+
lineHeight: 1.5,
|
|
473
|
+
textAlign: "left"
|
|
474
|
+
};
|
|
475
|
+
var headingStyle = {
|
|
476
|
+
fontWeight: 700,
|
|
477
|
+
marginBottom: "4px"
|
|
478
|
+
};
|
|
479
|
+
var metaStyle = {
|
|
480
|
+
opacity: 0.8,
|
|
481
|
+
marginBottom: "4px"
|
|
482
|
+
};
|
|
483
|
+
var messageStyle = {
|
|
484
|
+
whiteSpace: "pre-wrap",
|
|
485
|
+
overflowWrap: "anywhere"
|
|
486
|
+
};
|
|
487
|
+
function BlockErrorCard({
|
|
488
|
+
blockType,
|
|
489
|
+
blockId,
|
|
490
|
+
error
|
|
491
|
+
}) {
|
|
492
|
+
return /* @__PURE__ */ jsxs("div", { role: "alert", "data-cmssy-block-error": error.source, style: cardStyle, children: [
|
|
493
|
+
/* @__PURE__ */ jsxs("div", { style: headingStyle, children: [
|
|
494
|
+
'Block "',
|
|
495
|
+
blockType,
|
|
496
|
+
'" - ',
|
|
497
|
+
SOURCE_LABELS[error.source]
|
|
498
|
+
] }),
|
|
499
|
+
/* @__PURE__ */ jsxs("div", { style: metaStyle, children: [
|
|
500
|
+
"id: ",
|
|
501
|
+
blockId
|
|
502
|
+
] }),
|
|
503
|
+
/* @__PURE__ */ jsx("div", { style: messageStyle, children: error.message })
|
|
504
|
+
] });
|
|
505
|
+
}
|
|
423
506
|
var WARN_CAP = 256;
|
|
424
507
|
var warned = /* @__PURE__ */ new Set();
|
|
425
508
|
function UnknownBlock({ type }) {
|
|
426
509
|
if (typeof window !== "undefined" && !warned.has(type)) {
|
|
427
510
|
if (warned.size >= WARN_CAP) warned.clear();
|
|
428
511
|
warned.add(type);
|
|
429
|
-
console.
|
|
512
|
+
console.error(`[cmssy] no component registered for block type "${type}"`);
|
|
430
513
|
}
|
|
431
514
|
return /* @__PURE__ */ jsx("div", { "data-cmssy-unknown-block": type });
|
|
432
515
|
}
|
|
@@ -439,32 +522,71 @@ function CmssyBlock({
|
|
|
439
522
|
patchedStyle,
|
|
440
523
|
patchedAdvanced,
|
|
441
524
|
editable,
|
|
525
|
+
editMode,
|
|
442
526
|
layoutPosition,
|
|
443
527
|
context,
|
|
444
528
|
data
|
|
445
529
|
}) {
|
|
530
|
+
const inEditMode = editMode ?? editable ?? false;
|
|
446
531
|
const Component = Object.hasOwn(blockMap, block.type) ? blockMap[block.type] : void 0;
|
|
447
|
-
const
|
|
448
|
-
const
|
|
449
|
-
const style = patchedStyle ? { ...asBucket(block.style), ...patchedStyle } : asBucket(block.style);
|
|
450
|
-
const advanced = patchedAdvanced ? { ...asBucket(block.advanced), ...patchedAdvanced } : asBucket(block.advanced);
|
|
451
|
-
return /* @__PURE__ */ jsx(
|
|
532
|
+
const blockError = readBlockError(data);
|
|
533
|
+
const wrap = (children, hidden = false) => /* @__PURE__ */ jsx(
|
|
452
534
|
"div",
|
|
453
535
|
{
|
|
454
536
|
"data-block-id": block.id,
|
|
455
537
|
"data-block-type": block.type,
|
|
456
538
|
"data-layout-position": layoutPosition,
|
|
457
539
|
draggable: editable || void 0,
|
|
458
|
-
style:
|
|
459
|
-
children
|
|
460
|
-
content,
|
|
461
|
-
style,
|
|
462
|
-
advanced,
|
|
463
|
-
context,
|
|
464
|
-
data
|
|
465
|
-
}) : /* @__PURE__ */ jsx(UnknownBlock, { type: block.type })
|
|
540
|
+
style: hidden ? { display: "none" } : void 0,
|
|
541
|
+
children
|
|
466
542
|
}
|
|
467
543
|
);
|
|
544
|
+
if (!Component) {
|
|
545
|
+
return inEditMode ? wrap(
|
|
546
|
+
/* @__PURE__ */ jsx(
|
|
547
|
+
BlockErrorCard,
|
|
548
|
+
{
|
|
549
|
+
blockType: block.type,
|
|
550
|
+
blockId: block.id,
|
|
551
|
+
error: unregisteredBlockError(block.type)
|
|
552
|
+
}
|
|
553
|
+
)
|
|
554
|
+
) : wrap(/* @__PURE__ */ jsx(UnknownBlock, { type: block.type }), true);
|
|
555
|
+
}
|
|
556
|
+
if (blockError) {
|
|
557
|
+
if (!inEditMode) return null;
|
|
558
|
+
return wrap(
|
|
559
|
+
/* @__PURE__ */ jsx(
|
|
560
|
+
BlockErrorCard,
|
|
561
|
+
{
|
|
562
|
+
blockType: block.type,
|
|
563
|
+
blockId: block.id,
|
|
564
|
+
error: blockError
|
|
565
|
+
}
|
|
566
|
+
)
|
|
567
|
+
);
|
|
568
|
+
}
|
|
569
|
+
const base = getBlockContentForLanguage(block.content, locale, defaultLocale);
|
|
570
|
+
const content = patchedContent ? { ...base, ...patchedContent } : base;
|
|
571
|
+
const style = patchedStyle ? { ...asBucket(block.style), ...patchedStyle } : asBucket(block.style);
|
|
572
|
+
const advanced = patchedAdvanced ? { ...asBucket(block.advanced), ...patchedAdvanced } : asBucket(block.advanced);
|
|
573
|
+
return wrap(
|
|
574
|
+
/* @__PURE__ */ jsx(
|
|
575
|
+
BlockErrorBoundary,
|
|
576
|
+
{
|
|
577
|
+
blockType: block.type,
|
|
578
|
+
blockId: block.id,
|
|
579
|
+
editMode: inEditMode,
|
|
580
|
+
children: createElement(Component, {
|
|
581
|
+
content,
|
|
582
|
+
style,
|
|
583
|
+
advanced,
|
|
584
|
+
context,
|
|
585
|
+
data
|
|
586
|
+
})
|
|
587
|
+
}
|
|
588
|
+
)
|
|
589
|
+
);
|
|
468
590
|
}
|
|
469
591
|
function CmssyEditablePage({
|
|
470
592
|
page,
|
|
@@ -673,6 +795,7 @@ function CmssyEditableLayout({
|
|
|
673
795
|
defaultLocale,
|
|
674
796
|
blockMap,
|
|
675
797
|
patchedContent: patches[block.id],
|
|
798
|
+
editMode: true,
|
|
676
799
|
layoutPosition: position,
|
|
677
800
|
context,
|
|
678
801
|
data: data?.[block.id]
|
package/dist/index.cjs
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
var core = require('@cmssy/core');
|
|
4
4
|
var react = require('react');
|
|
5
|
+
var blockErrorBoundary = require('@cmssy/react/block-error-boundary');
|
|
5
6
|
var jsxRuntime = require('react/jsx-runtime');
|
|
6
7
|
var types = require('@cmssy/types');
|
|
7
8
|
|
|
@@ -48,41 +49,155 @@ function blocksToMeta(blocks, defaults = {}) {
|
|
|
48
49
|
}
|
|
49
50
|
return out;
|
|
50
51
|
}
|
|
52
|
+
|
|
53
|
+
// src/components/block-error.ts
|
|
54
|
+
var BLOCK_ERROR_KEY = "__cmssyBlockError";
|
|
55
|
+
var SOURCES = [
|
|
56
|
+
"loader",
|
|
57
|
+
"render",
|
|
58
|
+
"unregistered"
|
|
59
|
+
];
|
|
60
|
+
function blockErrorMessage(err) {
|
|
61
|
+
return err instanceof Error ? err.message : String(err);
|
|
62
|
+
}
|
|
63
|
+
function unregisteredBlockError(type) {
|
|
64
|
+
return {
|
|
65
|
+
source: "unregistered",
|
|
66
|
+
message: `Block type "${type}" is not registered in this site's blocks array.`
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
function markBlockError(error) {
|
|
70
|
+
return { [BLOCK_ERROR_KEY]: error };
|
|
71
|
+
}
|
|
72
|
+
function readBlockError(value) {
|
|
73
|
+
if (typeof value !== "object" || value === null) return void 0;
|
|
74
|
+
const marked = value[BLOCK_ERROR_KEY];
|
|
75
|
+
if (typeof marked !== "object" || marked === null) return void 0;
|
|
76
|
+
const { message, source } = marked;
|
|
77
|
+
if (typeof message !== "string") return void 0;
|
|
78
|
+
if (!SOURCES.includes(source)) return void 0;
|
|
79
|
+
return { message, source };
|
|
80
|
+
}
|
|
81
|
+
var SOURCE_LABELS = {
|
|
82
|
+
loader: "loader failed",
|
|
83
|
+
render: "render failed",
|
|
84
|
+
unregistered: "type not registered"
|
|
85
|
+
};
|
|
86
|
+
var cardStyle = {
|
|
87
|
+
boxSizing: "border-box",
|
|
88
|
+
margin: "8px 0",
|
|
89
|
+
padding: "12px 16px",
|
|
90
|
+
border: "1px dashed #ef4444",
|
|
91
|
+
borderRadius: "8px",
|
|
92
|
+
background: "rgba(239, 68, 68, 0.08)",
|
|
93
|
+
color: "#ef4444",
|
|
94
|
+
fontFamily: "ui-monospace, SFMono-Regular, Menlo, Consolas, 'Liberation Mono', monospace",
|
|
95
|
+
fontSize: "13px",
|
|
96
|
+
lineHeight: 1.5,
|
|
97
|
+
textAlign: "left"
|
|
98
|
+
};
|
|
99
|
+
var headingStyle = {
|
|
100
|
+
fontWeight: 700,
|
|
101
|
+
marginBottom: "4px"
|
|
102
|
+
};
|
|
103
|
+
var metaStyle = {
|
|
104
|
+
opacity: 0.8,
|
|
105
|
+
marginBottom: "4px"
|
|
106
|
+
};
|
|
107
|
+
var messageStyle = {
|
|
108
|
+
whiteSpace: "pre-wrap",
|
|
109
|
+
overflowWrap: "anywhere"
|
|
110
|
+
};
|
|
111
|
+
function BlockErrorCard({
|
|
112
|
+
blockType,
|
|
113
|
+
blockId,
|
|
114
|
+
error
|
|
115
|
+
}) {
|
|
116
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { role: "alert", "data-cmssy-block-error": error.source, style: cardStyle, children: [
|
|
117
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: headingStyle, children: [
|
|
118
|
+
'Block "',
|
|
119
|
+
blockType,
|
|
120
|
+
'" - ',
|
|
121
|
+
SOURCE_LABELS[error.source]
|
|
122
|
+
] }),
|
|
123
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: metaStyle, children: [
|
|
124
|
+
"id: ",
|
|
125
|
+
blockId
|
|
126
|
+
] }),
|
|
127
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: messageStyle, children: error.message })
|
|
128
|
+
] });
|
|
129
|
+
}
|
|
51
130
|
var WARN_CAP = 256;
|
|
52
131
|
var warned = /* @__PURE__ */ new Set();
|
|
53
132
|
function UnknownBlock({ type }) {
|
|
54
133
|
if (typeof window !== "undefined" && !warned.has(type)) {
|
|
55
134
|
if (warned.size >= WARN_CAP) warned.clear();
|
|
56
135
|
warned.add(type);
|
|
57
|
-
console.
|
|
136
|
+
console.error(`[cmssy] no component registered for block type "${type}"`);
|
|
58
137
|
}
|
|
59
138
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { "data-cmssy-unknown-block": type });
|
|
60
139
|
}
|
|
61
140
|
function renderResolvedBlock(block, map, locale, defaultLocale, options = {}) {
|
|
62
|
-
const { context, data, resolvedContent, enabledLocales } = options;
|
|
141
|
+
const { context, data, resolvedContent, enabledLocales, error, editMode } = options;
|
|
63
142
|
const Component = Object.hasOwn(map, block.type) ? map[block.type] : void 0;
|
|
64
|
-
const
|
|
65
|
-
block.content,
|
|
66
|
-
locale,
|
|
67
|
-
defaultLocale,
|
|
68
|
-
enabledLocales?.length ? enabledLocales : void 0
|
|
69
|
-
);
|
|
70
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
143
|
+
const wrap = (children, hidden = false) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
71
144
|
"div",
|
|
72
145
|
{
|
|
73
146
|
"data-block-id": block.id,
|
|
74
147
|
"data-block-type": block.type,
|
|
75
|
-
style:
|
|
76
|
-
children
|
|
77
|
-
content,
|
|
78
|
-
style: core.asBucket(block.style),
|
|
79
|
-
advanced: core.asBucket(block.advanced),
|
|
80
|
-
context,
|
|
81
|
-
data
|
|
82
|
-
}) : /* @__PURE__ */ jsxRuntime.jsx(UnknownBlock, { type: block.type })
|
|
148
|
+
style: hidden ? { display: "none" } : void 0,
|
|
149
|
+
children
|
|
83
150
|
},
|
|
84
151
|
block.id
|
|
85
152
|
);
|
|
153
|
+
if (!Component) {
|
|
154
|
+
return editMode ? wrap(
|
|
155
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
156
|
+
BlockErrorCard,
|
|
157
|
+
{
|
|
158
|
+
blockType: block.type,
|
|
159
|
+
blockId: block.id,
|
|
160
|
+
error: unregisteredBlockError(block.type)
|
|
161
|
+
}
|
|
162
|
+
)
|
|
163
|
+
) : wrap(/* @__PURE__ */ jsxRuntime.jsx(UnknownBlock, { type: block.type }), true);
|
|
164
|
+
}
|
|
165
|
+
if (error) {
|
|
166
|
+
if (!editMode) return null;
|
|
167
|
+
return wrap(
|
|
168
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
169
|
+
BlockErrorCard,
|
|
170
|
+
{
|
|
171
|
+
blockType: block.type,
|
|
172
|
+
blockId: block.id,
|
|
173
|
+
error
|
|
174
|
+
}
|
|
175
|
+
)
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
const content = resolvedContent ?? core.getBlockContentForLanguage(
|
|
179
|
+
block.content,
|
|
180
|
+
locale,
|
|
181
|
+
defaultLocale,
|
|
182
|
+
enabledLocales?.length ? enabledLocales : void 0
|
|
183
|
+
);
|
|
184
|
+
return wrap(
|
|
185
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
186
|
+
blockErrorBoundary.BlockErrorBoundary,
|
|
187
|
+
{
|
|
188
|
+
blockType: block.type,
|
|
189
|
+
blockId: block.id,
|
|
190
|
+
editMode,
|
|
191
|
+
children: react.createElement(Component, {
|
|
192
|
+
content,
|
|
193
|
+
style: core.asBucket(block.style),
|
|
194
|
+
advanced: core.asBucket(block.advanced),
|
|
195
|
+
context,
|
|
196
|
+
data
|
|
197
|
+
})
|
|
198
|
+
}
|
|
199
|
+
)
|
|
200
|
+
);
|
|
86
201
|
}
|
|
87
202
|
async function resolveBlocks(blocks, loaderMap, locale, defaultLocale, context, enabledLocales) {
|
|
88
203
|
return Promise.all(
|
|
@@ -95,19 +210,21 @@ async function resolveBlocks(blocks, loaderMap, locale, defaultLocale, context,
|
|
|
95
210
|
);
|
|
96
211
|
const loader = loaderMap[block.type];
|
|
97
212
|
let data;
|
|
213
|
+
let error;
|
|
98
214
|
if (loader) {
|
|
99
215
|
try {
|
|
100
216
|
data = await loader({ content, context });
|
|
101
217
|
} catch (err) {
|
|
102
218
|
if (typeof console !== "undefined") {
|
|
103
|
-
console.
|
|
219
|
+
console.error(
|
|
104
220
|
`[cmssy] loader for block "${block.type}" (${block.id}) failed`,
|
|
105
221
|
err
|
|
106
222
|
);
|
|
107
223
|
}
|
|
224
|
+
error = { message: blockErrorMessage(err), source: "loader" };
|
|
108
225
|
}
|
|
109
226
|
}
|
|
110
|
-
return { content, data };
|
|
227
|
+
return { content, data, error };
|
|
111
228
|
})
|
|
112
229
|
);
|
|
113
230
|
}
|
|
@@ -148,7 +265,8 @@ async function CmssyServerPage({
|
|
|
148
265
|
config,
|
|
149
266
|
forms,
|
|
150
267
|
auth,
|
|
151
|
-
workspace
|
|
268
|
+
workspace,
|
|
269
|
+
editMode
|
|
152
270
|
}) {
|
|
153
271
|
if (!page) return null;
|
|
154
272
|
const { locale, defaultLocale, enabledLocales } = await resolveRenderLocale({
|
|
@@ -180,10 +298,25 @@ async function CmssyServerPage({
|
|
|
180
298
|
context,
|
|
181
299
|
data: resolved[i]?.data,
|
|
182
300
|
resolvedContent: resolved[i]?.content,
|
|
183
|
-
enabledLocales
|
|
301
|
+
enabledLocales,
|
|
302
|
+
error: resolved[i]?.error,
|
|
303
|
+
editMode
|
|
184
304
|
})
|
|
185
305
|
) });
|
|
186
306
|
}
|
|
307
|
+
function collectBlockData(blocks, resolved, isPreview) {
|
|
308
|
+
const data = {};
|
|
309
|
+
blocks.forEach((block, index) => {
|
|
310
|
+
const entry = resolved[index];
|
|
311
|
+
if (!entry) return;
|
|
312
|
+
if (entry.error && isPreview) {
|
|
313
|
+
data[block.id] = markBlockError(entry.error);
|
|
314
|
+
} else if (entry.data !== void 0) {
|
|
315
|
+
data[block.id] = entry.data;
|
|
316
|
+
}
|
|
317
|
+
});
|
|
318
|
+
return data;
|
|
319
|
+
}
|
|
187
320
|
async function resolveBlockData({
|
|
188
321
|
page,
|
|
189
322
|
blocks,
|
|
@@ -210,12 +343,7 @@ async function resolveBlockData({
|
|
|
210
343
|
context,
|
|
211
344
|
enabledLocales
|
|
212
345
|
);
|
|
213
|
-
|
|
214
|
-
page.blocks.forEach((block, index) => {
|
|
215
|
-
const value = resolved[index]?.data;
|
|
216
|
-
if (value !== void 0) data[block.id] = value;
|
|
217
|
-
});
|
|
218
|
-
return data;
|
|
346
|
+
return collectBlockData(page.blocks, resolved, isPreview);
|
|
219
347
|
}
|
|
220
348
|
async function resolveLayoutBlockData({
|
|
221
349
|
groups,
|
|
@@ -246,12 +374,7 @@ async function resolveLayoutBlockData({
|
|
|
246
374
|
context,
|
|
247
375
|
enabledLocales
|
|
248
376
|
);
|
|
249
|
-
|
|
250
|
-
layoutBlocks.forEach((block, index) => {
|
|
251
|
-
const value = resolved[index]?.data;
|
|
252
|
-
if (value !== void 0) data[block.id] = value;
|
|
253
|
-
});
|
|
254
|
-
return data;
|
|
377
|
+
return collectBlockData(layoutBlocks, resolved, isPreview);
|
|
255
378
|
}
|
|
256
379
|
async function CmssyServerLayout({
|
|
257
380
|
groups,
|
|
@@ -260,7 +383,8 @@ async function CmssyServerLayout({
|
|
|
260
383
|
locale: localeProp,
|
|
261
384
|
defaultLocale: defaultLocaleProp,
|
|
262
385
|
enabledLocales: enabledLocalesProp,
|
|
263
|
-
config
|
|
386
|
+
config,
|
|
387
|
+
editMode
|
|
264
388
|
}) {
|
|
265
389
|
const { locale, defaultLocale, enabledLocales } = await resolveRenderLocale({
|
|
266
390
|
locale: localeProp,
|
|
@@ -287,7 +411,9 @@ async function CmssyServerLayout({
|
|
|
287
411
|
context,
|
|
288
412
|
data: resolved[i]?.data,
|
|
289
413
|
resolvedContent: resolved[i]?.content,
|
|
290
|
-
enabledLocales
|
|
414
|
+
enabledLocales,
|
|
415
|
+
error: resolved[i]?.error,
|
|
416
|
+
editMode
|
|
291
417
|
})
|
|
292
418
|
) });
|
|
293
419
|
}
|
|
@@ -300,32 +426,71 @@ function CmssyBlock({
|
|
|
300
426
|
patchedStyle,
|
|
301
427
|
patchedAdvanced,
|
|
302
428
|
editable,
|
|
429
|
+
editMode,
|
|
303
430
|
layoutPosition,
|
|
304
431
|
context,
|
|
305
432
|
data
|
|
306
433
|
}) {
|
|
434
|
+
const inEditMode = editMode ?? editable ?? false;
|
|
307
435
|
const Component = Object.hasOwn(blockMap, block.type) ? blockMap[block.type] : void 0;
|
|
308
|
-
const
|
|
309
|
-
const
|
|
310
|
-
const style = patchedStyle ? { ...core.asBucket(block.style), ...patchedStyle } : core.asBucket(block.style);
|
|
311
|
-
const advanced = patchedAdvanced ? { ...core.asBucket(block.advanced), ...patchedAdvanced } : core.asBucket(block.advanced);
|
|
312
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
436
|
+
const blockError = readBlockError(data);
|
|
437
|
+
const wrap = (children, hidden = false) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
313
438
|
"div",
|
|
314
439
|
{
|
|
315
440
|
"data-block-id": block.id,
|
|
316
441
|
"data-block-type": block.type,
|
|
317
442
|
"data-layout-position": layoutPosition,
|
|
318
443
|
draggable: editable || void 0,
|
|
319
|
-
style:
|
|
320
|
-
children
|
|
321
|
-
content,
|
|
322
|
-
style,
|
|
323
|
-
advanced,
|
|
324
|
-
context,
|
|
325
|
-
data
|
|
326
|
-
}) : /* @__PURE__ */ jsxRuntime.jsx(UnknownBlock, { type: block.type })
|
|
444
|
+
style: hidden ? { display: "none" } : void 0,
|
|
445
|
+
children
|
|
327
446
|
}
|
|
328
447
|
);
|
|
448
|
+
if (!Component) {
|
|
449
|
+
return inEditMode ? wrap(
|
|
450
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
451
|
+
BlockErrorCard,
|
|
452
|
+
{
|
|
453
|
+
blockType: block.type,
|
|
454
|
+
blockId: block.id,
|
|
455
|
+
error: unregisteredBlockError(block.type)
|
|
456
|
+
}
|
|
457
|
+
)
|
|
458
|
+
) : wrap(/* @__PURE__ */ jsxRuntime.jsx(UnknownBlock, { type: block.type }), true);
|
|
459
|
+
}
|
|
460
|
+
if (blockError) {
|
|
461
|
+
if (!inEditMode) return null;
|
|
462
|
+
return wrap(
|
|
463
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
464
|
+
BlockErrorCard,
|
|
465
|
+
{
|
|
466
|
+
blockType: block.type,
|
|
467
|
+
blockId: block.id,
|
|
468
|
+
error: blockError
|
|
469
|
+
}
|
|
470
|
+
)
|
|
471
|
+
);
|
|
472
|
+
}
|
|
473
|
+
const base = core.getBlockContentForLanguage(block.content, locale, defaultLocale);
|
|
474
|
+
const content = patchedContent ? { ...base, ...patchedContent } : base;
|
|
475
|
+
const style = patchedStyle ? { ...core.asBucket(block.style), ...patchedStyle } : core.asBucket(block.style);
|
|
476
|
+
const advanced = patchedAdvanced ? { ...core.asBucket(block.advanced), ...patchedAdvanced } : core.asBucket(block.advanced);
|
|
477
|
+
return wrap(
|
|
478
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
479
|
+
blockErrorBoundary.BlockErrorBoundary,
|
|
480
|
+
{
|
|
481
|
+
blockType: block.type,
|
|
482
|
+
blockId: block.id,
|
|
483
|
+
editMode: inEditMode,
|
|
484
|
+
children: react.createElement(Component, {
|
|
485
|
+
content,
|
|
486
|
+
style,
|
|
487
|
+
advanced,
|
|
488
|
+
context,
|
|
489
|
+
data
|
|
490
|
+
})
|
|
491
|
+
}
|
|
492
|
+
)
|
|
493
|
+
);
|
|
329
494
|
}
|
|
330
495
|
|
|
331
496
|
Object.defineProperty(exports, "CmssyRequestError", {
|
package/dist/index.d.cts
CHANGED
|
@@ -24,13 +24,14 @@ interface CmssyServerPageProps {
|
|
|
24
24
|
auth?: CmssyBlockAuthContext;
|
|
25
25
|
/** Workspace identity, exposed via context.workspace. Resolved by createCmssyPage. */
|
|
26
26
|
workspace?: CmssyBlockWorkspace;
|
|
27
|
+
editMode?: boolean;
|
|
27
28
|
}
|
|
28
29
|
/**
|
|
29
30
|
* Async React Server Component (Next.js App Router / RSC). It runs each block's
|
|
30
31
|
* loader server-side before rendering, so it must be rendered in a server
|
|
31
32
|
* component tree (as `createCmssyPage` does) - not in a client component.
|
|
32
33
|
*/
|
|
33
|
-
declare function CmssyServerPage({ page, blocks, locale: localeProp, defaultLocale: defaultLocaleProp, enabledLocales: enabledLocalesProp, config, forms, auth, workspace, }: CmssyServerPageProps): Promise<react_jsx_runtime.JSX.Element | null>;
|
|
34
|
+
declare function CmssyServerPage({ page, blocks, locale: localeProp, defaultLocale: defaultLocaleProp, enabledLocales: enabledLocalesProp, config, forms, auth, workspace, editMode, }: CmssyServerPageProps): Promise<react_jsx_runtime.JSX.Element | null>;
|
|
34
35
|
|
|
35
36
|
interface ResolveBlockDataOptions {
|
|
36
37
|
page: CmssyPageData | null;
|
|
@@ -68,13 +69,14 @@ interface CmssyServerLayoutProps {
|
|
|
68
69
|
* Without it the SDK has to guess, and its guess is "en".
|
|
69
70
|
*/
|
|
70
71
|
config?: CmssyClientConfig;
|
|
72
|
+
editMode?: boolean;
|
|
71
73
|
}
|
|
72
74
|
/**
|
|
73
75
|
* Async React Server Component. Like CmssyServerPage it runs each block's
|
|
74
76
|
* loader server-side before rendering, so a header block can list categories
|
|
75
77
|
* the same way a page block can. Must be rendered in a server component tree.
|
|
76
78
|
*/
|
|
77
|
-
declare function CmssyServerLayout({ groups, blocks, position, locale: localeProp, defaultLocale: defaultLocaleProp, enabledLocales: enabledLocalesProp, config, }: CmssyServerLayoutProps): Promise<react_jsx_runtime.JSX.Element | null>;
|
|
79
|
+
declare function CmssyServerLayout({ groups, blocks, position, locale: localeProp, defaultLocale: defaultLocaleProp, enabledLocales: enabledLocalesProp, config, editMode, }: CmssyServerLayoutProps): Promise<react_jsx_runtime.JSX.Element | null>;
|
|
78
80
|
|
|
79
81
|
interface CmssyBlockProps {
|
|
80
82
|
block: RawBlock;
|
|
@@ -85,11 +87,12 @@ interface CmssyBlockProps {
|
|
|
85
87
|
patchedStyle?: Record<string, unknown>;
|
|
86
88
|
patchedAdvanced?: Record<string, unknown>;
|
|
87
89
|
editable?: boolean;
|
|
90
|
+
editMode?: boolean;
|
|
88
91
|
layoutPosition?: string;
|
|
89
92
|
context?: CmssyBlockContext;
|
|
90
93
|
data?: unknown;
|
|
91
94
|
}
|
|
92
|
-
declare function CmssyBlock({ block, locale, defaultLocale, blockMap, patchedContent, patchedStyle, patchedAdvanced, editable, layoutPosition, context, data, }: CmssyBlockProps): react_jsx_runtime.JSX.Element;
|
|
95
|
+
declare function CmssyBlock({ block, locale, defaultLocale, blockMap, patchedContent, patchedStyle, patchedAdvanced, editable, editMode, layoutPosition, context, data, }: CmssyBlockProps): react_jsx_runtime.JSX.Element | null;
|
|
93
96
|
|
|
94
97
|
interface UnknownBlockProps {
|
|
95
98
|
type: string;
|