@cmssy/react 9.2.0 → 9.3.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 +127 -14
- package/dist/client.js +127 -14
- 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/index.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { buildBlockContext, getBlockContentForLanguage, asBucket, resolveSiteLocales } from '@cmssy/core';
|
|
2
2
|
export { CmssyRequestError, DEFAULT_CMSSY_API_URL, FORM_QUERY, MODEL_DEFINITIONS_QUERY, MODEL_RECORDS_QUERY, PROTOCOL_VERSION, SITE_CONFIG_QUERY, SUBMIT_FORM_MUTATION, buildBlockContext, buildLocaleSwitchHref, collectFormIds, createCmssyClient, fetchLayouts, fetchPage, fetchPageById, fetchPageMeta, fetchPages, fetchSiteConfig, fields, getBlockContentForLanguage, graphqlRequest, isProtocolCompatible, localizeHref, localizeHtmlLinks, normalizeOrigin, normalizeSlug, parseEditorMessage, postToEditor, resolveApiUrl, resolveForms, resolvePublicUrl, resolveSiteLocales, resolveWorkspaceId, splitLocaleFromPath } from '@cmssy/core';
|
|
3
3
|
import { createElement } from 'react';
|
|
4
|
-
import {
|
|
4
|
+
import { BlockErrorBoundary } from '@cmssy/react/block-error-boundary';
|
|
5
|
+
import { jsx, Fragment, jsxs } from 'react/jsx-runtime';
|
|
5
6
|
export { evaluateFieldConditionGroup } from '@cmssy/types';
|
|
6
7
|
|
|
7
8
|
// src/index.ts
|
|
@@ -47,41 +48,155 @@ function blocksToMeta(blocks, defaults = {}) {
|
|
|
47
48
|
}
|
|
48
49
|
return out;
|
|
49
50
|
}
|
|
51
|
+
|
|
52
|
+
// src/components/block-error.ts
|
|
53
|
+
var BLOCK_ERROR_KEY = "__cmssyBlockError";
|
|
54
|
+
var SOURCES = [
|
|
55
|
+
"loader",
|
|
56
|
+
"render",
|
|
57
|
+
"unregistered"
|
|
58
|
+
];
|
|
59
|
+
function blockErrorMessage(err) {
|
|
60
|
+
return err instanceof Error ? err.message : String(err);
|
|
61
|
+
}
|
|
62
|
+
function unregisteredBlockError(type) {
|
|
63
|
+
return {
|
|
64
|
+
source: "unregistered",
|
|
65
|
+
message: `Block type "${type}" is not registered in this site's blocks array.`
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
function markBlockError(error) {
|
|
69
|
+
return { [BLOCK_ERROR_KEY]: error };
|
|
70
|
+
}
|
|
71
|
+
function readBlockError(value) {
|
|
72
|
+
if (typeof value !== "object" || value === null) return void 0;
|
|
73
|
+
const marked = value[BLOCK_ERROR_KEY];
|
|
74
|
+
if (typeof marked !== "object" || marked === null) return void 0;
|
|
75
|
+
const { message, source } = marked;
|
|
76
|
+
if (typeof message !== "string") return void 0;
|
|
77
|
+
if (!SOURCES.includes(source)) return void 0;
|
|
78
|
+
return { message, source };
|
|
79
|
+
}
|
|
80
|
+
var SOURCE_LABELS = {
|
|
81
|
+
loader: "loader failed",
|
|
82
|
+
render: "render failed",
|
|
83
|
+
unregistered: "type not registered"
|
|
84
|
+
};
|
|
85
|
+
var cardStyle = {
|
|
86
|
+
boxSizing: "border-box",
|
|
87
|
+
margin: "8px 0",
|
|
88
|
+
padding: "12px 16px",
|
|
89
|
+
border: "1px dashed #ef4444",
|
|
90
|
+
borderRadius: "8px",
|
|
91
|
+
background: "rgba(239, 68, 68, 0.08)",
|
|
92
|
+
color: "#ef4444",
|
|
93
|
+
fontFamily: "ui-monospace, SFMono-Regular, Menlo, Consolas, 'Liberation Mono', monospace",
|
|
94
|
+
fontSize: "13px",
|
|
95
|
+
lineHeight: 1.5,
|
|
96
|
+
textAlign: "left"
|
|
97
|
+
};
|
|
98
|
+
var headingStyle = {
|
|
99
|
+
fontWeight: 700,
|
|
100
|
+
marginBottom: "4px"
|
|
101
|
+
};
|
|
102
|
+
var metaStyle = {
|
|
103
|
+
opacity: 0.8,
|
|
104
|
+
marginBottom: "4px"
|
|
105
|
+
};
|
|
106
|
+
var messageStyle = {
|
|
107
|
+
whiteSpace: "pre-wrap",
|
|
108
|
+
overflowWrap: "anywhere"
|
|
109
|
+
};
|
|
110
|
+
function BlockErrorCard({
|
|
111
|
+
blockType,
|
|
112
|
+
blockId,
|
|
113
|
+
error
|
|
114
|
+
}) {
|
|
115
|
+
return /* @__PURE__ */ jsxs("div", { role: "alert", "data-cmssy-block-error": error.source, style: cardStyle, children: [
|
|
116
|
+
/* @__PURE__ */ jsxs("div", { style: headingStyle, children: [
|
|
117
|
+
'Block "',
|
|
118
|
+
blockType,
|
|
119
|
+
'" - ',
|
|
120
|
+
SOURCE_LABELS[error.source]
|
|
121
|
+
] }),
|
|
122
|
+
/* @__PURE__ */ jsxs("div", { style: metaStyle, children: [
|
|
123
|
+
"id: ",
|
|
124
|
+
blockId
|
|
125
|
+
] }),
|
|
126
|
+
/* @__PURE__ */ jsx("div", { style: messageStyle, children: error.message })
|
|
127
|
+
] });
|
|
128
|
+
}
|
|
50
129
|
var WARN_CAP = 256;
|
|
51
130
|
var warned = /* @__PURE__ */ new Set();
|
|
52
131
|
function UnknownBlock({ type }) {
|
|
53
132
|
if (typeof window !== "undefined" && !warned.has(type)) {
|
|
54
133
|
if (warned.size >= WARN_CAP) warned.clear();
|
|
55
134
|
warned.add(type);
|
|
56
|
-
console.
|
|
135
|
+
console.error(`[cmssy] no component registered for block type "${type}"`);
|
|
57
136
|
}
|
|
58
137
|
return /* @__PURE__ */ jsx("div", { "data-cmssy-unknown-block": type });
|
|
59
138
|
}
|
|
60
139
|
function renderResolvedBlock(block, map, locale, defaultLocale, options = {}) {
|
|
61
|
-
const { context, data, resolvedContent, enabledLocales } = options;
|
|
140
|
+
const { context, data, resolvedContent, enabledLocales, error, editMode } = options;
|
|
62
141
|
const Component = Object.hasOwn(map, block.type) ? map[block.type] : void 0;
|
|
63
|
-
const
|
|
64
|
-
block.content,
|
|
65
|
-
locale,
|
|
66
|
-
defaultLocale,
|
|
67
|
-
enabledLocales?.length ? enabledLocales : void 0
|
|
68
|
-
);
|
|
69
|
-
return /* @__PURE__ */ jsx(
|
|
142
|
+
const wrap = (children, hidden = false) => /* @__PURE__ */ jsx(
|
|
70
143
|
"div",
|
|
71
144
|
{
|
|
72
145
|
"data-block-id": block.id,
|
|
73
146
|
"data-block-type": block.type,
|
|
74
|
-
style:
|
|
75
|
-
children
|
|
76
|
-
content,
|
|
77
|
-
style: asBucket(block.style),
|
|
78
|
-
advanced: asBucket(block.advanced),
|
|
79
|
-
context,
|
|
80
|
-
data
|
|
81
|
-
}) : /* @__PURE__ */ jsx(UnknownBlock, { type: block.type })
|
|
147
|
+
style: hidden ? { display: "none" } : void 0,
|
|
148
|
+
children
|
|
82
149
|
},
|
|
83
150
|
block.id
|
|
84
151
|
);
|
|
152
|
+
if (!Component) {
|
|
153
|
+
return editMode ? wrap(
|
|
154
|
+
/* @__PURE__ */ jsx(
|
|
155
|
+
BlockErrorCard,
|
|
156
|
+
{
|
|
157
|
+
blockType: block.type,
|
|
158
|
+
blockId: block.id,
|
|
159
|
+
error: unregisteredBlockError(block.type)
|
|
160
|
+
}
|
|
161
|
+
)
|
|
162
|
+
) : wrap(/* @__PURE__ */ jsx(UnknownBlock, { type: block.type }), true);
|
|
163
|
+
}
|
|
164
|
+
if (error) {
|
|
165
|
+
if (!editMode) return null;
|
|
166
|
+
return wrap(
|
|
167
|
+
/* @__PURE__ */ jsx(
|
|
168
|
+
BlockErrorCard,
|
|
169
|
+
{
|
|
170
|
+
blockType: block.type,
|
|
171
|
+
blockId: block.id,
|
|
172
|
+
error
|
|
173
|
+
}
|
|
174
|
+
)
|
|
175
|
+
);
|
|
176
|
+
}
|
|
177
|
+
const content = resolvedContent ?? getBlockContentForLanguage(
|
|
178
|
+
block.content,
|
|
179
|
+
locale,
|
|
180
|
+
defaultLocale,
|
|
181
|
+
enabledLocales?.length ? enabledLocales : void 0
|
|
182
|
+
);
|
|
183
|
+
return wrap(
|
|
184
|
+
/* @__PURE__ */ jsx(
|
|
185
|
+
BlockErrorBoundary,
|
|
186
|
+
{
|
|
187
|
+
blockType: block.type,
|
|
188
|
+
blockId: block.id,
|
|
189
|
+
editMode,
|
|
190
|
+
children: createElement(Component, {
|
|
191
|
+
content,
|
|
192
|
+
style: asBucket(block.style),
|
|
193
|
+
advanced: asBucket(block.advanced),
|
|
194
|
+
context,
|
|
195
|
+
data
|
|
196
|
+
})
|
|
197
|
+
}
|
|
198
|
+
)
|
|
199
|
+
);
|
|
85
200
|
}
|
|
86
201
|
async function resolveBlocks(blocks, loaderMap, locale, defaultLocale, context, enabledLocales) {
|
|
87
202
|
return Promise.all(
|
|
@@ -94,19 +209,21 @@ async function resolveBlocks(blocks, loaderMap, locale, defaultLocale, context,
|
|
|
94
209
|
);
|
|
95
210
|
const loader = loaderMap[block.type];
|
|
96
211
|
let data;
|
|
212
|
+
let error;
|
|
97
213
|
if (loader) {
|
|
98
214
|
try {
|
|
99
215
|
data = await loader({ content, context });
|
|
100
216
|
} catch (err) {
|
|
101
217
|
if (typeof console !== "undefined") {
|
|
102
|
-
console.
|
|
218
|
+
console.error(
|
|
103
219
|
`[cmssy] loader for block "${block.type}" (${block.id}) failed`,
|
|
104
220
|
err
|
|
105
221
|
);
|
|
106
222
|
}
|
|
223
|
+
error = { message: blockErrorMessage(err), source: "loader" };
|
|
107
224
|
}
|
|
108
225
|
}
|
|
109
|
-
return { content, data };
|
|
226
|
+
return { content, data, error };
|
|
110
227
|
})
|
|
111
228
|
);
|
|
112
229
|
}
|
|
@@ -147,7 +264,8 @@ async function CmssyServerPage({
|
|
|
147
264
|
config,
|
|
148
265
|
forms,
|
|
149
266
|
auth,
|
|
150
|
-
workspace
|
|
267
|
+
workspace,
|
|
268
|
+
editMode
|
|
151
269
|
}) {
|
|
152
270
|
if (!page) return null;
|
|
153
271
|
const { locale, defaultLocale, enabledLocales } = await resolveRenderLocale({
|
|
@@ -179,10 +297,25 @@ async function CmssyServerPage({
|
|
|
179
297
|
context,
|
|
180
298
|
data: resolved[i]?.data,
|
|
181
299
|
resolvedContent: resolved[i]?.content,
|
|
182
|
-
enabledLocales
|
|
300
|
+
enabledLocales,
|
|
301
|
+
error: resolved[i]?.error,
|
|
302
|
+
editMode
|
|
183
303
|
})
|
|
184
304
|
) });
|
|
185
305
|
}
|
|
306
|
+
function collectBlockData(blocks, resolved, isPreview) {
|
|
307
|
+
const data = {};
|
|
308
|
+
blocks.forEach((block, index) => {
|
|
309
|
+
const entry = resolved[index];
|
|
310
|
+
if (!entry) return;
|
|
311
|
+
if (entry.error && isPreview) {
|
|
312
|
+
data[block.id] = markBlockError(entry.error);
|
|
313
|
+
} else if (entry.data !== void 0) {
|
|
314
|
+
data[block.id] = entry.data;
|
|
315
|
+
}
|
|
316
|
+
});
|
|
317
|
+
return data;
|
|
318
|
+
}
|
|
186
319
|
async function resolveBlockData({
|
|
187
320
|
page,
|
|
188
321
|
blocks,
|
|
@@ -209,12 +342,7 @@ async function resolveBlockData({
|
|
|
209
342
|
context,
|
|
210
343
|
enabledLocales
|
|
211
344
|
);
|
|
212
|
-
|
|
213
|
-
page.blocks.forEach((block, index) => {
|
|
214
|
-
const value = resolved[index]?.data;
|
|
215
|
-
if (value !== void 0) data[block.id] = value;
|
|
216
|
-
});
|
|
217
|
-
return data;
|
|
345
|
+
return collectBlockData(page.blocks, resolved, isPreview);
|
|
218
346
|
}
|
|
219
347
|
async function resolveLayoutBlockData({
|
|
220
348
|
groups,
|
|
@@ -245,12 +373,7 @@ async function resolveLayoutBlockData({
|
|
|
245
373
|
context,
|
|
246
374
|
enabledLocales
|
|
247
375
|
);
|
|
248
|
-
|
|
249
|
-
layoutBlocks.forEach((block, index) => {
|
|
250
|
-
const value = resolved[index]?.data;
|
|
251
|
-
if (value !== void 0) data[block.id] = value;
|
|
252
|
-
});
|
|
253
|
-
return data;
|
|
376
|
+
return collectBlockData(layoutBlocks, resolved, isPreview);
|
|
254
377
|
}
|
|
255
378
|
async function CmssyServerLayout({
|
|
256
379
|
groups,
|
|
@@ -259,7 +382,8 @@ async function CmssyServerLayout({
|
|
|
259
382
|
locale: localeProp,
|
|
260
383
|
defaultLocale: defaultLocaleProp,
|
|
261
384
|
enabledLocales: enabledLocalesProp,
|
|
262
|
-
config
|
|
385
|
+
config,
|
|
386
|
+
editMode
|
|
263
387
|
}) {
|
|
264
388
|
const { locale, defaultLocale, enabledLocales } = await resolveRenderLocale({
|
|
265
389
|
locale: localeProp,
|
|
@@ -286,7 +410,9 @@ async function CmssyServerLayout({
|
|
|
286
410
|
context,
|
|
287
411
|
data: resolved[i]?.data,
|
|
288
412
|
resolvedContent: resolved[i]?.content,
|
|
289
|
-
enabledLocales
|
|
413
|
+
enabledLocales,
|
|
414
|
+
error: resolved[i]?.error,
|
|
415
|
+
editMode
|
|
290
416
|
})
|
|
291
417
|
) });
|
|
292
418
|
}
|
|
@@ -299,32 +425,71 @@ function CmssyBlock({
|
|
|
299
425
|
patchedStyle,
|
|
300
426
|
patchedAdvanced,
|
|
301
427
|
editable,
|
|
428
|
+
editMode,
|
|
302
429
|
layoutPosition,
|
|
303
430
|
context,
|
|
304
431
|
data
|
|
305
432
|
}) {
|
|
433
|
+
const inEditMode = editMode ?? editable ?? false;
|
|
306
434
|
const Component = Object.hasOwn(blockMap, block.type) ? blockMap[block.type] : void 0;
|
|
307
|
-
const
|
|
308
|
-
const
|
|
309
|
-
const style = patchedStyle ? { ...asBucket(block.style), ...patchedStyle } : asBucket(block.style);
|
|
310
|
-
const advanced = patchedAdvanced ? { ...asBucket(block.advanced), ...patchedAdvanced } : asBucket(block.advanced);
|
|
311
|
-
return /* @__PURE__ */ jsx(
|
|
435
|
+
const blockError = readBlockError(data);
|
|
436
|
+
const wrap = (children, hidden = false) => /* @__PURE__ */ jsx(
|
|
312
437
|
"div",
|
|
313
438
|
{
|
|
314
439
|
"data-block-id": block.id,
|
|
315
440
|
"data-block-type": block.type,
|
|
316
441
|
"data-layout-position": layoutPosition,
|
|
317
442
|
draggable: editable || void 0,
|
|
318
|
-
style:
|
|
319
|
-
children
|
|
320
|
-
content,
|
|
321
|
-
style,
|
|
322
|
-
advanced,
|
|
323
|
-
context,
|
|
324
|
-
data
|
|
325
|
-
}) : /* @__PURE__ */ jsx(UnknownBlock, { type: block.type })
|
|
443
|
+
style: hidden ? { display: "none" } : void 0,
|
|
444
|
+
children
|
|
326
445
|
}
|
|
327
446
|
);
|
|
447
|
+
if (!Component) {
|
|
448
|
+
return inEditMode ? wrap(
|
|
449
|
+
/* @__PURE__ */ jsx(
|
|
450
|
+
BlockErrorCard,
|
|
451
|
+
{
|
|
452
|
+
blockType: block.type,
|
|
453
|
+
blockId: block.id,
|
|
454
|
+
error: unregisteredBlockError(block.type)
|
|
455
|
+
}
|
|
456
|
+
)
|
|
457
|
+
) : wrap(/* @__PURE__ */ jsx(UnknownBlock, { type: block.type }), true);
|
|
458
|
+
}
|
|
459
|
+
if (blockError) {
|
|
460
|
+
if (!inEditMode) return null;
|
|
461
|
+
return wrap(
|
|
462
|
+
/* @__PURE__ */ jsx(
|
|
463
|
+
BlockErrorCard,
|
|
464
|
+
{
|
|
465
|
+
blockType: block.type,
|
|
466
|
+
blockId: block.id,
|
|
467
|
+
error: blockError
|
|
468
|
+
}
|
|
469
|
+
)
|
|
470
|
+
);
|
|
471
|
+
}
|
|
472
|
+
const base = getBlockContentForLanguage(block.content, locale, defaultLocale);
|
|
473
|
+
const content = patchedContent ? { ...base, ...patchedContent } : base;
|
|
474
|
+
const style = patchedStyle ? { ...asBucket(block.style), ...patchedStyle } : asBucket(block.style);
|
|
475
|
+
const advanced = patchedAdvanced ? { ...asBucket(block.advanced), ...patchedAdvanced } : asBucket(block.advanced);
|
|
476
|
+
return wrap(
|
|
477
|
+
/* @__PURE__ */ jsx(
|
|
478
|
+
BlockErrorBoundary,
|
|
479
|
+
{
|
|
480
|
+
blockType: block.type,
|
|
481
|
+
blockId: block.id,
|
|
482
|
+
editMode: inEditMode,
|
|
483
|
+
children: createElement(Component, {
|
|
484
|
+
content,
|
|
485
|
+
style,
|
|
486
|
+
advanced,
|
|
487
|
+
context,
|
|
488
|
+
data
|
|
489
|
+
})
|
|
490
|
+
}
|
|
491
|
+
)
|
|
492
|
+
);
|
|
328
493
|
}
|
|
329
494
|
|
|
330
495
|
export { CmssyBlock, CmssyServerLayout, CmssyServerPage, UnknownBlock, blocksToMeta, blocksToSchemas, buildBlockMap, defineBlock, resolveBlockData, resolveLayoutBlockData };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cmssy/react",
|
|
3
|
-
"version": "9.
|
|
3
|
+
"version": "9.3.0",
|
|
4
4
|
"description": "React blocks, renderers, data client and editor bridge for cmssy headless sites",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cmssy",
|
|
@@ -32,6 +32,11 @@
|
|
|
32
32
|
"types": "./dist/client.d.ts",
|
|
33
33
|
"import": "./dist/client.js",
|
|
34
34
|
"require": "./dist/client.cjs"
|
|
35
|
+
},
|
|
36
|
+
"./block-error-boundary": {
|
|
37
|
+
"types": "./dist/block-error-boundary.d.ts",
|
|
38
|
+
"import": "./dist/block-error-boundary.js",
|
|
39
|
+
"require": "./dist/block-error-boundary.cjs"
|
|
35
40
|
}
|
|
36
41
|
},
|
|
37
42
|
"main": "./dist/index.cjs",
|
|
@@ -57,7 +62,7 @@
|
|
|
57
62
|
},
|
|
58
63
|
"dependencies": {
|
|
59
64
|
"@cmssy/types": "0.28.0",
|
|
60
|
-
"@cmssy/core": "9.
|
|
65
|
+
"@cmssy/core": "9.3.0"
|
|
61
66
|
},
|
|
62
67
|
"scripts": {
|
|
63
68
|
"build": "tsup",
|