@endora-commerce/mod-cms 0.0.0-stage → 0.100.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.
Files changed (264) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +65 -2
  3. package/dist/admin/api/cms-client.d.ts +77 -0
  4. package/dist/admin/api/cms-client.d.ts.map +1 -0
  5. package/dist/admin/api/cms-client.js +162 -0
  6. package/dist/admin/api/cms-client.js.map +1 -0
  7. package/dist/admin/components/AdminCatalogPreviewProvider.d.ts +6 -0
  8. package/dist/admin/components/AdminCatalogPreviewProvider.d.ts.map +1 -0
  9. package/dist/admin/components/AdminCatalogPreviewProvider.js +74 -0
  10. package/dist/admin/components/AdminCatalogPreviewProvider.js.map +1 -0
  11. package/dist/admin/components/AdminCmsAssetProvider.d.ts +9 -0
  12. package/dist/admin/components/AdminCmsAssetProvider.d.ts.map +1 -0
  13. package/dist/admin/components/AdminCmsAssetProvider.js +50 -0
  14. package/dist/admin/components/AdminCmsAssetProvider.js.map +1 -0
  15. package/dist/admin/components/BackgroundFields.d.ts +4 -0
  16. package/dist/admin/components/BackgroundFields.d.ts.map +1 -0
  17. package/dist/admin/components/BackgroundFields.js +40 -0
  18. package/dist/admin/components/BackgroundFields.js.map +1 -0
  19. package/dist/admin/components/ButtonLinkFields.d.ts +6 -0
  20. package/dist/admin/components/ButtonLinkFields.d.ts.map +1 -0
  21. package/dist/admin/components/ButtonLinkFields.js +127 -0
  22. package/dist/admin/components/ButtonLinkFields.js.map +1 -0
  23. package/dist/admin/components/CarouselPreviewNav.d.ts +12 -0
  24. package/dist/admin/components/CarouselPreviewNav.d.ts.map +1 -0
  25. package/dist/admin/components/CarouselPreviewNav.js +31 -0
  26. package/dist/admin/components/CarouselPreviewNav.js.map +1 -0
  27. package/dist/admin/components/CmsContentEditorLayout.d.ts +12 -0
  28. package/dist/admin/components/CmsContentEditorLayout.d.ts.map +1 -0
  29. package/dist/admin/components/CmsContentEditorLayout.js +9 -0
  30. package/dist/admin/components/CmsContentEditorLayout.js.map +1 -0
  31. package/dist/admin/components/ComponentDragHandle.d.ts +6 -0
  32. package/dist/admin/components/ComponentDragHandle.d.ts.map +1 -0
  33. package/dist/admin/components/ComponentDragHandle.js +119 -0
  34. package/dist/admin/components/ComponentDragHandle.js.map +1 -0
  35. package/dist/admin/components/ContentSliderActionBarExtras.d.ts +6 -0
  36. package/dist/admin/components/ContentSliderActionBarExtras.d.ts.map +1 -0
  37. package/dist/admin/components/ContentSliderActionBarExtras.js +109 -0
  38. package/dist/admin/components/ContentSliderActionBarExtras.js.map +1 -0
  39. package/dist/admin/components/HookBlockAttachmentsPanel.d.ts +9 -0
  40. package/dist/admin/components/HookBlockAttachmentsPanel.d.ts.map +1 -0
  41. package/dist/admin/components/HookBlockAttachmentsPanel.js +137 -0
  42. package/dist/admin/components/HookBlockAttachmentsPanel.js.map +1 -0
  43. package/dist/admin/components/PageBuilderActionBar.d.ts +10 -0
  44. package/dist/admin/components/PageBuilderActionBar.d.ts.map +1 -0
  45. package/dist/admin/components/PageBuilderActionBar.js +118 -0
  46. package/dist/admin/components/PageBuilderActionBar.js.map +1 -0
  47. package/dist/admin/components/PageBuilderDrawer.d.ts +16 -0
  48. package/dist/admin/components/PageBuilderDrawer.d.ts.map +1 -0
  49. package/dist/admin/components/PageBuilderDrawer.js +53 -0
  50. package/dist/admin/components/PageBuilderDrawer.js.map +1 -0
  51. package/dist/admin/components/PageBuilderEditor.d.ts +45 -0
  52. package/dist/admin/components/PageBuilderEditor.d.ts.map +1 -0
  53. package/dist/admin/components/PageBuilderEditor.js +632 -0
  54. package/dist/admin/components/PageBuilderEditor.js.map +1 -0
  55. package/dist/admin/components/PuckActionGuard.d.ts +12 -0
  56. package/dist/admin/components/PuckActionGuard.d.ts.map +1 -0
  57. package/dist/admin/components/PuckActionGuard.js +30 -0
  58. package/dist/admin/components/PuckActionGuard.js.map +1 -0
  59. package/dist/admin/components/RowLayoutPicker.d.ts +8 -0
  60. package/dist/admin/components/RowLayoutPicker.d.ts.map +1 -0
  61. package/dist/admin/components/RowLayoutPicker.js +17 -0
  62. package/dist/admin/components/RowLayoutPicker.js.map +1 -0
  63. package/dist/admin/components/SliderPreviewActionBarExtras.d.ts +6 -0
  64. package/dist/admin/components/SliderPreviewActionBarExtras.d.ts.map +1 -0
  65. package/dist/admin/components/SliderPreviewActionBarExtras.js +32 -0
  66. package/dist/admin/components/SliderPreviewActionBarExtras.js.map +1 -0
  67. package/dist/admin/components/admin-catalog-preview-map.d.ts +17 -0
  68. package/dist/admin/components/admin-catalog-preview-map.d.ts.map +1 -0
  69. package/dist/admin/components/admin-catalog-preview-map.js +18 -0
  70. package/dist/admin/components/admin-catalog-preview-map.js.map +1 -0
  71. package/dist/admin/components/build-viewports.d.ts +23 -0
  72. package/dist/admin/components/build-viewports.d.ts.map +1 -0
  73. package/dist/admin/components/build-viewports.js +23 -0
  74. package/dist/admin/components/build-viewports.js.map +1 -0
  75. package/dist/admin/components/cms-template-layout.d.ts +16 -0
  76. package/dist/admin/components/cms-template-layout.d.ts.map +1 -0
  77. package/dist/admin/components/cms-template-layout.js +53 -0
  78. package/dist/admin/components/cms-template-layout.js.map +1 -0
  79. package/dist/admin/components/page-builder-i18n.d.ts +27 -0
  80. package/dist/admin/components/page-builder-i18n.d.ts.map +1 -0
  81. package/dist/admin/components/page-builder-i18n.js +34 -0
  82. package/dist/admin/components/page-builder-i18n.js.map +1 -0
  83. package/dist/admin/components/puck-safe.d.ts +10 -0
  84. package/dist/admin/components/puck-safe.d.ts.map +1 -0
  85. package/dist/admin/components/puck-safe.js +22 -0
  86. package/dist/admin/components/puck-safe.js.map +1 -0
  87. package/dist/admin/components/scope-utils.d.ts +4 -0
  88. package/dist/admin/components/scope-utils.d.ts.map +1 -0
  89. package/dist/admin/components/scope-utils.js +7 -0
  90. package/dist/admin/components/scope-utils.js.map +1 -0
  91. package/dist/admin/editors/BlockEditor.d.ts +9 -0
  92. package/dist/admin/editors/BlockEditor.d.ts.map +1 -0
  93. package/dist/admin/editors/BlockEditor.js +217 -0
  94. package/dist/admin/editors/BlockEditor.js.map +1 -0
  95. package/dist/admin/editors/PageEditor.d.ts +9 -0
  96. package/dist/admin/editors/PageEditor.d.ts.map +1 -0
  97. package/dist/admin/editors/PageEditor.js +316 -0
  98. package/dist/admin/editors/PageEditor.js.map +1 -0
  99. package/dist/admin/editors/TemplateEditor.d.ts +9 -0
  100. package/dist/admin/editors/TemplateEditor.d.ts.map +1 -0
  101. package/dist/admin/editors/TemplateEditor.js +180 -0
  102. package/dist/admin/editors/TemplateEditor.js.map +1 -0
  103. package/dist/admin/index.d.ts +38 -0
  104. package/dist/admin/index.d.ts.map +1 -0
  105. package/dist/admin/index.js +144 -0
  106. package/dist/admin/index.js.map +1 -0
  107. package/dist/admin/pages/BlocksListPage.d.ts +9 -0
  108. package/dist/admin/pages/BlocksListPage.d.ts.map +1 -0
  109. package/dist/admin/pages/BlocksListPage.js +47 -0
  110. package/dist/admin/pages/BlocksListPage.js.map +1 -0
  111. package/dist/admin/pages/HooksPage.d.ts +9 -0
  112. package/dist/admin/pages/HooksPage.d.ts.map +1 -0
  113. package/dist/admin/pages/HooksPage.js +41 -0
  114. package/dist/admin/pages/HooksPage.js.map +1 -0
  115. package/dist/admin/pages/PagesListPage.d.ts +9 -0
  116. package/dist/admin/pages/PagesListPage.d.ts.map +1 -0
  117. package/dist/admin/pages/PagesListPage.js +51 -0
  118. package/dist/admin/pages/PagesListPage.js.map +1 -0
  119. package/dist/admin/pages/TemplatesListPage.d.ts +9 -0
  120. package/dist/admin/pages/TemplatesListPage.d.ts.map +1 -0
  121. package/dist/admin/pages/TemplatesListPage.js +47 -0
  122. package/dist/admin/pages/TemplatesListPage.js.map +1 -0
  123. package/dist/admin-ui/index.d.ts +90 -0
  124. package/dist/admin-ui/index.d.ts.map +1 -0
  125. package/dist/admin-ui/index.js +89 -0
  126. package/dist/admin-ui/index.js.map +1 -0
  127. package/dist/backend/cli/block-names.d.ts +92 -0
  128. package/dist/backend/cli/block-names.d.ts.map +1 -0
  129. package/dist/backend/cli/block-names.js +132 -0
  130. package/dist/backend/cli/block-names.js.map +1 -0
  131. package/dist/backend/entities/cms-block.entity.d.ts +20 -0
  132. package/dist/backend/entities/cms-block.entity.d.ts.map +1 -0
  133. package/dist/backend/entities/cms-block.entity.js +77 -0
  134. package/dist/backend/entities/cms-block.entity.js.map +1 -0
  135. package/dist/backend/entities/cms-hook-block-attachment.entity.d.ts +15 -0
  136. package/dist/backend/entities/cms-hook-block-attachment.entity.d.ts.map +1 -0
  137. package/dist/backend/entities/cms-hook-block-attachment.entity.js +46 -0
  138. package/dist/backend/entities/cms-hook-block-attachment.entity.js.map +1 -0
  139. package/dist/backend/entities/cms-hook.entity.d.ts +20 -0
  140. package/dist/backend/entities/cms-hook.entity.d.ts.map +1 -0
  141. package/dist/backend/entities/cms-hook.entity.js +73 -0
  142. package/dist/backend/entities/cms-hook.entity.js.map +1 -0
  143. package/dist/backend/entities/cms-page.entity.d.ts +43 -0
  144. package/dist/backend/entities/cms-page.entity.d.ts.map +1 -0
  145. package/dist/backend/entities/cms-page.entity.js +140 -0
  146. package/dist/backend/entities/cms-page.entity.js.map +1 -0
  147. package/dist/backend/entities/cms-template.entity.d.ts +20 -0
  148. package/dist/backend/entities/cms-template.entity.d.ts.map +1 -0
  149. package/dist/backend/entities/cms-template.entity.js +73 -0
  150. package/dist/backend/entities/cms-template.entity.js.map +1 -0
  151. package/dist/backend/index.d.ts +157 -0
  152. package/dist/backend/index.d.ts.map +1 -0
  153. package/dist/backend/index.js +317 -0
  154. package/dist/backend/index.js.map +1 -0
  155. package/dist/backend/plugin.d.ts +81 -0
  156. package/dist/backend/plugin.d.ts.map +1 -0
  157. package/dist/backend/plugin.js +81 -0
  158. package/dist/backend/plugin.js.map +1 -0
  159. package/dist/backend/routes.admin.d.ts +19 -0
  160. package/dist/backend/routes.admin.d.ts.map +1 -0
  161. package/dist/backend/routes.admin.js +164 -0
  162. package/dist/backend/routes.admin.js.map +1 -0
  163. package/dist/backend/routes.storefront.d.ts +6 -0
  164. package/dist/backend/routes.storefront.d.ts.map +1 -0
  165. package/dist/backend/routes.storefront.js +89 -0
  166. package/dist/backend/routes.storefront.js.map +1 -0
  167. package/dist/backend/services/asset-embed-resolver.d.ts +17 -0
  168. package/dist/backend/services/asset-embed-resolver.d.ts.map +1 -0
  169. package/dist/backend/services/asset-embed-resolver.js +40 -0
  170. package/dist/backend/services/asset-embed-resolver.js.map +1 -0
  171. package/dist/backend/services/asset-references.d.ts +4 -0
  172. package/dist/backend/services/asset-references.d.ts.map +1 -0
  173. package/dist/backend/services/asset-references.js +55 -0
  174. package/dist/backend/services/asset-references.js.map +1 -0
  175. package/dist/backend/services/cms-block-read-port.d.ts +27 -0
  176. package/dist/backend/services/cms-block-read-port.d.ts.map +1 -0
  177. package/dist/backend/services/cms-block-read-port.js +50 -0
  178. package/dist/backend/services/cms-block-read-port.js.map +1 -0
  179. package/dist/backend/services/cms-block-seed-port.d.ts +31 -0
  180. package/dist/backend/services/cms-block-seed-port.d.ts.map +1 -0
  181. package/dist/backend/services/cms-block-seed-port.js +68 -0
  182. package/dist/backend/services/cms-block-seed-port.js.map +1 -0
  183. package/dist/backend/services/cms-block-service.d.ts +38 -0
  184. package/dist/backend/services/cms-block-service.d.ts.map +1 -0
  185. package/dist/backend/services/cms-block-service.js +218 -0
  186. package/dist/backend/services/cms-block-service.js.map +1 -0
  187. package/dist/backend/services/cms-cache.d.ts +54 -0
  188. package/dist/backend/services/cms-cache.d.ts.map +1 -0
  189. package/dist/backend/services/cms-cache.js +113 -0
  190. package/dist/backend/services/cms-cache.js.map +1 -0
  191. package/dist/backend/services/cms-hook-service.d.ts +35 -0
  192. package/dist/backend/services/cms-hook-service.d.ts.map +1 -0
  193. package/dist/backend/services/cms-hook-service.js +216 -0
  194. package/dist/backend/services/cms-hook-service.js.map +1 -0
  195. package/dist/backend/services/cms-language-reference.d.ts +11 -0
  196. package/dist/backend/services/cms-language-reference.d.ts.map +1 -0
  197. package/dist/backend/services/cms-language-reference.js +26 -0
  198. package/dist/backend/services/cms-language-reference.js.map +1 -0
  199. package/dist/backend/services/cms-page-read-port.d.ts +23 -0
  200. package/dist/backend/services/cms-page-read-port.d.ts.map +1 -0
  201. package/dist/backend/services/cms-page-read-port.js +54 -0
  202. package/dist/backend/services/cms-page-read-port.js.map +1 -0
  203. package/dist/backend/services/cms-page-service.d.ts +104 -0
  204. package/dist/backend/services/cms-page-service.d.ts.map +1 -0
  205. package/dist/backend/services/cms-page-service.js +468 -0
  206. package/dist/backend/services/cms-page-service.js.map +1 -0
  207. package/dist/backend/services/cms-reference-registry.d.ts +30 -0
  208. package/dist/backend/services/cms-reference-registry.d.ts.map +1 -0
  209. package/dist/backend/services/cms-reference-registry.js +98 -0
  210. package/dist/backend/services/cms-reference-registry.js.map +1 -0
  211. package/dist/backend/services/cms-template-service.d.ts +37 -0
  212. package/dist/backend/services/cms-template-service.d.ts.map +1 -0
  213. package/dist/backend/services/cms-template-service.js +205 -0
  214. package/dist/backend/services/cms-template-service.js.map +1 -0
  215. package/dist/backend/services/content-tree-walker.d.ts +7 -0
  216. package/dist/backend/services/content-tree-walker.d.ts.map +1 -0
  217. package/dist/backend/services/content-tree-walker.js +89 -0
  218. package/dist/backend/services/content-tree-walker.js.map +1 -0
  219. package/dist/backend/services/page-builder-registry.d.ts +120 -0
  220. package/dist/backend/services/page-builder-registry.d.ts.map +1 -0
  221. package/dist/backend/services/page-builder-registry.js +220 -0
  222. package/dist/backend/services/page-builder-registry.js.map +1 -0
  223. package/dist/backend/services/seed-hooks.d.ts +22 -0
  224. package/dist/backend/services/seed-hooks.d.ts.map +1 -0
  225. package/dist/backend/services/seed-hooks.js +94 -0
  226. package/dist/backend/services/seed-hooks.js.map +1 -0
  227. package/dist/backend/services/storefront-resolver.d.ts +71 -0
  228. package/dist/backend/services/storefront-resolver.d.ts.map +1 -0
  229. package/dist/backend/services/storefront-resolver.js +329 -0
  230. package/dist/backend/services/storefront-resolver.js.map +1 -0
  231. package/dist/manifest.d.ts +225 -0
  232. package/dist/manifest.d.ts.map +1 -0
  233. package/dist/manifest.js +695 -0
  234. package/dist/manifest.js.map +1 -0
  235. package/dist/migrations/20260425T162418_cms_pages_init.d.ts +10 -0
  236. package/dist/migrations/20260425T162418_cms_pages_init.d.ts.map +1 -0
  237. package/dist/migrations/20260425T162418_cms_pages_init.js +30 -0
  238. package/dist/migrations/20260425T162418_cms_pages_init.js.map +1 -0
  239. package/dist/migrations/20260505T130214_cms_init.d.ts +28 -0
  240. package/dist/migrations/20260505T130214_cms_init.d.ts.map +1 -0
  241. package/dist/migrations/20260505T130214_cms_init.js +332 -0
  242. package/dist/migrations/20260505T130214_cms_init.js.map +1 -0
  243. package/dist/migrations/20260903T101741_cms_namespace_block_names.d.ts +6 -0
  244. package/dist/migrations/20260903T101741_cms_namespace_block_names.d.ts.map +1 -0
  245. package/dist/migrations/20260903T101741_cms_namespace_block_names.js +60 -0
  246. package/dist/migrations/20260903T101741_cms_namespace_block_names.js.map +1 -0
  247. package/dist/migrations/20260912T094733_cms_sales_channel_cms_pages.d.ts +27 -0
  248. package/dist/migrations/20260912T094733_cms_sales_channel_cms_pages.d.ts.map +1 -0
  249. package/dist/migrations/20260912T094733_cms_sales_channel_cms_pages.js +44 -0
  250. package/dist/migrations/20260912T094733_cms_sales_channel_cms_pages.js.map +1 -0
  251. package/dist/migrations/20260912T125709_cms_page_body_asset_ref_index.d.ts +32 -0
  252. package/dist/migrations/20260912T125709_cms_page_body_asset_ref_index.d.ts.map +1 -0
  253. package/dist/migrations/20260912T125709_cms_page_body_asset_ref_index.js +36 -0
  254. package/dist/migrations/20260912T125709_cms_page_body_asset_ref_index.js.map +1 -0
  255. package/dist/migrations/index.d.ts +31 -0
  256. package/dist/migrations/index.d.ts.map +1 -0
  257. package/dist/migrations/index.js +37 -0
  258. package/dist/migrations/index.js.map +1 -0
  259. package/docs/cms/extending-page-builder.md +256 -0
  260. package/docs/cms/index.md +233 -0
  261. package/i18n/en.json +231 -0
  262. package/i18n/pl.json +231 -0
  263. package/package.json +125 -3
  264. package/tailwind.css +16 -0
