@cmssy/next 10.9.2 → 11.0.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/server.cjs CHANGED
@@ -9,6 +9,7 @@ var internalServer = require('@cmssy/react/internal-server');
9
9
  var internal = require('@cmssy/core/internal');
10
10
  var core = require('@cmssy/core');
11
11
  var jsxRuntime = require('react/jsx-runtime');
12
+ var locale = require('@cmssy/core/internal/locale');
12
13
 
13
14
  // src/server.ts
14
15
  function hasEditFlag(value) {
@@ -249,7 +250,68 @@ async function isCmssyEditMode() {
249
250
  const h = await headers.headers();
250
251
  return h.get(core.CMSSY_EDIT_HEADER) === "1";
251
252
  }
253
+ async function CmssyLayoutSlot({
254
+ config,
255
+ blocks,
256
+ position,
257
+ path,
258
+ locale: explicitLocale,
259
+ editMode,
260
+ page = "/",
261
+ editable: Editable,
262
+ appContext
263
+ }) {
264
+ const [groups, siteLocales] = await Promise.all([
265
+ internal.fetchLayouts(config, page, {
266
+ previewSecret: editMode ? config.draftSecret : void 0
267
+ }),
268
+ locale.resolveSiteLocales(config)
269
+ ]);
270
+ const locale$1 = explicitLocale ?? locale.splitLocaleFromPath(path ?? [], siteLocales).locale;
271
+ if (!editMode) {
272
+ return /* @__PURE__ */ jsxRuntime.jsx(
273
+ react.CmssyServerLayout,
274
+ {
275
+ groups,
276
+ blocks,
277
+ position,
278
+ locale: locale$1,
279
+ defaultLocale: siteLocales.defaultLocale,
280
+ enabledLocales: siteLocales.locales,
281
+ config,
282
+ appContext
283
+ }
284
+ );
285
+ }
286
+ const origin = core.resolveEditorOrigin(config.editorOrigin);
287
+ const editorData = await react.resolveEditorLayoutBlockData({
288
+ groups,
289
+ blocks,
290
+ position,
291
+ locale: locale$1,
292
+ defaultLocale: siteLocales.defaultLocale,
293
+ enabledLocales: siteLocales.locales,
294
+ isPreview: true,
295
+ config,
296
+ appContext
297
+ });
298
+ return /* @__PURE__ */ jsxRuntime.jsx(
299
+ Editable,
300
+ {
301
+ groups,
302
+ position,
303
+ locale: locale$1,
304
+ defaultLocale: siteLocales.defaultLocale,
305
+ enabledLocales: siteLocales.locales,
306
+ edit: { editorOrigin: (Array.isArray(origin) ? origin[0] : origin) ?? "" },
307
+ data: editorData.data,
308
+ resolvedContent: editorData.content,
309
+ appContext
310
+ }
311
+ );
312
+ }
252
313
 
314
+ exports.CmssyLayoutSlot = CmssyLayoutSlot;
253
315
  exports.createCmssyEditPage = createCmssyEditPage;
254
316
  exports.createCmssyPage = createCmssyPage;
255
317
  exports.createDraftRoute = createDraftRoute;
package/dist/server.d.cts CHANGED
@@ -1,8 +1,8 @@
1
1
  export { C as CmssyAppContext, a as CmssyEditorProps, b as CreateCmssyPageOptions, c as createCmssyEditPage, d as createCmssyPage } from './index-B64zk2X7.cjs';
2
- import { CmssyConfig } from '@cmssy/core';
3
- import 'react/jsx-runtime';
4
- import 'react';
5
- import '@cmssy/react';
2
+ import { CmssyConfig, LayoutPosition } from '@cmssy/core';
3
+ import * as react_jsx_runtime from 'react/jsx-runtime';
4
+ import { ComponentType } from 'react';
5
+ import { BlockDefinition, CmssyLayoutGroup } from '@cmssy/react';
6
6
  import '@cmssy/react/client';
7
7
 
8
8
  type CmssyDraftRouteConfig = Pick<CmssyConfig, "draftSecret"> & {
@@ -12,4 +12,83 @@ declare function createDraftRoute(config: CmssyDraftRouteConfig): (request: Requ
12
12
 
13
13
  declare function isCmssyEditMode(): Promise<boolean>;
14
14
 
15
- export { type CmssyDraftRouteConfig, createDraftRoute, isCmssyEditMode };
15
+ interface CmssyLayoutSlotBaseProps {
16
+ config: CmssyConfig;
17
+ blocks: BlockDefinition[];
18
+ /**
19
+ * Which layout position to render. Six exist - `top`, `header`,
20
+ * `sidebar_left`, `sidebar_right`, `footer`, `bottom` - and most sites use
21
+ * two of them; the type is what tells you about the other four.
22
+ */
23
+ position: LayoutPosition;
24
+ /**
25
+ * Whether to render through the edit bridge. A parameter rather than a
26
+ * lookup: every way of asking the request - `headers()`, `draftMode()` - is a
27
+ * dynamic API, and one read makes the whole route uncacheable. The route
28
+ * segment already knows the answer, so it passes it.
29
+ *
30
+ * Required on purpose. A slot that guessed `false` in an edit route would
31
+ * wrap draft content in published chrome, and nothing would report it.
32
+ */
33
+ editMode: boolean;
34
+ /** The page whose layout to render. Defaults to the site-wide header/footer. */
35
+ page?: string;
36
+ /**
37
+ * The client wrapper around `CmssyLazyLayout`, rendered in edit mode.
38
+ *
39
+ * Required, and a component rather than a loader: the block registry has to
40
+ * be imported lazily ON THE CLIENT, and a function cannot cross the server
41
+ * boundary. Without it the editor gets a header it can select and not fill -
42
+ * which is why this is a type error rather than a runtime warning.
43
+ */
44
+ editable: ComponentType<{
45
+ groups: CmssyLayoutGroup[];
46
+ position: string;
47
+ locale: string;
48
+ defaultLocale: string;
49
+ enabledLocales: string[];
50
+ edit: {
51
+ editorOrigin: string;
52
+ };
53
+ data?: Record<string, unknown>;
54
+ resolvedContent?: Record<string, Record<string, unknown>>;
55
+ appContext?: Record<string, unknown>;
56
+ }>;
57
+ /** Forwarded untouched to every block as `context.app`. */
58
+ appContext?: Record<string, unknown>;
59
+ }
60
+ /**
61
+ * Where the language comes from - one of two, never neither.
62
+ *
63
+ * `path` is the catch-all segments **as routed**: the language prefix in them
64
+ * IS the language, and reading it costs the route nothing. A caller with no
65
+ * params (a root layout) has to resolve the language itself and pass `locale`;
66
+ * there is deliberately no fallback to the request header, because a static
67
+ * route never sees the header the proxy set and would render the wrong
68
+ * language while looking like it worked.
69
+ */
70
+ type CmssyLayoutSlotLocaleSource = {
71
+ path: string[];
72
+ locale?: never;
73
+ } | {
74
+ locale: string;
75
+ path?: never;
76
+ };
77
+ type CmssyLayoutSlotProps = CmssyLayoutSlotBaseProps & CmssyLayoutSlotLocaleSource;
78
+ /**
79
+ * The site-wide header and footer, which are layout **blocks** rather than
80
+ * markup the app owns. Rendered the way each mode needs them:
81
+ *
82
+ * - published traffic: server-rendered blocks, no client cost;
83
+ * - the editor: the same blocks through the edit bridge, fetched with the
84
+ * preview secret and handed their server-resolved content, so a relation
85
+ * field shows records rather than the ids it stores.
86
+ *
87
+ * Getting any of that wrong is invisible - the site looks right while the
88
+ * editor shows a header it cannot fill, or the published version of one. Every
89
+ * app that wrote this by hand between 10.0 and 10.9 got at least one of the
90
+ * three wrong, which is why it is back.
91
+ */
92
+ declare function CmssyLayoutSlot({ config, blocks, position, path, locale: explicitLocale, editMode, page, editable: Editable, appContext, }: CmssyLayoutSlotProps): Promise<react_jsx_runtime.JSX.Element>;
93
+
94
+ export { type CmssyDraftRouteConfig, CmssyLayoutSlot, type CmssyLayoutSlotProps, createDraftRoute, isCmssyEditMode };
package/dist/server.d.ts CHANGED
@@ -1,8 +1,8 @@
1
1
  export { C as CmssyAppContext, a as CmssyEditorProps, b as CreateCmssyPageOptions, c as createCmssyEditPage, d as createCmssyPage } from './index-B64zk2X7.js';
2
- import { CmssyConfig } from '@cmssy/core';
3
- import 'react/jsx-runtime';
4
- import 'react';
5
- import '@cmssy/react';
2
+ import { CmssyConfig, LayoutPosition } from '@cmssy/core';
3
+ import * as react_jsx_runtime from 'react/jsx-runtime';
4
+ import { ComponentType } from 'react';
5
+ import { BlockDefinition, CmssyLayoutGroup } from '@cmssy/react';
6
6
  import '@cmssy/react/client';
7
7
 
8
8
  type CmssyDraftRouteConfig = Pick<CmssyConfig, "draftSecret"> & {
@@ -12,4 +12,83 @@ declare function createDraftRoute(config: CmssyDraftRouteConfig): (request: Requ
12
12
 
13
13
  declare function isCmssyEditMode(): Promise<boolean>;
14
14
 
15
- export { type CmssyDraftRouteConfig, createDraftRoute, isCmssyEditMode };
15
+ interface CmssyLayoutSlotBaseProps {
16
+ config: CmssyConfig;
17
+ blocks: BlockDefinition[];
18
+ /**
19
+ * Which layout position to render. Six exist - `top`, `header`,
20
+ * `sidebar_left`, `sidebar_right`, `footer`, `bottom` - and most sites use
21
+ * two of them; the type is what tells you about the other four.
22
+ */
23
+ position: LayoutPosition;
24
+ /**
25
+ * Whether to render through the edit bridge. A parameter rather than a
26
+ * lookup: every way of asking the request - `headers()`, `draftMode()` - is a
27
+ * dynamic API, and one read makes the whole route uncacheable. The route
28
+ * segment already knows the answer, so it passes it.
29
+ *
30
+ * Required on purpose. A slot that guessed `false` in an edit route would
31
+ * wrap draft content in published chrome, and nothing would report it.
32
+ */
33
+ editMode: boolean;
34
+ /** The page whose layout to render. Defaults to the site-wide header/footer. */
35
+ page?: string;
36
+ /**
37
+ * The client wrapper around `CmssyLazyLayout`, rendered in edit mode.
38
+ *
39
+ * Required, and a component rather than a loader: the block registry has to
40
+ * be imported lazily ON THE CLIENT, and a function cannot cross the server
41
+ * boundary. Without it the editor gets a header it can select and not fill -
42
+ * which is why this is a type error rather than a runtime warning.
43
+ */
44
+ editable: ComponentType<{
45
+ groups: CmssyLayoutGroup[];
46
+ position: string;
47
+ locale: string;
48
+ defaultLocale: string;
49
+ enabledLocales: string[];
50
+ edit: {
51
+ editorOrigin: string;
52
+ };
53
+ data?: Record<string, unknown>;
54
+ resolvedContent?: Record<string, Record<string, unknown>>;
55
+ appContext?: Record<string, unknown>;
56
+ }>;
57
+ /** Forwarded untouched to every block as `context.app`. */
58
+ appContext?: Record<string, unknown>;
59
+ }
60
+ /**
61
+ * Where the language comes from - one of two, never neither.
62
+ *
63
+ * `path` is the catch-all segments **as routed**: the language prefix in them
64
+ * IS the language, and reading it costs the route nothing. A caller with no
65
+ * params (a root layout) has to resolve the language itself and pass `locale`;
66
+ * there is deliberately no fallback to the request header, because a static
67
+ * route never sees the header the proxy set and would render the wrong
68
+ * language while looking like it worked.
69
+ */
70
+ type CmssyLayoutSlotLocaleSource = {
71
+ path: string[];
72
+ locale?: never;
73
+ } | {
74
+ locale: string;
75
+ path?: never;
76
+ };
77
+ type CmssyLayoutSlotProps = CmssyLayoutSlotBaseProps & CmssyLayoutSlotLocaleSource;
78
+ /**
79
+ * The site-wide header and footer, which are layout **blocks** rather than
80
+ * markup the app owns. Rendered the way each mode needs them:
81
+ *
82
+ * - published traffic: server-rendered blocks, no client cost;
83
+ * - the editor: the same blocks through the edit bridge, fetched with the
84
+ * preview secret and handed their server-resolved content, so a relation
85
+ * field shows records rather than the ids it stores.
86
+ *
87
+ * Getting any of that wrong is invisible - the site looks right while the
88
+ * editor shows a header it cannot fill, or the published version of one. Every
89
+ * app that wrote this by hand between 10.0 and 10.9 got at least one of the
90
+ * three wrong, which is why it is back.
91
+ */
92
+ declare function CmssyLayoutSlot({ config, blocks, position, path, locale: explicitLocale, editMode, page, editable: Editable, appContext, }: CmssyLayoutSlotProps): Promise<react_jsx_runtime.JSX.Element>;
93
+
94
+ export { type CmssyDraftRouteConfig, CmssyLayoutSlot, type CmssyLayoutSlotProps, createDraftRoute, isCmssyEditMode };
package/dist/server.js CHANGED
@@ -1,12 +1,13 @@
1
1
  import 'server-only';
2
2
  import { draftMode, headers } from 'next/headers';
3
3
  import { notFound, redirect } from 'next/navigation';
4
- import { createCmssyClient, CmssyServerPage } from '@cmssy/react';
4
+ import { createCmssyClient, CmssyServerPage, CmssyServerLayout, resolveEditorLayoutBlockData } from '@cmssy/react';
5
5
  import { CmssyLocaleProvider } from '@cmssy/react/internal';
6
6
  import { resolveEditorBlockData } from '@cmssy/react/internal-server';
7
- import { isDevelopment, resolveSiteLocales, splitLocaleFromPath, fetchPage, resolveForms, toCspOrigin, cmssySecretsMatch } from '@cmssy/core/internal';
7
+ import { isDevelopment, resolveSiteLocales, splitLocaleFromPath, fetchPage, resolveForms, toCspOrigin, cmssySecretsMatch, fetchLayouts } from '@cmssy/core/internal';
8
8
  import { CMSSY_SECRET_QUERY_PARAM, resolveEditorOrigin, CMSSY_EDIT_HEADER, CMSSY_EDIT_QUERY_PARAM } from '@cmssy/core';
9
9
  import { jsx } from 'react/jsx-runtime';
10
+ import { resolveSiteLocales as resolveSiteLocales$1, splitLocaleFromPath as splitLocaleFromPath$1 } from '@cmssy/core/internal/locale';
10
11
 
11
12
  // src/server.ts
12
13
  function hasEditFlag(value) {
@@ -247,5 +248,65 @@ async function isCmssyEditMode() {
247
248
  const h = await headers();
248
249
  return h.get(CMSSY_EDIT_HEADER) === "1";
249
250
  }
251
+ async function CmssyLayoutSlot({
252
+ config,
253
+ blocks,
254
+ position,
255
+ path,
256
+ locale: explicitLocale,
257
+ editMode,
258
+ page = "/",
259
+ editable: Editable,
260
+ appContext
261
+ }) {
262
+ const [groups, siteLocales] = await Promise.all([
263
+ fetchLayouts(config, page, {
264
+ previewSecret: editMode ? config.draftSecret : void 0
265
+ }),
266
+ resolveSiteLocales$1(config)
267
+ ]);
268
+ const locale = explicitLocale ?? splitLocaleFromPath$1(path ?? [], siteLocales).locale;
269
+ if (!editMode) {
270
+ return /* @__PURE__ */ jsx(
271
+ CmssyServerLayout,
272
+ {
273
+ groups,
274
+ blocks,
275
+ position,
276
+ locale,
277
+ defaultLocale: siteLocales.defaultLocale,
278
+ enabledLocales: siteLocales.locales,
279
+ config,
280
+ appContext
281
+ }
282
+ );
283
+ }
284
+ const origin = resolveEditorOrigin(config.editorOrigin);
285
+ const editorData = await resolveEditorLayoutBlockData({
286
+ groups,
287
+ blocks,
288
+ position,
289
+ locale,
290
+ defaultLocale: siteLocales.defaultLocale,
291
+ enabledLocales: siteLocales.locales,
292
+ isPreview: true,
293
+ config,
294
+ appContext
295
+ });
296
+ return /* @__PURE__ */ jsx(
297
+ Editable,
298
+ {
299
+ groups,
300
+ position,
301
+ locale,
302
+ defaultLocale: siteLocales.defaultLocale,
303
+ enabledLocales: siteLocales.locales,
304
+ edit: { editorOrigin: (Array.isArray(origin) ? origin[0] : origin) ?? "" },
305
+ data: editorData.data,
306
+ resolvedContent: editorData.content,
307
+ appContext
308
+ }
309
+ );
310
+ }
250
311
 
251
- export { createCmssyEditPage, createCmssyPage, createDraftRoute, isCmssyEditMode };
312
+ export { CmssyLayoutSlot, createCmssyEditPage, createCmssyPage, createDraftRoute, isCmssyEditMode };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cmssy/next",
3
- "version": "10.9.2",
3
+ "version": "11.0.0",
4
4
  "description": "Next.js App Router bindings for cmssy headless sites (createCmssyPage + draft preview)",
5
5
  "keywords": [
6
6
  "cmssy",
@@ -51,7 +51,7 @@
51
51
  "dist"
52
52
  ],
53
53
  "peerDependencies": {
54
- "@cmssy/react": "^10.0.0",
54
+ "@cmssy/react": "^11.0.0",
55
55
  "next": ">=15",
56
56
  "react": "^18.2.0 || ^19.0.0",
57
57
  "react-dom": "^18.2.0 || ^19.0.0"
@@ -65,12 +65,12 @@
65
65
  "tsup": "^8.3.0",
66
66
  "typescript": "^5.6.0",
67
67
  "vitest": "^2.1.0",
68
- "@cmssy/react": "10.9.2"
68
+ "@cmssy/react": "11.0.0"
69
69
  },
70
70
  "dependencies": {
71
71
  "@cmssy/types": "0.32.0",
72
72
  "server-only": "^0.0.1",
73
- "@cmssy/core": "10.9.2"
73
+ "@cmssy/core": "11.0.0"
74
74
  },
75
75
  "scripts": {
76
76
  "build": "tsup",