@cmssy/react 0.1.6 → 0.1.8
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/client.d.cts +1 -1
- package/dist/client.d.ts +1 -1
- package/dist/index.cjs +105 -20
- package/dist/index.d.cts +19 -4
- package/dist/index.d.ts +19 -4
- package/dist/index.js +104 -21
- package/dist/{registry-BaFQ2k7r.d.cts → registry-e3O4s_bN.d.cts} +23 -1
- package/dist/{registry-BaFQ2k7r.d.ts → registry-e3O4s_bN.d.ts} +23 -1
- package/package.json +1 -1
package/dist/client.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
-
import { B as BlockSchema, a as BlockMeta, C as CmssyPageData, b as BlockDefinition, c as CmssyFormDefinition, d as CmssyLayoutGroup } from './registry-
|
|
2
|
+
import { B as BlockSchema, a as BlockMeta, C as CmssyPageData, b as BlockDefinition, c as CmssyFormDefinition, d as CmssyLayoutGroup } from './registry-e3O4s_bN.cjs';
|
|
3
3
|
import 'react';
|
|
4
4
|
|
|
5
5
|
interface EditBridgeConfig {
|
package/dist/client.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
-
import { B as BlockSchema, a as BlockMeta, C as CmssyPageData, b as BlockDefinition, c as CmssyFormDefinition, d as CmssyLayoutGroup } from './registry-
|
|
2
|
+
import { B as BlockSchema, a as BlockMeta, C as CmssyPageData, b as BlockDefinition, c as CmssyFormDefinition, d as CmssyLayoutGroup } from './registry-e3O4s_bN.js';
|
|
3
3
|
import 'react';
|
|
4
4
|
|
|
5
5
|
interface EditBridgeConfig {
|
package/dist/index.cjs
CHANGED
|
@@ -35,6 +35,13 @@ function buildBlockMap(blocks) {
|
|
|
35
35
|
for (const block of blocks) map[block.type] = block.component;
|
|
36
36
|
return map;
|
|
37
37
|
}
|
|
38
|
+
function buildLoaderMap(blocks) {
|
|
39
|
+
const map = /* @__PURE__ */ Object.create(null);
|
|
40
|
+
for (const block of blocks) {
|
|
41
|
+
if (block.loader) map[block.type] = block.loader;
|
|
42
|
+
}
|
|
43
|
+
return map;
|
|
44
|
+
}
|
|
38
45
|
function blocksToSchemas(blocks) {
|
|
39
46
|
const out = /* @__PURE__ */ Object.create(null);
|
|
40
47
|
for (const block of blocks) {
|
|
@@ -60,19 +67,6 @@ function blocksToMeta(blocks, defaults = {}) {
|
|
|
60
67
|
return out;
|
|
61
68
|
}
|
|
62
69
|
|
|
63
|
-
// src/components/block-context.ts
|
|
64
|
-
function buildBlockContext(locale, defaultLocale, enabledLocales, isPreview, forms) {
|
|
65
|
-
return {
|
|
66
|
-
locale: {
|
|
67
|
-
current: locale,
|
|
68
|
-
default: defaultLocale,
|
|
69
|
-
enabled: enabledLocales && enabledLocales.length > 0 ? enabledLocales : Array.from(/* @__PURE__ */ new Set([defaultLocale, locale]))
|
|
70
|
-
},
|
|
71
|
-
isPreview: isPreview ?? false,
|
|
72
|
-
forms
|
|
73
|
-
};
|
|
74
|
-
}
|
|
75
|
-
|
|
76
70
|
// src/content/get-block-content.ts
|
|
77
71
|
function isPlainObject(value) {
|
|
78
72
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -96,6 +90,19 @@ function getBlockContentForLanguage(content, locale, defaultLocale = "en", avail
|
|
|
96
90
|
const chosen = localeMap[locale] ?? localeMap[defaultLocale] ?? localeMap[fallbackKey];
|
|
97
91
|
return { ...nonTranslatable, ...chosen };
|
|
98
92
|
}
|
|
93
|
+
|
|
94
|
+
// src/components/block-context.ts
|
|
95
|
+
function buildBlockContext(locale, defaultLocale, enabledLocales, isPreview, forms) {
|
|
96
|
+
return {
|
|
97
|
+
locale: {
|
|
98
|
+
current: locale,
|
|
99
|
+
default: defaultLocale,
|
|
100
|
+
enabled: enabledLocales && enabledLocales.length > 0 ? enabledLocales : Array.from(/* @__PURE__ */ new Set([defaultLocale, locale]))
|
|
101
|
+
},
|
|
102
|
+
isPreview: isPreview ?? false,
|
|
103
|
+
forms
|
|
104
|
+
};
|
|
105
|
+
}
|
|
99
106
|
var WARN_CAP = 256;
|
|
100
107
|
var warned = /* @__PURE__ */ new Set();
|
|
101
108
|
function UnknownBlock({ type }) {
|
|
@@ -106,12 +113,14 @@ function UnknownBlock({ type }) {
|
|
|
106
113
|
}
|
|
107
114
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { "data-cmssy-unknown-block": type });
|
|
108
115
|
}
|
|
109
|
-
function renderResolvedBlock(block, map, locale, defaultLocale,
|
|
116
|
+
function renderResolvedBlock(block, map, locale, defaultLocale, options = {}) {
|
|
117
|
+
const { context, data, resolvedContent, enabledLocales } = options;
|
|
110
118
|
const Component = Object.hasOwn(map, block.type) ? map[block.type] : void 0;
|
|
111
|
-
const content = getBlockContentForLanguage(
|
|
119
|
+
const content = resolvedContent ?? getBlockContentForLanguage(
|
|
112
120
|
block.content,
|
|
113
121
|
locale,
|
|
114
|
-
defaultLocale
|
|
122
|
+
defaultLocale,
|
|
123
|
+
enabledLocales?.length ? enabledLocales : void 0
|
|
115
124
|
);
|
|
116
125
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
117
126
|
"div",
|
|
@@ -119,12 +128,12 @@ function renderResolvedBlock(block, map, locale, defaultLocale, context) {
|
|
|
119
128
|
"data-block-id": block.id,
|
|
120
129
|
"data-block-type": block.type,
|
|
121
130
|
style: Component ? void 0 : { display: "none" },
|
|
122
|
-
children: Component ? react.createElement(Component, { content, context }) : /* @__PURE__ */ jsxRuntime.jsx(UnknownBlock, { type: block.type })
|
|
131
|
+
children: Component ? react.createElement(Component, { content, context, data }) : /* @__PURE__ */ jsxRuntime.jsx(UnknownBlock, { type: block.type })
|
|
123
132
|
},
|
|
124
133
|
block.id
|
|
125
134
|
);
|
|
126
135
|
}
|
|
127
|
-
function CmssyServerPage({
|
|
136
|
+
async function CmssyServerPage({
|
|
128
137
|
page,
|
|
129
138
|
blocks,
|
|
130
139
|
locale = "en",
|
|
@@ -134,6 +143,7 @@ function CmssyServerPage({
|
|
|
134
143
|
}) {
|
|
135
144
|
if (!page) return null;
|
|
136
145
|
const map = buildBlockMap(blocks);
|
|
146
|
+
const loaderMap = buildLoaderMap(blocks);
|
|
137
147
|
const context = buildBlockContext(
|
|
138
148
|
locale,
|
|
139
149
|
defaultLocale,
|
|
@@ -141,8 +151,38 @@ function CmssyServerPage({
|
|
|
141
151
|
false,
|
|
142
152
|
forms
|
|
143
153
|
);
|
|
154
|
+
const resolved = await Promise.all(
|
|
155
|
+
page.blocks.map(async (block) => {
|
|
156
|
+
const content = getBlockContentForLanguage(
|
|
157
|
+
block.content,
|
|
158
|
+
locale,
|
|
159
|
+
defaultLocale,
|
|
160
|
+
enabledLocales?.length ? enabledLocales : void 0
|
|
161
|
+
);
|
|
162
|
+
const loader = loaderMap[block.type];
|
|
163
|
+
let data;
|
|
164
|
+
if (loader) {
|
|
165
|
+
try {
|
|
166
|
+
data = await loader({ content, context });
|
|
167
|
+
} catch (err) {
|
|
168
|
+
if (typeof console !== "undefined") {
|
|
169
|
+
console.warn(
|
|
170
|
+
`[cmssy] loader for block "${block.type}" (${block.id}) failed`,
|
|
171
|
+
err
|
|
172
|
+
);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
return { content, data };
|
|
177
|
+
})
|
|
178
|
+
);
|
|
144
179
|
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: page.blocks.map(
|
|
145
|
-
(block) => renderResolvedBlock(block, map, locale, defaultLocale,
|
|
180
|
+
(block, i) => renderResolvedBlock(block, map, locale, defaultLocale, {
|
|
181
|
+
context,
|
|
182
|
+
data: resolved[i]?.data,
|
|
183
|
+
resolvedContent: resolved[i]?.content,
|
|
184
|
+
enabledLocales
|
|
185
|
+
})
|
|
146
186
|
) });
|
|
147
187
|
}
|
|
148
188
|
function CmssyServerLayout({
|
|
@@ -159,7 +199,10 @@ function CmssyServerLayout({
|
|
|
159
199
|
const map = buildBlockMap(blocks);
|
|
160
200
|
const context = buildBlockContext(locale, defaultLocale, enabledLocales);
|
|
161
201
|
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: layoutBlocks.map(
|
|
162
|
-
(block) => renderResolvedBlock(block, map, locale, defaultLocale,
|
|
202
|
+
(block) => renderResolvedBlock(block, map, locale, defaultLocale, {
|
|
203
|
+
context,
|
|
204
|
+
enabledLocales
|
|
205
|
+
})
|
|
163
206
|
) });
|
|
164
207
|
}
|
|
165
208
|
|
|
@@ -547,6 +590,46 @@ async function resolveForms(config, blocks, locale, defaultLocale, options) {
|
|
|
547
590
|
}
|
|
548
591
|
return forms;
|
|
549
592
|
}
|
|
593
|
+
|
|
594
|
+
// src/data/site-locales.ts
|
|
595
|
+
var TTL_MS = 6e4;
|
|
596
|
+
var MAX_ENTRIES = 64;
|
|
597
|
+
var cache = /* @__PURE__ */ new Map();
|
|
598
|
+
async function resolveSiteLocales(config, options) {
|
|
599
|
+
const key = `${config.apiUrl}::${config.workspaceSlug}`;
|
|
600
|
+
const cached = cache.get(key);
|
|
601
|
+
if (cached && cached.expires > Date.now()) return cached.value;
|
|
602
|
+
cache.delete(key);
|
|
603
|
+
let value;
|
|
604
|
+
try {
|
|
605
|
+
const data = await graphqlRequest(
|
|
606
|
+
config,
|
|
607
|
+
SITE_CONFIG_QUERY,
|
|
608
|
+
{ workspaceSlug: config.workspaceSlug },
|
|
609
|
+
options,
|
|
610
|
+
"site config"
|
|
611
|
+
);
|
|
612
|
+
const siteConfig = data.publicSiteConfig;
|
|
613
|
+
const defaultLocale = siteConfig?.defaultLanguage || "en";
|
|
614
|
+
const enabled = siteConfig?.enabledLanguages ?? [];
|
|
615
|
+
value = {
|
|
616
|
+
defaultLocale,
|
|
617
|
+
locales: enabled.length > 0 ? enabled : [defaultLocale]
|
|
618
|
+
};
|
|
619
|
+
} catch {
|
|
620
|
+
value = { defaultLocale: "en", locales: ["en"] };
|
|
621
|
+
}
|
|
622
|
+
if (cache.size >= MAX_ENTRIES) cache.clear();
|
|
623
|
+
cache.set(key, { value, expires: Date.now() + TTL_MS });
|
|
624
|
+
return value;
|
|
625
|
+
}
|
|
626
|
+
function splitLocaleFromPath(path, siteLocales) {
|
|
627
|
+
const first = path?.[0];
|
|
628
|
+
if (first && first !== siteLocales.defaultLocale && siteLocales.locales.includes(first)) {
|
|
629
|
+
return { locale: first, path: path.slice(1) };
|
|
630
|
+
}
|
|
631
|
+
return { locale: siteLocales.defaultLocale, path };
|
|
632
|
+
}
|
|
550
633
|
function CmssyBlock({
|
|
551
634
|
block,
|
|
552
635
|
locale,
|
|
@@ -601,3 +684,5 @@ exports.normalizeSlug = normalizeSlug;
|
|
|
601
684
|
exports.parseEditorMessage = parseEditorMessage;
|
|
602
685
|
exports.postToEditor = postToEditor;
|
|
603
686
|
exports.resolveForms = resolveForms;
|
|
687
|
+
exports.resolveSiteLocales = resolveSiteLocales;
|
|
688
|
+
exports.splitLocaleFromPath = splitLocaleFromPath;
|
package/dist/index.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { F as FieldDefinition, C as CmssyPageData, b as BlockDefinition, c as CmssyFormDefinition, d as CmssyLayoutGroup, E as EditorToAppMessage, A as AppToEditorMessage, e as FetchLike, f as CmssyClientConfig, R as RawBlock, g as BlockMap, h as CmssyBlockContext } from './registry-
|
|
2
|
-
export { a as BlockMeta, i as BlockRect, B as BlockSchema, j as BoundsMessage, k as ClickMessage, l as CmssyBranding, m as CmssyFormField, n as CmssyFormSettings, o as CmssyFormSubmitResponse, p as CmssyLocaleContext, q as CmssyModelDefinition, r as CmssyModelRecord, s as CmssyRecordList, t as CmssySiteConfig, u as FORM_QUERY, v as FetchLikeResponse, w as FetchPageOptions, x as FieldType, M as MODEL_DEFINITIONS_QUERY, y as MODEL_RECORDS_QUERY, P as PROTOCOL_VERSION, z as ParentReadyMessage, D as PatchMessage, G as RawLayoutBlock, H as ReadyMessage, S as SITE_CONFIG_QUERY, I as SUBMIT_FORM_MUTATION, J as SelectMessage, K as SubmitFormInput, L as blocksToMeta, N as blocksToSchemas, O as buildBlockContext, Q as buildBlockMap, T as defineBlock, U as fetchLayouts, V as fetchPage, W as isProtocolCompatible, X as normalizeSlug } from './registry-
|
|
1
|
+
import { F as FieldDefinition, C as CmssyPageData, b as BlockDefinition, c as CmssyFormDefinition, d as CmssyLayoutGroup, E as EditorToAppMessage, A as AppToEditorMessage, e as FetchLike, f as CmssyClientConfig, R as RawBlock, g as BlockMap, h as CmssyBlockContext } from './registry-e3O4s_bN.cjs';
|
|
2
|
+
export { a as BlockMeta, i as BlockRect, B as BlockSchema, j as BoundsMessage, k as ClickMessage, l as CmssyBranding, m as CmssyFormField, n as CmssyFormSettings, o as CmssyFormSubmitResponse, p as CmssyLocaleContext, q as CmssyModelDefinition, r as CmssyModelRecord, s as CmssyRecordList, t as CmssySiteConfig, u as FORM_QUERY, v as FetchLikeResponse, w as FetchPageOptions, x as FieldType, M as MODEL_DEFINITIONS_QUERY, y as MODEL_RECORDS_QUERY, P as PROTOCOL_VERSION, z as ParentReadyMessage, D as PatchMessage, G as RawLayoutBlock, H as ReadyMessage, S as SITE_CONFIG_QUERY, I as SUBMIT_FORM_MUTATION, J as SelectMessage, K as SubmitFormInput, L as blocksToMeta, N as blocksToSchemas, O as buildBlockContext, Q as buildBlockMap, T as defineBlock, U as fetchLayouts, V as fetchPage, W as isProtocolCompatible, X as normalizeSlug } from './registry-e3O4s_bN.cjs';
|
|
3
3
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
4
4
|
import 'react';
|
|
5
5
|
|
|
@@ -31,7 +31,12 @@ interface CmssyServerPageProps {
|
|
|
31
31
|
/** Form definitions referenced by page blocks, exposed via context.forms. */
|
|
32
32
|
forms?: Record<string, CmssyFormDefinition>;
|
|
33
33
|
}
|
|
34
|
-
|
|
34
|
+
/**
|
|
35
|
+
* Async React Server Component (Next.js App Router / RSC). It runs each block's
|
|
36
|
+
* loader server-side before rendering, so it must be rendered in a server
|
|
37
|
+
* component tree (as `createCmssyPage` does) - not in a client component.
|
|
38
|
+
*/
|
|
39
|
+
declare function CmssyServerPage({ page, blocks, locale, defaultLocale, enabledLocales, forms, }: CmssyServerPageProps): Promise<react_jsx_runtime.JSX.Element | null>;
|
|
35
40
|
|
|
36
41
|
interface CmssyServerLayoutProps {
|
|
37
42
|
groups: CmssyLayoutGroup[];
|
|
@@ -74,6 +79,16 @@ declare function createCmssyClient(config: CmssyClientConfig): CmssyClient;
|
|
|
74
79
|
declare function collectFormIds(blocks: RawBlock[], locale: string, defaultLocale: string): string[];
|
|
75
80
|
declare function resolveForms(config: CmssyClientConfig, blocks: RawBlock[], locale: string, defaultLocale: string, options?: QueryScopedOptions): Promise<Record<string, CmssyFormDefinition>>;
|
|
76
81
|
|
|
82
|
+
interface CmssySiteLocales {
|
|
83
|
+
defaultLocale: string;
|
|
84
|
+
locales: string[];
|
|
85
|
+
}
|
|
86
|
+
declare function resolveSiteLocales(config: CmssyClientConfig, options?: GraphqlRequestOptions): Promise<CmssySiteLocales>;
|
|
87
|
+
declare function splitLocaleFromPath(path: string[] | undefined, siteLocales: CmssySiteLocales): {
|
|
88
|
+
locale: string;
|
|
89
|
+
path: string[] | undefined;
|
|
90
|
+
};
|
|
91
|
+
|
|
77
92
|
interface CmssyBlockProps {
|
|
78
93
|
block: RawBlock;
|
|
79
94
|
locale: string;
|
|
@@ -91,4 +106,4 @@ interface UnknownBlockProps {
|
|
|
91
106
|
}
|
|
92
107
|
declare function UnknownBlock({ type }: UnknownBlockProps): react_jsx_runtime.JSX.Element;
|
|
93
108
|
|
|
94
|
-
export { AppToEditorMessage, BlockDefinition, BlockMap, CmssyBlock, CmssyBlockContext, type CmssyBlockProps, type CmssyClient, CmssyClientConfig, CmssyFormDefinition, CmssyLayoutGroup, CmssyPageData, CmssyServerLayout, type CmssyServerLayoutProps, CmssyServerPage, type CmssyServerPageProps, EditorToAppMessage, FetchLike, type FieldControl, FieldDefinition, type GraphqlRequestOptions, type PostTarget, type QueryScopedOptions, RawBlock, UnknownBlock, type UnknownBlockProps, collectFormIds, createCmssyClient, fields, getBlockContentForLanguage, graphqlRequest, normalizeOrigin, parseEditorMessage, postToEditor, resolveForms };
|
|
109
|
+
export { AppToEditorMessage, BlockDefinition, BlockMap, CmssyBlock, CmssyBlockContext, type CmssyBlockProps, type CmssyClient, CmssyClientConfig, CmssyFormDefinition, CmssyLayoutGroup, CmssyPageData, CmssyServerLayout, type CmssyServerLayoutProps, CmssyServerPage, type CmssyServerPageProps, type CmssySiteLocales, EditorToAppMessage, FetchLike, type FieldControl, FieldDefinition, type GraphqlRequestOptions, type PostTarget, type QueryScopedOptions, RawBlock, UnknownBlock, type UnknownBlockProps, collectFormIds, createCmssyClient, fields, getBlockContentForLanguage, graphqlRequest, normalizeOrigin, parseEditorMessage, postToEditor, resolveForms, resolveSiteLocales, splitLocaleFromPath };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { F as FieldDefinition, C as CmssyPageData, b as BlockDefinition, c as CmssyFormDefinition, d as CmssyLayoutGroup, E as EditorToAppMessage, A as AppToEditorMessage, e as FetchLike, f as CmssyClientConfig, R as RawBlock, g as BlockMap, h as CmssyBlockContext } from './registry-
|
|
2
|
-
export { a as BlockMeta, i as BlockRect, B as BlockSchema, j as BoundsMessage, k as ClickMessage, l as CmssyBranding, m as CmssyFormField, n as CmssyFormSettings, o as CmssyFormSubmitResponse, p as CmssyLocaleContext, q as CmssyModelDefinition, r as CmssyModelRecord, s as CmssyRecordList, t as CmssySiteConfig, u as FORM_QUERY, v as FetchLikeResponse, w as FetchPageOptions, x as FieldType, M as MODEL_DEFINITIONS_QUERY, y as MODEL_RECORDS_QUERY, P as PROTOCOL_VERSION, z as ParentReadyMessage, D as PatchMessage, G as RawLayoutBlock, H as ReadyMessage, S as SITE_CONFIG_QUERY, I as SUBMIT_FORM_MUTATION, J as SelectMessage, K as SubmitFormInput, L as blocksToMeta, N as blocksToSchemas, O as buildBlockContext, Q as buildBlockMap, T as defineBlock, U as fetchLayouts, V as fetchPage, W as isProtocolCompatible, X as normalizeSlug } from './registry-
|
|
1
|
+
import { F as FieldDefinition, C as CmssyPageData, b as BlockDefinition, c as CmssyFormDefinition, d as CmssyLayoutGroup, E as EditorToAppMessage, A as AppToEditorMessage, e as FetchLike, f as CmssyClientConfig, R as RawBlock, g as BlockMap, h as CmssyBlockContext } from './registry-e3O4s_bN.js';
|
|
2
|
+
export { a as BlockMeta, i as BlockRect, B as BlockSchema, j as BoundsMessage, k as ClickMessage, l as CmssyBranding, m as CmssyFormField, n as CmssyFormSettings, o as CmssyFormSubmitResponse, p as CmssyLocaleContext, q as CmssyModelDefinition, r as CmssyModelRecord, s as CmssyRecordList, t as CmssySiteConfig, u as FORM_QUERY, v as FetchLikeResponse, w as FetchPageOptions, x as FieldType, M as MODEL_DEFINITIONS_QUERY, y as MODEL_RECORDS_QUERY, P as PROTOCOL_VERSION, z as ParentReadyMessage, D as PatchMessage, G as RawLayoutBlock, H as ReadyMessage, S as SITE_CONFIG_QUERY, I as SUBMIT_FORM_MUTATION, J as SelectMessage, K as SubmitFormInput, L as blocksToMeta, N as blocksToSchemas, O as buildBlockContext, Q as buildBlockMap, T as defineBlock, U as fetchLayouts, V as fetchPage, W as isProtocolCompatible, X as normalizeSlug } from './registry-e3O4s_bN.js';
|
|
3
3
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
4
4
|
import 'react';
|
|
5
5
|
|
|
@@ -31,7 +31,12 @@ interface CmssyServerPageProps {
|
|
|
31
31
|
/** Form definitions referenced by page blocks, exposed via context.forms. */
|
|
32
32
|
forms?: Record<string, CmssyFormDefinition>;
|
|
33
33
|
}
|
|
34
|
-
|
|
34
|
+
/**
|
|
35
|
+
* Async React Server Component (Next.js App Router / RSC). It runs each block's
|
|
36
|
+
* loader server-side before rendering, so it must be rendered in a server
|
|
37
|
+
* component tree (as `createCmssyPage` does) - not in a client component.
|
|
38
|
+
*/
|
|
39
|
+
declare function CmssyServerPage({ page, blocks, locale, defaultLocale, enabledLocales, forms, }: CmssyServerPageProps): Promise<react_jsx_runtime.JSX.Element | null>;
|
|
35
40
|
|
|
36
41
|
interface CmssyServerLayoutProps {
|
|
37
42
|
groups: CmssyLayoutGroup[];
|
|
@@ -74,6 +79,16 @@ declare function createCmssyClient(config: CmssyClientConfig): CmssyClient;
|
|
|
74
79
|
declare function collectFormIds(blocks: RawBlock[], locale: string, defaultLocale: string): string[];
|
|
75
80
|
declare function resolveForms(config: CmssyClientConfig, blocks: RawBlock[], locale: string, defaultLocale: string, options?: QueryScopedOptions): Promise<Record<string, CmssyFormDefinition>>;
|
|
76
81
|
|
|
82
|
+
interface CmssySiteLocales {
|
|
83
|
+
defaultLocale: string;
|
|
84
|
+
locales: string[];
|
|
85
|
+
}
|
|
86
|
+
declare function resolveSiteLocales(config: CmssyClientConfig, options?: GraphqlRequestOptions): Promise<CmssySiteLocales>;
|
|
87
|
+
declare function splitLocaleFromPath(path: string[] | undefined, siteLocales: CmssySiteLocales): {
|
|
88
|
+
locale: string;
|
|
89
|
+
path: string[] | undefined;
|
|
90
|
+
};
|
|
91
|
+
|
|
77
92
|
interface CmssyBlockProps {
|
|
78
93
|
block: RawBlock;
|
|
79
94
|
locale: string;
|
|
@@ -91,4 +106,4 @@ interface UnknownBlockProps {
|
|
|
91
106
|
}
|
|
92
107
|
declare function UnknownBlock({ type }: UnknownBlockProps): react_jsx_runtime.JSX.Element;
|
|
93
108
|
|
|
94
|
-
export { AppToEditorMessage, BlockDefinition, BlockMap, CmssyBlock, CmssyBlockContext, type CmssyBlockProps, type CmssyClient, CmssyClientConfig, CmssyFormDefinition, CmssyLayoutGroup, CmssyPageData, CmssyServerLayout, type CmssyServerLayoutProps, CmssyServerPage, type CmssyServerPageProps, EditorToAppMessage, FetchLike, type FieldControl, FieldDefinition, type GraphqlRequestOptions, type PostTarget, type QueryScopedOptions, RawBlock, UnknownBlock, type UnknownBlockProps, collectFormIds, createCmssyClient, fields, getBlockContentForLanguage, graphqlRequest, normalizeOrigin, parseEditorMessage, postToEditor, resolveForms };
|
|
109
|
+
export { AppToEditorMessage, BlockDefinition, BlockMap, CmssyBlock, CmssyBlockContext, type CmssyBlockProps, type CmssyClient, CmssyClientConfig, CmssyFormDefinition, CmssyLayoutGroup, CmssyPageData, CmssyServerLayout, type CmssyServerLayoutProps, CmssyServerPage, type CmssyServerPageProps, type CmssySiteLocales, EditorToAppMessage, FetchLike, type FieldControl, FieldDefinition, type GraphqlRequestOptions, type PostTarget, type QueryScopedOptions, RawBlock, UnknownBlock, type UnknownBlockProps, collectFormIds, createCmssyClient, fields, getBlockContentForLanguage, graphqlRequest, normalizeOrigin, parseEditorMessage, postToEditor, resolveForms, resolveSiteLocales, splitLocaleFromPath };
|
package/dist/index.js
CHANGED
|
@@ -33,6 +33,13 @@ function buildBlockMap(blocks) {
|
|
|
33
33
|
for (const block of blocks) map[block.type] = block.component;
|
|
34
34
|
return map;
|
|
35
35
|
}
|
|
36
|
+
function buildLoaderMap(blocks) {
|
|
37
|
+
const map = /* @__PURE__ */ Object.create(null);
|
|
38
|
+
for (const block of blocks) {
|
|
39
|
+
if (block.loader) map[block.type] = block.loader;
|
|
40
|
+
}
|
|
41
|
+
return map;
|
|
42
|
+
}
|
|
36
43
|
function blocksToSchemas(blocks) {
|
|
37
44
|
const out = /* @__PURE__ */ Object.create(null);
|
|
38
45
|
for (const block of blocks) {
|
|
@@ -58,19 +65,6 @@ function blocksToMeta(blocks, defaults = {}) {
|
|
|
58
65
|
return out;
|
|
59
66
|
}
|
|
60
67
|
|
|
61
|
-
// src/components/block-context.ts
|
|
62
|
-
function buildBlockContext(locale, defaultLocale, enabledLocales, isPreview, forms) {
|
|
63
|
-
return {
|
|
64
|
-
locale: {
|
|
65
|
-
current: locale,
|
|
66
|
-
default: defaultLocale,
|
|
67
|
-
enabled: enabledLocales && enabledLocales.length > 0 ? enabledLocales : Array.from(/* @__PURE__ */ new Set([defaultLocale, locale]))
|
|
68
|
-
},
|
|
69
|
-
isPreview: isPreview ?? false,
|
|
70
|
-
forms
|
|
71
|
-
};
|
|
72
|
-
}
|
|
73
|
-
|
|
74
68
|
// src/content/get-block-content.ts
|
|
75
69
|
function isPlainObject(value) {
|
|
76
70
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -94,6 +88,19 @@ function getBlockContentForLanguage(content, locale, defaultLocale = "en", avail
|
|
|
94
88
|
const chosen = localeMap[locale] ?? localeMap[defaultLocale] ?? localeMap[fallbackKey];
|
|
95
89
|
return { ...nonTranslatable, ...chosen };
|
|
96
90
|
}
|
|
91
|
+
|
|
92
|
+
// src/components/block-context.ts
|
|
93
|
+
function buildBlockContext(locale, defaultLocale, enabledLocales, isPreview, forms) {
|
|
94
|
+
return {
|
|
95
|
+
locale: {
|
|
96
|
+
current: locale,
|
|
97
|
+
default: defaultLocale,
|
|
98
|
+
enabled: enabledLocales && enabledLocales.length > 0 ? enabledLocales : Array.from(/* @__PURE__ */ new Set([defaultLocale, locale]))
|
|
99
|
+
},
|
|
100
|
+
isPreview: isPreview ?? false,
|
|
101
|
+
forms
|
|
102
|
+
};
|
|
103
|
+
}
|
|
97
104
|
var WARN_CAP = 256;
|
|
98
105
|
var warned = /* @__PURE__ */ new Set();
|
|
99
106
|
function UnknownBlock({ type }) {
|
|
@@ -104,12 +111,14 @@ function UnknownBlock({ type }) {
|
|
|
104
111
|
}
|
|
105
112
|
return /* @__PURE__ */ jsx("div", { "data-cmssy-unknown-block": type });
|
|
106
113
|
}
|
|
107
|
-
function renderResolvedBlock(block, map, locale, defaultLocale,
|
|
114
|
+
function renderResolvedBlock(block, map, locale, defaultLocale, options = {}) {
|
|
115
|
+
const { context, data, resolvedContent, enabledLocales } = options;
|
|
108
116
|
const Component = Object.hasOwn(map, block.type) ? map[block.type] : void 0;
|
|
109
|
-
const content = getBlockContentForLanguage(
|
|
117
|
+
const content = resolvedContent ?? getBlockContentForLanguage(
|
|
110
118
|
block.content,
|
|
111
119
|
locale,
|
|
112
|
-
defaultLocale
|
|
120
|
+
defaultLocale,
|
|
121
|
+
enabledLocales?.length ? enabledLocales : void 0
|
|
113
122
|
);
|
|
114
123
|
return /* @__PURE__ */ jsx(
|
|
115
124
|
"div",
|
|
@@ -117,12 +126,12 @@ function renderResolvedBlock(block, map, locale, defaultLocale, context) {
|
|
|
117
126
|
"data-block-id": block.id,
|
|
118
127
|
"data-block-type": block.type,
|
|
119
128
|
style: Component ? void 0 : { display: "none" },
|
|
120
|
-
children: Component ? createElement(Component, { content, context }) : /* @__PURE__ */ jsx(UnknownBlock, { type: block.type })
|
|
129
|
+
children: Component ? createElement(Component, { content, context, data }) : /* @__PURE__ */ jsx(UnknownBlock, { type: block.type })
|
|
121
130
|
},
|
|
122
131
|
block.id
|
|
123
132
|
);
|
|
124
133
|
}
|
|
125
|
-
function CmssyServerPage({
|
|
134
|
+
async function CmssyServerPage({
|
|
126
135
|
page,
|
|
127
136
|
blocks,
|
|
128
137
|
locale = "en",
|
|
@@ -132,6 +141,7 @@ function CmssyServerPage({
|
|
|
132
141
|
}) {
|
|
133
142
|
if (!page) return null;
|
|
134
143
|
const map = buildBlockMap(blocks);
|
|
144
|
+
const loaderMap = buildLoaderMap(blocks);
|
|
135
145
|
const context = buildBlockContext(
|
|
136
146
|
locale,
|
|
137
147
|
defaultLocale,
|
|
@@ -139,8 +149,38 @@ function CmssyServerPage({
|
|
|
139
149
|
false,
|
|
140
150
|
forms
|
|
141
151
|
);
|
|
152
|
+
const resolved = await Promise.all(
|
|
153
|
+
page.blocks.map(async (block) => {
|
|
154
|
+
const content = getBlockContentForLanguage(
|
|
155
|
+
block.content,
|
|
156
|
+
locale,
|
|
157
|
+
defaultLocale,
|
|
158
|
+
enabledLocales?.length ? enabledLocales : void 0
|
|
159
|
+
);
|
|
160
|
+
const loader = loaderMap[block.type];
|
|
161
|
+
let data;
|
|
162
|
+
if (loader) {
|
|
163
|
+
try {
|
|
164
|
+
data = await loader({ content, context });
|
|
165
|
+
} catch (err) {
|
|
166
|
+
if (typeof console !== "undefined") {
|
|
167
|
+
console.warn(
|
|
168
|
+
`[cmssy] loader for block "${block.type}" (${block.id}) failed`,
|
|
169
|
+
err
|
|
170
|
+
);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
return { content, data };
|
|
175
|
+
})
|
|
176
|
+
);
|
|
142
177
|
return /* @__PURE__ */ jsx(Fragment, { children: page.blocks.map(
|
|
143
|
-
(block) => renderResolvedBlock(block, map, locale, defaultLocale,
|
|
178
|
+
(block, i) => renderResolvedBlock(block, map, locale, defaultLocale, {
|
|
179
|
+
context,
|
|
180
|
+
data: resolved[i]?.data,
|
|
181
|
+
resolvedContent: resolved[i]?.content,
|
|
182
|
+
enabledLocales
|
|
183
|
+
})
|
|
144
184
|
) });
|
|
145
185
|
}
|
|
146
186
|
function CmssyServerLayout({
|
|
@@ -157,7 +197,10 @@ function CmssyServerLayout({
|
|
|
157
197
|
const map = buildBlockMap(blocks);
|
|
158
198
|
const context = buildBlockContext(locale, defaultLocale, enabledLocales);
|
|
159
199
|
return /* @__PURE__ */ jsx(Fragment, { children: layoutBlocks.map(
|
|
160
|
-
(block) => renderResolvedBlock(block, map, locale, defaultLocale,
|
|
200
|
+
(block) => renderResolvedBlock(block, map, locale, defaultLocale, {
|
|
201
|
+
context,
|
|
202
|
+
enabledLocales
|
|
203
|
+
})
|
|
161
204
|
) });
|
|
162
205
|
}
|
|
163
206
|
|
|
@@ -545,6 +588,46 @@ async function resolveForms(config, blocks, locale, defaultLocale, options) {
|
|
|
545
588
|
}
|
|
546
589
|
return forms;
|
|
547
590
|
}
|
|
591
|
+
|
|
592
|
+
// src/data/site-locales.ts
|
|
593
|
+
var TTL_MS = 6e4;
|
|
594
|
+
var MAX_ENTRIES = 64;
|
|
595
|
+
var cache = /* @__PURE__ */ new Map();
|
|
596
|
+
async function resolveSiteLocales(config, options) {
|
|
597
|
+
const key = `${config.apiUrl}::${config.workspaceSlug}`;
|
|
598
|
+
const cached = cache.get(key);
|
|
599
|
+
if (cached && cached.expires > Date.now()) return cached.value;
|
|
600
|
+
cache.delete(key);
|
|
601
|
+
let value;
|
|
602
|
+
try {
|
|
603
|
+
const data = await graphqlRequest(
|
|
604
|
+
config,
|
|
605
|
+
SITE_CONFIG_QUERY,
|
|
606
|
+
{ workspaceSlug: config.workspaceSlug },
|
|
607
|
+
options,
|
|
608
|
+
"site config"
|
|
609
|
+
);
|
|
610
|
+
const siteConfig = data.publicSiteConfig;
|
|
611
|
+
const defaultLocale = siteConfig?.defaultLanguage || "en";
|
|
612
|
+
const enabled = siteConfig?.enabledLanguages ?? [];
|
|
613
|
+
value = {
|
|
614
|
+
defaultLocale,
|
|
615
|
+
locales: enabled.length > 0 ? enabled : [defaultLocale]
|
|
616
|
+
};
|
|
617
|
+
} catch {
|
|
618
|
+
value = { defaultLocale: "en", locales: ["en"] };
|
|
619
|
+
}
|
|
620
|
+
if (cache.size >= MAX_ENTRIES) cache.clear();
|
|
621
|
+
cache.set(key, { value, expires: Date.now() + TTL_MS });
|
|
622
|
+
return value;
|
|
623
|
+
}
|
|
624
|
+
function splitLocaleFromPath(path, siteLocales) {
|
|
625
|
+
const first = path?.[0];
|
|
626
|
+
if (first && first !== siteLocales.defaultLocale && siteLocales.locales.includes(first)) {
|
|
627
|
+
return { locale: first, path: path.slice(1) };
|
|
628
|
+
}
|
|
629
|
+
return { locale: siteLocales.defaultLocale, path };
|
|
630
|
+
}
|
|
548
631
|
function CmssyBlock({
|
|
549
632
|
block,
|
|
550
633
|
locale,
|
|
@@ -571,4 +654,4 @@ function CmssyBlock({
|
|
|
571
654
|
);
|
|
572
655
|
}
|
|
573
656
|
|
|
574
|
-
export { CmssyBlock, CmssyServerLayout, CmssyServerPage, FORM_QUERY, MODEL_DEFINITIONS_QUERY, MODEL_RECORDS_QUERY, PROTOCOL_VERSION, SITE_CONFIG_QUERY, SUBMIT_FORM_MUTATION, UnknownBlock, blocksToMeta, blocksToSchemas, buildBlockContext, buildBlockMap, collectFormIds, createCmssyClient, defineBlock, fetchLayouts, fetchPage, fields, getBlockContentForLanguage, graphqlRequest, isProtocolCompatible, normalizeOrigin, normalizeSlug, parseEditorMessage, postToEditor, resolveForms };
|
|
657
|
+
export { CmssyBlock, CmssyServerLayout, CmssyServerPage, FORM_QUERY, MODEL_DEFINITIONS_QUERY, MODEL_RECORDS_QUERY, PROTOCOL_VERSION, SITE_CONFIG_QUERY, SUBMIT_FORM_MUTATION, UnknownBlock, blocksToMeta, blocksToSchemas, buildBlockContext, buildBlockMap, collectFormIds, createCmssyClient, defineBlock, fetchLayouts, fetchPage, fields, getBlockContentForLanguage, graphqlRequest, isProtocolCompatible, normalizeOrigin, normalizeSlug, parseEditorMessage, postToEditor, resolveForms, resolveSiteLocales, splitLocaleFromPath };
|
|
@@ -256,6 +256,11 @@ interface DragEndMessage {
|
|
|
256
256
|
type EditorToAppMessage = SelectMessage | PatchMessage | ParentReadyMessage | InsertMessage | ReorderMessage | RemoveMessage | DragOverMessage | DragEndMessage;
|
|
257
257
|
declare function isProtocolCompatible(version: number): boolean;
|
|
258
258
|
|
|
259
|
+
interface BlockLoaderArgs {
|
|
260
|
+
content: Record<string, unknown>;
|
|
261
|
+
context?: CmssyBlockContext;
|
|
262
|
+
}
|
|
263
|
+
type BlockLoader = (args: BlockLoaderArgs) => Promise<unknown> | unknown;
|
|
259
264
|
interface BlockDefinition {
|
|
260
265
|
type: string;
|
|
261
266
|
label?: string;
|
|
@@ -263,26 +268,43 @@ interface BlockDefinition {
|
|
|
263
268
|
icon?: string;
|
|
264
269
|
layoutPositions?: string[];
|
|
265
270
|
props: Record<string, FieldDefinition>;
|
|
271
|
+
/**
|
|
272
|
+
* Optional server-side data loader. Run by CmssyServerPage during SSR; its
|
|
273
|
+
* result is passed to the component as the `data` prop. Not run in the
|
|
274
|
+
* editor (the component receives `data: undefined` there).
|
|
275
|
+
*
|
|
276
|
+
* The result crosses the server→client boundary when the block component is a
|
|
277
|
+
* Client Component, so it must be RSC-serializable (plain objects, arrays and
|
|
278
|
+
* primitives - no functions, class instances, etc.).
|
|
279
|
+
*/
|
|
280
|
+
loader?: BlockLoader;
|
|
266
281
|
component: ComponentType<{
|
|
267
282
|
content: Record<string, unknown>;
|
|
268
283
|
context?: CmssyBlockContext;
|
|
284
|
+
data?: unknown;
|
|
269
285
|
}>;
|
|
270
286
|
}
|
|
271
|
-
declare function defineBlock<C extends Record<string, unknown
|
|
287
|
+
declare function defineBlock<C extends Record<string, unknown>, D = unknown>(def: {
|
|
272
288
|
type: string;
|
|
273
289
|
label?: string;
|
|
274
290
|
category?: string;
|
|
275
291
|
icon?: string;
|
|
276
292
|
layoutPositions?: string[];
|
|
277
293
|
props: Record<string, FieldDefinition>;
|
|
294
|
+
loader?: (args: {
|
|
295
|
+
content: C;
|
|
296
|
+
context?: CmssyBlockContext;
|
|
297
|
+
}) => Promise<D> | D;
|
|
278
298
|
component: ComponentType<{
|
|
279
299
|
content: C;
|
|
280
300
|
context?: CmssyBlockContext;
|
|
301
|
+
data?: D;
|
|
281
302
|
}>;
|
|
282
303
|
}): BlockDefinition;
|
|
283
304
|
type BlockMap = Record<string, ComponentType<{
|
|
284
305
|
content: Record<string, unknown>;
|
|
285
306
|
context?: CmssyBlockContext;
|
|
307
|
+
data?: unknown;
|
|
286
308
|
}>>;
|
|
287
309
|
declare function buildBlockMap(blocks: BlockDefinition[]): BlockMap;
|
|
288
310
|
declare function blocksToSchemas(blocks: BlockDefinition[]): Record<string, BlockSchema>;
|
|
@@ -256,6 +256,11 @@ interface DragEndMessage {
|
|
|
256
256
|
type EditorToAppMessage = SelectMessage | PatchMessage | ParentReadyMessage | InsertMessage | ReorderMessage | RemoveMessage | DragOverMessage | DragEndMessage;
|
|
257
257
|
declare function isProtocolCompatible(version: number): boolean;
|
|
258
258
|
|
|
259
|
+
interface BlockLoaderArgs {
|
|
260
|
+
content: Record<string, unknown>;
|
|
261
|
+
context?: CmssyBlockContext;
|
|
262
|
+
}
|
|
263
|
+
type BlockLoader = (args: BlockLoaderArgs) => Promise<unknown> | unknown;
|
|
259
264
|
interface BlockDefinition {
|
|
260
265
|
type: string;
|
|
261
266
|
label?: string;
|
|
@@ -263,26 +268,43 @@ interface BlockDefinition {
|
|
|
263
268
|
icon?: string;
|
|
264
269
|
layoutPositions?: string[];
|
|
265
270
|
props: Record<string, FieldDefinition>;
|
|
271
|
+
/**
|
|
272
|
+
* Optional server-side data loader. Run by CmssyServerPage during SSR; its
|
|
273
|
+
* result is passed to the component as the `data` prop. Not run in the
|
|
274
|
+
* editor (the component receives `data: undefined` there).
|
|
275
|
+
*
|
|
276
|
+
* The result crosses the server→client boundary when the block component is a
|
|
277
|
+
* Client Component, so it must be RSC-serializable (plain objects, arrays and
|
|
278
|
+
* primitives - no functions, class instances, etc.).
|
|
279
|
+
*/
|
|
280
|
+
loader?: BlockLoader;
|
|
266
281
|
component: ComponentType<{
|
|
267
282
|
content: Record<string, unknown>;
|
|
268
283
|
context?: CmssyBlockContext;
|
|
284
|
+
data?: unknown;
|
|
269
285
|
}>;
|
|
270
286
|
}
|
|
271
|
-
declare function defineBlock<C extends Record<string, unknown
|
|
287
|
+
declare function defineBlock<C extends Record<string, unknown>, D = unknown>(def: {
|
|
272
288
|
type: string;
|
|
273
289
|
label?: string;
|
|
274
290
|
category?: string;
|
|
275
291
|
icon?: string;
|
|
276
292
|
layoutPositions?: string[];
|
|
277
293
|
props: Record<string, FieldDefinition>;
|
|
294
|
+
loader?: (args: {
|
|
295
|
+
content: C;
|
|
296
|
+
context?: CmssyBlockContext;
|
|
297
|
+
}) => Promise<D> | D;
|
|
278
298
|
component: ComponentType<{
|
|
279
299
|
content: C;
|
|
280
300
|
context?: CmssyBlockContext;
|
|
301
|
+
data?: D;
|
|
281
302
|
}>;
|
|
282
303
|
}): BlockDefinition;
|
|
283
304
|
type BlockMap = Record<string, ComponentType<{
|
|
284
305
|
content: Record<string, unknown>;
|
|
285
306
|
context?: CmssyBlockContext;
|
|
307
|
+
data?: unknown;
|
|
286
308
|
}>>;
|
|
287
309
|
declare function buildBlockMap(blocks: BlockDefinition[]): BlockMap;
|
|
288
310
|
declare function blocksToSchemas(blocks: BlockDefinition[]): Record<string, BlockSchema>;
|