@@ -0,0 +1,632 @@
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Component, useCallback, useEffect, useMemo, useRef, useState } from 'react';
3
+ import { Puck, Render } from '@measured/puck';
4
+ import '@measured/puck/puck.css';
5
+ // Self-contained, prefix-isolated (`cmsc:`) stylesheet for the shared CMS components
6
+ // (feature 041, FR-012b). This is the admin's ONLY change; it carries its own token
7
+ // values + no preflight, so it cannot restyle admin chrome.
8
+ import '@endora-commerce/cms-components/styles.css';
9
+ import { defaultPageBuilderConfig, makeMissingComponentConfig, withCmsPageRoot, withMissingBlockPlaceholders, } from '@endora-commerce/cms-components';
10
+ import { buildPaletteCategories, contextAdmits, countBlockNames, filterConfigByContext, } from '@endora-commerce/page-builder-core';
11
+ import { createPageBuilderEditorPlugin } from '@endora-commerce/page-builder-core/editor';
12
+ import { AdminCmsAssetProvider } from './AdminCmsAssetProvider.js';
13
+ import { Alert, AlertDescription } from '@endora-commerce/admin-kit/ui';
14
+ import { cn } from '@endora-commerce/admin-kit/lib';
15
+ import { useTranslation, useTranslationContext } from '@endora-commerce/admin-kit/i18n';
16
+ import { cmsClient } from '../api/cms-client.js';
17
+ import { PageBuilderColorPaletteProvider, createCategorySlugField, createCategorySlugsField, createProductSlugField, createProductSlugsField, createImageAssetField, createImageSourceField, createImageUrlField, createSlideImageField, PageBuilderHeaderActions, PageBuilderHeaderShell, PageBuilderTemplateActions, emptyPageBuilderData, isEmptyPageBuilderData, PageBuilderOverlayBridge, } from '@endora-commerce/page-builder-admin';
18
+ import { AdminCatalogPreviewProvider } from './AdminCatalogPreviewProvider.js';
19
+ import { createButtonLinkSlugField } from './ButtonLinkFields.js';
20
+ import { createAdminBackgroundField } from './BackgroundFields.js';
21
+ import { buildViewports } from './build-viewports.js';
22
+ import { applyRowLayoutPreset, findRowById, replaceRowInData, wrapRowInContentSliderSlide, } from '@endora-commerce/cms-components/editor/row-layout-presets';
23
+ import { isContentSliderSlidesZone, toPuckItemArray } from '@endora-commerce/page-builder-core/editor';
24
+ import { createPuckActionHandler, PuckDispatchBridgeSlot } from './PuckActionGuard.js';
25
+ import { RowLayoutPicker } from './RowLayoutPicker.js';
26
+ import { PageBuilderActionBar } from './PageBuilderActionBar.js';
27
+ import { PageBuilderDrawer } from './PageBuilderDrawer.js';
28
+ import { applyPageBuilderTranslations } from './page-builder-i18n.js';
29
+ import { hasInvalidColumnPlacement } from '@endora-commerce/page-builder-core/editor';
30
+ const emptyData = { root: { props: {} }, content: [] };
31
+ function insertedItem(action, data) {
32
+ const items = action.destinationZone.startsWith('root:')
33
+ ? toPuckItemArray(data.content)
34
+ : toPuckItemArray(data.zones?.[action.destinationZone]);
35
+ return items[action.destinationIndex] ?? null;
36
+ }
37
+ function resolveInsertedRowId(action, data) {
38
+ if (typeof action.id === 'string' && action.id.length > 0)
39
+ return action.id;
40
+ const inserted = insertedItem(action, data);
41
+ return typeof inserted?.props.id === 'string' ? inserted.props.id : null;
42
+ }
43
+ function collectRowIds(data) {
44
+ const ids = new Set();
45
+ const visit = (items) => {
46
+ for (const item of items) {
47
+ if (item.type === 'cms.Row' && typeof item.props.id === 'string') {
48
+ ids.add(item.props.id);
49
+ }
50
+ for (const value of Object.values(item.props)) {
51
+ const nested = toPuckItemArray(value);
52
+ if (nested.length > 0)
53
+ visit(nested);
54
+ }
55
+ }
56
+ };
57
+ visit(toPuckItemArray(data.content));
58
+ for (const zoneItems of Object.values(data.zones ?? {})) {
59
+ visit(toPuckItemArray(zoneItems));
60
+ }
61
+ return ids;
62
+ }
63
+ /**
64
+ * Guards a best-effort on-canvas embed preview: if rendering a referenced
65
+ * block/template tree throws (e.g. an unknown extension component or a
66
+ * malformed tree), the placeholder simply disappears instead of taking the
67
+ * whole editor down with it.
68
+ */
69
+ class PreviewBoundary extends Component {
70
+ constructor(props) {
71
+ super(props);
72
+ this.state = { failed: false };
73
+ }
74
+ static getDerivedStateFromError() {
75
+ return { failed: true };
76
+ }
77
+ render() {
78
+ return this.state.failed ? null : this.props.children;
79
+ }
80
+ }
81
+ /**
82
+ * Renders a block/template's stored content (per-language Puck trees) into an
83
+ * on-canvas preview so the InsertBlock/InsertTemplate embeds show their actual
84
+ * content instead of just printing the referenced code. Prefers Polish, then
85
+ * English, then any available language.
86
+ */
87
+ function previewNode(content) {
88
+ const langs = content.languages ?? {};
89
+ const tree = langs['pl-PL'] ?? langs['en-US'] ?? Object.values(langs)[0] ?? null;
90
+ if (!tree)
91
+ return null;
92
+ return (_jsx(PreviewBoundary, { children: _jsx(Render, { config: defaultPageBuilderConfig, data: tree }) }));
93
+ }
94
+ function mergeConfig(descriptor, extensionTitle, blockOptions, context, sectionTitle) {
95
+ const base = defaultPageBuilderConfig;
96
+ const components = {
97
+ ...(base.components ?? {}),
98
+ };
99
+ // Replace InsertBlock's free-text "Block code" field with a dropdown of the
100
+ // available CMS blocks, so authors pick from a list instead of having to know
101
+ // and type a code by hand.
102
+ const insertBlock = components['cms.InsertBlock'];
103
+ if (insertBlock) {
104
+ components['cms.InsertBlock'] = {
105
+ ...insertBlock,
106
+ fields: {
107
+ ...insertBlock.fields,
108
+ code: {
109
+ type: 'select',
110
+ label: 'Block',
111
+ options: [{ label: '—', value: '' }, ...blockOptions],
112
+ },
113
+ },
114
+ };
115
+ }
116
+ const button = components['cms.Button'];
117
+ if (button) {
118
+ components['cms.Button'] = {
119
+ ...button,
120
+ fields: {
121
+ ...button.fields,
122
+ linkSlug: createButtonLinkSlugField(),
123
+ },
124
+ };
125
+ }
126
+ const hero = components['cms.Hero'];
127
+ if (hero) {
128
+ components['cms.Hero'] = {
129
+ ...hero,
130
+ fields: {
131
+ ...hero.fields,
132
+ buttonLinkSlug: createButtonLinkSlugField({
133
+ label: 'Button link target',
134
+ linkTypeProp: 'buttonLinkType',
135
+ }),
136
+ },
137
+ };
138
+ }
139
+ const productCard = components['catalog.ProductCard'];
140
+ if (productCard) {
141
+ components['catalog.ProductCard'] = {
142
+ ...productCard,
143
+ fields: { ...productCard.fields, productSlug: createProductSlugField() },
144
+ };
145
+ }
146
+ for (const name of ['catalog.ProductGrid', 'catalog.ProductSlider']) {
147
+ const cfg = components[name];
148
+ if (cfg) {
149
+ components[name] = {
150
+ ...cfg,
151
+ fields: {
152
+ ...cfg.fields,
153
+ productSlugs: createProductSlugsField(),
154
+ categorySlug: createCategorySlugField(),
155
+ },
156
+ };
157
+ }
158
+ }
159
+ for (const name of ['catalog.CategoryList', 'catalog.CategoryGrid']) {
160
+ const cfg = components[name];
161
+ if (cfg) {
162
+ components[name] = {
163
+ ...cfg,
164
+ fields: {
165
+ ...cfg.fields,
166
+ categorySlugs: createCategorySlugsField(),
167
+ parentSlug: createCategorySlugField(),
168
+ },
169
+ };
170
+ }
171
+ }
172
+ const image = components['cms.Image'];
173
+ if (image) {
174
+ components['cms.Image'] = {
175
+ ...image,
176
+ fields: {
177
+ ...image.fields,
178
+ imageSource: createImageSourceField(),
179
+ src: createImageUrlField('Image URL'),
180
+ assetId: createImageAssetField('Image'),
181
+ },
182
+ };
183
+ }
184
+ const imageSlider = components['cms.ImageSlider'];
185
+ if (imageSlider) {
186
+ const itemsField = imageSlider.fields?.items;
187
+ components['cms.ImageSlider'] = {
188
+ ...imageSlider,
189
+ fields: {
190
+ ...imageSlider.fields,
191
+ items: itemsField && itemsField.type === 'array'
192
+ ? {
193
+ ...itemsField,
194
+ arrayFields: {
195
+ image: createSlideImageField(),
196
+ title: { type: 'text', label: 'Title' },
197
+ titlePlacement: itemsField.arrayFields?.titlePlacement ?? {
198
+ type: 'select',
199
+ label: 'Title placement',
200
+ options: [
201
+ { label: 'Hidden', value: 'none' },
202
+ { label: 'Top left', value: 'top-left' },
203
+ { label: 'Top center', value: 'top-center' },
204
+ { label: 'Top right', value: 'top-right' },
205
+ { label: 'Center', value: 'center' },
206
+ { label: 'Bottom left', value: 'bottom-left' },
207
+ { label: 'Bottom center', value: 'bottom-center' },
208
+ { label: 'Bottom right', value: 'bottom-right' },
209
+ ],
210
+ },
211
+ ...(itemsField.arrayFields?.titleBackground
212
+ ? { titleBackground: itemsField.arrayFields.titleBackground }
213
+ : {}),
214
+ ...(itemsField.arrayFields?.titleColor
215
+ ? { titleColor: itemsField.arrayFields.titleColor }
216
+ : {}),
217
+ ...(itemsField.arrayFields?.titleBorderColor
218
+ ? { titleBorderColor: itemsField.arrayFields.titleBorderColor }
219
+ : {}),
220
+ ...(itemsField.arrayFields?.titleBorderWidth
221
+ ? { titleBorderWidth: itemsField.arrayFields.titleBorderWidth }
222
+ : {}),
223
+ ...(itemsField.arrayFields?.titleBorderRadius
224
+ ? { titleBorderRadius: itemsField.arrayFields.titleBorderRadius }
225
+ : {}),
226
+ ...(itemsField.arrayFields?.titlePaddingPx
227
+ ? { titlePaddingPx: itemsField.arrayFields.titlePaddingPx }
228
+ : {}),
229
+ },
230
+ }
231
+ : itemsField,
232
+ },
233
+ };
234
+ }
235
+ for (const name of ['cms.Row', 'cms.Column', 'cms.Hero', 'cms.Testimonial', 'cms.NewsletterSignup']) {
236
+ const cfg = components[name];
237
+ if (cfg) {
238
+ components[name] = {
239
+ ...cfg,
240
+ fields: {
241
+ ...cfg.fields,
242
+ background: createAdminBackgroundField(),
243
+ },
244
+ };
245
+ }
246
+ }
247
+ const testimonial = components['cms.Testimonial'];
248
+ if (testimonial) {
249
+ components['cms.Testimonial'] = {
250
+ ...testimonial,
251
+ fields: {
252
+ ...testimonial.fields,
253
+ avatarSource: createImageSourceField(),
254
+ avatarUrl: createImageUrlField('Avatar URL'),
255
+ avatarAssetId: createImageAssetField('Avatar'),
256
+ },
257
+ };
258
+ }
259
+ const logoStrip = components['cms.LogoStrip'];
260
+ if (logoStrip) {
261
+ const itemsField = logoStrip.fields?.items;
262
+ components['cms.LogoStrip'] = {
263
+ ...logoStrip,
264
+ fields: {
265
+ ...logoStrip.fields,
266
+ items: itemsField && itemsField.type === 'array'
267
+ ? {
268
+ ...itemsField,
269
+ arrayFields: {
270
+ image: createSlideImageField(),
271
+ alt: itemsField.arrayFields?.alt ?? { type: 'text', label: 'Alt text' },
272
+ href: itemsField.arrayFields?.href ?? {
273
+ type: 'text',
274
+ label: 'Link URL (optional)',
275
+ },
276
+ },
277
+ }
278
+ : itemsField,
279
+ },
280
+ };
281
+ }
282
+ // Feature 096, T306 — **the descriptor is filtered by context here.**
283
+ // Until Phase 3 it carried only the 35 CMS names, so every entry belonged in
284
+ // this palette by construction; it now carries all 74 a platform composes,
285
+ // and an unfiltered sweep would put 39 e-mail and invoice blocks into this
286
+ // editor as missing-renderer placeholders.
287
+ const declared = (descriptor?.components ?? []).filter((entry) => contextAdmits(entry.contexts ?? ['cms'], context));
288
+ for (const entry of declared) {
289
+ if (components[entry.name])
290
+ continue;
291
+ // `visible: true` because this is an editing surface: the operator has to be
292
+ // told which module a block is waiting on. The parameter had no caller until
293
+ // feature 096's T602 and the placeholder read the `?cms_admin=1` preview
294
+ // parameter instead, which nothing in this repository sets — so every
295
+ // placeholder the editor merged rendered an empty span.
296
+ components[entry.name] = makeMissingComponentConfig(entry.name, entry.ownerModule, {
297
+ visible: true,
298
+ });
299
+ }
300
+ // The sections come from the modules that declared them, resolved and merged
301
+ // by the registry (`contracts/block-definition.md` §1.1 and §4.1.1). The
302
+ // hand-written `categories` map this replaced lived in `cms-components` and
303
+ // listed five of `catalog`'s blocks.
304
+ const categories = buildPaletteCategories(declared, descriptor?.categories ?? [], context, {
305
+ title: (section) => sectionTitle(section.ownerModule ?? 'cms', section.titleKey, section.key),
306
+ renderable: new Set(Object.keys(components)),
307
+ });
308
+ // Anything the descriptor declares for this context but no declared section
309
+ // holds still has to be reachable, or it is a block an operator can never
310
+ // insert. That is the *Extensions* drawer's job and it stays.
311
+ const sectioned = new Set(Object.values(categories).flatMap((c) => c.components ?? []));
312
+ const unsectioned = declared.map((entry) => entry.name).filter((name) => !sectioned.has(name));
313
+ return {
314
+ ...base,
315
+ components,
316
+ categories: unsectioned.length > 0
317
+ ? { ...categories, extensions: { title: extensionTitle, components: unsectioned } }
318
+ : categories,
319
+ };
320
+ }
321
+ export function PageBuilderEditor({ data, onChange, contentKey, pageContainer = false, context = 'cms', languages = [], activeLanguage = null, onResolveLanguageContent, onSaveAsTemplate, onListTemplatesForApply, onResolveTemplateLayout, }) {
322
+ const t = useTranslation('cms');
323
+ // A section's `titleKey` is **module-relative** and belongs to the module
324
+ // whose declaration won the merge, so it is resolved in that module's scope
325
+ // and not in `cms`' (`contracts/block-definition.md` §2). The key itself is
326
+ // the fallback the resolver already renders for a key it cannot find; the
327
+ // section key is a last resort so a drawer is never headed with nothing.
328
+ const { t: translateInScope } = useTranslationContext();
329
+ const sectionTitle = useCallback((ownerModule, titleKey, fallback) => {
330
+ const resolved = translateInScope(ownerModule, titleKey);
331
+ return resolved === `${ownerModule}.${titleKey}` ? fallback : resolved;
332
+ }, [translateInScope]);
333
+ // The shared page-builder chrome (`PageBuilderHeaderShell`,
334
+ // `PageBuilderTemplateActions`, `PageBuilderHeaderActions`) owns no module
335
+ // knowledge and reads `core`; this screen's own strings stay `cms`' (feature
336
+ // 091 P5a, R-1).
337
+ const tChrome = useTranslation('core');
338
+ const [descriptor, setDescriptor] = useState(null);
339
+ /**
340
+ * A block's palette label, from the declaring module's own bundle.
341
+ *
342
+ * Same rule as the section title and for the same reason: `labelKey` is
343
+ * module-relative, and after Phase 3 five of the CMS palette's entries are
344
+ * `catalog`'s. Falls through to `applyPageBuilderTranslations`' legacy
345
+ * `pageBuilder.components.<name>` key when the descriptor has not been
346
+ * fetched yet, which is the first render.
347
+ */
348
+ const blockLabel = useCallback((name) => {
349
+ const entry = descriptor?.components.find((component) => component.name === name);
350
+ if (!entry?.labelKey)
351
+ return undefined;
352
+ const resolved = translateInScope(entry.ownerModule, entry.labelKey);
353
+ return resolved === `${entry.ownerModule}.${entry.labelKey}` ? undefined : resolved;
354
+ }, [descriptor, translateInScope]);
355
+ const [blockOptions, setBlockOptions] = useState([]);
356
+ const [embeds, setEmbeds] = useState({ blocks: {}, templates: {} });
357
+ const [error, setError] = useState(null);
358
+ const [fullscreen, setFullscreen] = useState(false);
359
+ const [rowLayoutPickerForId, setRowLayoutPickerForId] = useState(null);
360
+ /** Bumped on clear / copy-from so Puck remounts (data prop is mount-only). */
361
+ const [canvasEpoch, setCanvasEpoch] = useState(0);
362
+ const dispatchRef = useRef(null);
363
+ // Allow exiting fullscreen with Escape.
364
+ useEffect(() => {
365
+ if (!fullscreen)
366
+ return undefined;
367
+ const onKey = (e) => {
368
+ if (e.key === 'Escape')
369
+ setFullscreen(false);
370
+ };
371
+ window.addEventListener('keydown', onKey);
372
+ return () => window.removeEventListener('keydown', onKey);
373
+ }, [fullscreen]);
374
+ useEffect(() => {
375
+ let live = true;
376
+ cmsClient
377
+ .getPageBuilderConfig()
378
+ .then((result) => {
379
+ if (live)
380
+ setDescriptor(result);
381
+ })
382
+ .catch((err) => {
383
+ if (live)
384
+ setError(err instanceof Error ? err.message : String(err));
385
+ });
386
+ return () => {
387
+ live = false;
388
+ };
389
+ }, []);
390
+ // Available CMS blocks power the InsertBlock dropdown; their resolved content
391
+ // (and templates') power the on-canvas embed previews. Best-effort: any
392
+ // failure degrades to an empty dropdown / code-only placeholder rather than
393
+ // breaking the editor.
394
+ useEffect(() => {
395
+ let live = true;
396
+ void (async () => {
397
+ const [blockRes, templateRes] = await Promise.all([
398
+ cmsClient.listBlocks().catch(() => ({ data: [] })),
399
+ cmsClient.listTemplates().catch(() => ({ data: [] })),
400
+ ]);
401
+ if (!live)
402
+ return;
403
+ setBlockOptions(blockRes.data.map((b) => ({
404
+ label: b.name ? `${b.name} (${b.code})` : b.code,
405
+ value: b.code,
406
+ })));
407
+ const blockPreviews = {};
408
+ await Promise.all(blockRes.data.map(async (b) => {
409
+ try {
410
+ const detail = await cmsClient.getBlock(b.id);
411
+ blockPreviews[b.code] = previewNode(detail.content);
412
+ }
413
+ catch {
414
+ /* leave the code-only fallback */
415
+ }
416
+ }));
417
+ const templatePreviews = {};
418
+ await Promise.all(templateRes.data.map(async (tpl) => {
419
+ try {
420
+ const detail = await cmsClient.getTemplate(tpl.id);
421
+ templatePreviews[tpl.code] = previewNode(detail.content);
422
+ }
423
+ catch {
424
+ /* leave the code-only fallback */
425
+ }
426
+ }));
427
+ if (live)
428
+ setEmbeds({ blocks: blockPreviews, templates: templatePreviews });
429
+ })();
430
+ return () => {
431
+ live = false;
432
+ };
433
+ }, []);
434
+ const viewports = useMemo(() => buildViewports(descriptor), [descriptor]);
435
+ const plugins = useMemo(() => [createPageBuilderEditorPlugin()], []);
436
+ /** Holds canvas data across remount until parent `data` catches up (clear / copy-from). */
437
+ const pendingSeedRef = useRef(null);
438
+ const editorData = pendingSeedRef.current ?? data ?? emptyData;
439
+ /**
440
+ * The block names the loaded document carries, as a stable key.
441
+ *
442
+ * `editorData` changes identity on every keystroke and the set of names it
443
+ * holds almost never does, so keying the config on the document would rebuild
444
+ * the whole Puck config while an author types. The key is what the
445
+ * degradation merge below actually depends on (feature 096, T602).
446
+ */
447
+ const storedBlockNamesKey = useMemo(() => [...countBlockNames(editorData).keys()].sort().join('\n'), [editorData]);
448
+ const config = useMemo(() => {
449
+ const merged = mergeConfig(descriptor, t('pageBuilder.extensions'), blockOptions, context, sectionTitle);
450
+ const filtered = filterConfigByContext(merged, context);
451
+ // FR-019/FR-020 — a stored block nothing here can render degrades to the
452
+ // placeholder rather than vanishing from the canvas. **After** the context
453
+ // filter and after the categories, deliberately: the block stays visible and
454
+ // editable where it already is, and is not something an operator may insert.
455
+ const degraded = withMissingBlockPlaceholders(filtered, storedBlockNamesKey === '' ? [] : storedBlockNamesKey.split('\n'));
456
+ const rooted = pageContainer ? withCmsPageRoot(degraded) : degraded;
457
+ return applyPageBuilderTranslations(rooted, t, blockLabel);
458
+ }, [
459
+ descriptor,
460
+ t,
461
+ sectionTitle,
462
+ blockLabel,
463
+ blockOptions,
464
+ pageContainer,
465
+ context,
466
+ storedBlockNamesKey,
467
+ ]);
468
+ const lastValidDataRef = useRef(editorData);
469
+ const knownRowIdsRef = useRef(collectRowIds(editorData));
470
+ useEffect(() => {
471
+ pendingSeedRef.current = null;
472
+ lastValidDataRef.current = data ?? emptyData;
473
+ knownRowIdsRef.current = collectRowIds(data ?? emptyData);
474
+ setRowLayoutPickerForId(null);
475
+ setCanvasEpoch(0);
476
+ // Only reseed when switching page/language — not on every draft edit.
477
+ // eslint-disable-next-line react-hooks/exhaustive-deps -- data intentionally omitted
478
+ }, [contentKey]);
479
+ useEffect(() => {
480
+ lastValidDataRef.current = editorData;
481
+ }, [editorData]);
482
+ const handleEditorChange = useCallback((next) => {
483
+ if (hasInvalidColumnPlacement(next)) {
484
+ dispatchRef.current?.({
485
+ type: 'setData',
486
+ data: lastValidDataRef.current,
487
+ recordHistory: false,
488
+ });
489
+ return;
490
+ }
491
+ pendingSeedRef.current = null;
492
+ const nextRowIds = collectRowIds(next);
493
+ let newRowId = null;
494
+ for (const id of nextRowIds) {
495
+ if (!knownRowIdsRef.current.has(id)) {
496
+ newRowId = id;
497
+ break;
498
+ }
499
+ }
500
+ knownRowIdsRef.current = nextRowIds;
501
+ lastValidDataRef.current = next;
502
+ onChange(next);
503
+ if (newRowId) {
504
+ const rowId = newRowId;
505
+ window.setTimeout(() => setRowLayoutPickerForId(rowId), 0);
506
+ }
507
+ }, [onChange]);
508
+ const applyCanvasData = useCallback((next) => {
509
+ pendingSeedRef.current = next;
510
+ lastValidDataRef.current = next;
511
+ knownRowIdsRef.current = collectRowIds(next);
512
+ onChange(next);
513
+ // Puck treats `data` as initial only — remount so the canvas reseeds.
514
+ setCanvasEpoch((epoch) => epoch + 1);
515
+ }, [onChange]);
516
+ const headerActionsStateRef = useRef({
517
+ fullscreen,
518
+ setFullscreen,
519
+ tChrome,
520
+ languages,
521
+ activeLanguage,
522
+ editorData: data ?? emptyPageBuilderData(),
523
+ onCopyFromLanguage: null,
524
+ onClearCanvas: null,
525
+ onSaveAsTemplate: null,
526
+ onListTemplatesForApply: null,
527
+ onApplyTemplate: null,
528
+ drawerSearchPlaceholder: t('pageBuilder.drawer.searchPlaceholder'),
529
+ drawerSearchEmpty: t('pageBuilder.drawer.searchEmpty'),
530
+ });
531
+ headerActionsStateRef.current = {
532
+ fullscreen,
533
+ setFullscreen,
534
+ tChrome,
535
+ languages,
536
+ activeLanguage,
537
+ editorData: editorData,
538
+ onCopyFromLanguage: onResolveLanguageContent
539
+ ? async (sourceLanguage) => {
540
+ const resolved = await onResolveLanguageContent(sourceLanguage);
541
+ if (isEmptyPageBuilderData(resolved)) {
542
+ throw new Error(t('pageBuilder.copyLanguage.emptySource'));
543
+ }
544
+ applyCanvasData(structuredClone(resolved));
545
+ }
546
+ : null,
547
+ onClearCanvas: () => {
548
+ applyCanvasData(emptyPageBuilderData());
549
+ },
550
+ onSaveAsTemplate: onSaveAsTemplate
551
+ ? async (meta, canvasData) => {
552
+ await onSaveAsTemplate(meta, canvasData);
553
+ }
554
+ : null,
555
+ onListTemplatesForApply: onListTemplatesForApply ?? null,
556
+ onApplyTemplate: onResolveTemplateLayout
557
+ ? async (templateId) => {
558
+ const next = await onResolveTemplateLayout(templateId);
559
+ applyCanvasData(structuredClone(next));
560
+ }
561
+ : null,
562
+ drawerSearchPlaceholder: t('pageBuilder.drawer.searchPlaceholder'),
563
+ drawerSearchEmpty: t('pageBuilder.drawer.searchEmpty'),
564
+ };
565
+ const applyRowPreset = useCallback((rowId, presetId) => {
566
+ dispatchRef.current?.({
567
+ type: 'setData',
568
+ data: (previous) => {
569
+ const row = findRowById(previous, rowId);
570
+ if (!row)
571
+ return previous;
572
+ const nextProps = applyRowLayoutPreset(row.props, presetId);
573
+ return replaceRowInData(previous, rowId, { type: 'cms.Row', props: { ...nextProps, id: rowId } });
574
+ },
575
+ });
576
+ }, []);
577
+ const handlePuckAction = useMemo(() => createPuckActionHandler(dispatchRef, (action, appState) => {
578
+ if (action.type !== 'insert' || action.componentType !== 'cms.Row')
579
+ return;
580
+ const rowId = resolveInsertedRowId(action, appState.data);
581
+ if (!rowId)
582
+ return;
583
+ if (!isContentSliderSlidesZone(action.destinationZone, appState.data))
584
+ return;
585
+ const inserted = insertedItem(action, appState.data) ??
586
+ findRowById(appState.data, rowId) ?? {
587
+ type: 'cms.Row',
588
+ props: { id: rowId, content: [] },
589
+ };
590
+ dispatchRef.current?.({
591
+ type: 'setData',
592
+ data: (previous) => wrapRowInContentSliderSlide(previous, action.destinationZone, action.destinationIndex, inserted),
593
+ recordHistory: false,
594
+ });
595
+ }), []);
596
+ const puckOverrides = useMemo(() => ({
597
+ puck: ({ children }) => (_jsx(PuckDispatchBridgeSlot, { dispatchRef: dispatchRef, children: children })),
598
+ actionBar: (props) => _jsx(PageBuilderActionBar, { ...props }),
599
+ componentOverlay: (props) => _jsx(PageBuilderOverlayBridge, { ...props }),
600
+ drawerItem: ({ name, children, }) => (name === 'cms.Column' || name === 'cms.Slide' ? _jsx(_Fragment, {}) : _jsx(_Fragment, { children: children })),
601
+ drawer: ({ children }) => {
602
+ const state = headerActionsStateRef.current;
603
+ return (_jsx(PageBuilderDrawer, { searchPlaceholder: state.drawerSearchPlaceholder, emptyLabel: state.drawerSearchEmpty, children: children }));
604
+ },
605
+ header: ({ children }) => {
606
+ const state = headerActionsStateRef.current;
607
+ const hasTemplates = Boolean(state.onSaveAsTemplate || state.onApplyTemplate);
608
+ return (_jsx(PageBuilderHeaderShell, { leading: hasTemplates ? (_jsx(PageBuilderTemplateActions, { currentData: state.editorData, ...(state.onSaveAsTemplate ? { onSaveAsTemplate: state.onSaveAsTemplate } : {}), ...(state.onListTemplatesForApply
609
+ ? { onListTemplatesForApply: state.onListTemplatesForApply }
610
+ : {}), ...(state.onApplyTemplate
611
+ ? {
612
+ onApplyTemplate: async (templateId) => {
613
+ await state.onApplyTemplate?.(templateId);
614
+ },
615
+ }
616
+ : {}), t: state.tChrome })) : null, children: children }));
617
+ },
618
+ headerActions: () => {
619
+ const state = headerActionsStateRef.current;
620
+ return (_jsx(PageBuilderHeaderActions, { fullscreen: state.fullscreen, onToggleFullscreen: () => state.setFullscreen((f) => !f), languages: state.languages, activeLanguage: state.activeLanguage, currentData: state.editorData, ...(state.onCopyFromLanguage ? { onCopyFromLanguage: state.onCopyFromLanguage } : {}), ...(state.onClearCanvas ? { onClearCanvas: state.onClearCanvas } : {}), t: state.tChrome }));
621
+ },
622
+ }), []);
623
+ return (_jsxs("div", { className: cn('cms-page-builder space-y-3', fullscreen && 'fixed inset-0 z-50 flex flex-col overflow-auto bg-background p-4'), children: [error ? (_jsx(Alert, { variant: "destructive", children: _jsx(AlertDescription, { children: error }) })) : null, !descriptor && !error ? (_jsx("p", { className: "text-sm text-muted-foreground", children: t('pageBuilder.loadingConfig') })) : null, _jsx("div", { className: cn('cms-page-builder__canvas overflow-x-auto overflow-y-auto border', fullscreen ? 'min-h-0 flex-1 rounded-md' : 'min-h-[640px] rounded-md'), children: _jsx(AdminCmsAssetProvider, { embeds: embeds, data: editorData, children: _jsx(AdminCatalogPreviewProvider, { children: _jsx(PageBuilderColorPaletteProvider, { initialEntries: descriptor?.colorPalette ?? [], children: _jsx(Puck, { config: config, data: editorData, onChange: handleEditorChange, onAction: handlePuckAction, viewports: viewports, iframe: { enabled: true, waitForStyles: true }, plugins: plugins, overrides: puckOverrides }, `${contentKey ?? 'pb'}:${canvasEpoch}`) }) }) }) }), _jsx(RowLayoutPicker, { open: rowLayoutPickerForId !== null, onOpenChange: (open) => {
624
+ if (!open)
625
+ setRowLayoutPickerForId(null);
626
+ }, onSelect: (presetId) => {
627
+ if (rowLayoutPickerForId)
628
+ applyRowPreset(rowLayoutPickerForId, presetId);
629
+ setRowLayoutPickerForId(null);
630
+ } })] }));
631
+ }
632
+ //# sourceMappingURL=PageBuilderEditor.js.map