@prenta/admin 0.92.0 → 0.94.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 (425) hide show
  1. package/CHANGELOG.md +663 -0
  2. package/design-system/tokens.css +173 -71
  3. package/design-system/tokens.json +244 -63
  4. package/design-system/tokens.scss +203 -98
  5. package/design-system/tokens.tailwind.cjs +93 -38
  6. package/dist/AdminRoot.d.ts +27 -6
  7. package/dist/AdminRoot.d.ts.map +1 -1
  8. package/dist/AdminRoot.js.map +1 -1
  9. package/dist/__tests__/components/breakpoint-controls.render.test.d.ts +2 -0
  10. package/dist/__tests__/components/breakpoint-controls.render.test.d.ts.map +1 -0
  11. package/dist/__tests__/components/breakpoint-controls.render.test.js +51 -0
  12. package/dist/__tests__/components/breakpoint-controls.render.test.js.map +1 -0
  13. package/dist/__tests__/components/canvas-edit-tip.render.test.d.ts +2 -0
  14. package/dist/__tests__/components/canvas-edit-tip.render.test.d.ts.map +1 -0
  15. package/dist/__tests__/components/canvas-edit-tip.render.test.js +37 -0
  16. package/dist/__tests__/components/canvas-edit-tip.render.test.js.map +1 -0
  17. package/dist/__tests__/components/editor-rail.render.test.d.ts +2 -0
  18. package/dist/__tests__/components/editor-rail.render.test.d.ts.map +1 -0
  19. package/dist/__tests__/components/editor-rail.render.test.js +138 -0
  20. package/dist/__tests__/components/editor-rail.render.test.js.map +1 -0
  21. package/dist/__tests__/components/media-block.render.test.d.ts +2 -0
  22. package/dist/__tests__/components/media-block.render.test.d.ts.map +1 -0
  23. package/dist/__tests__/components/media-block.render.test.js +108 -0
  24. package/dist/__tests__/components/media-block.render.test.js.map +1 -0
  25. package/dist/__tests__/components/page-audit-panel.render.test.d.ts +2 -0
  26. package/dist/__tests__/components/page-audit-panel.render.test.d.ts.map +1 -0
  27. package/dist/__tests__/components/page-audit-panel.render.test.js +59 -0
  28. package/dist/__tests__/components/page-audit-panel.render.test.js.map +1 -0
  29. package/dist/__tests__/components/reflow-meter.render.test.d.ts +2 -0
  30. package/dist/__tests__/components/reflow-meter.render.test.d.ts.map +1 -0
  31. package/dist/__tests__/components/reflow-meter.render.test.js +94 -0
  32. package/dist/__tests__/components/reflow-meter.render.test.js.map +1 -0
  33. package/dist/__tests__/components/seo-char-count.test.js +24 -6
  34. package/dist/__tests__/components/seo-char-count.test.js.map +1 -1
  35. package/dist/__tests__/components/serp-preview.render.test.d.ts +2 -0
  36. package/dist/__tests__/components/serp-preview.render.test.d.ts.map +1 -0
  37. package/dist/__tests__/components/serp-preview.render.test.js +25 -0
  38. package/dist/__tests__/components/serp-preview.render.test.js.map +1 -0
  39. package/dist/__tests__/lib/breakpoints.test.d.ts +2 -0
  40. package/dist/__tests__/lib/breakpoints.test.d.ts.map +1 -0
  41. package/dist/__tests__/lib/breakpoints.test.js +67 -0
  42. package/dist/__tests__/lib/breakpoints.test.js.map +1 -0
  43. package/dist/__tests__/lib/canvas-edit-chrome.test.d.ts +2 -0
  44. package/dist/__tests__/lib/canvas-edit-chrome.test.d.ts.map +1 -0
  45. package/dist/__tests__/lib/canvas-edit-chrome.test.js +44 -0
  46. package/dist/__tests__/lib/canvas-edit-chrome.test.js.map +1 -0
  47. package/dist/__tests__/lib/media-format.test.d.ts +2 -0
  48. package/dist/__tests__/lib/media-format.test.d.ts.map +1 -0
  49. package/dist/__tests__/lib/media-format.test.js +70 -0
  50. package/dist/__tests__/lib/media-format.test.js.map +1 -0
  51. package/dist/__tests__/lib/page-audit-input.test.d.ts +2 -0
  52. package/dist/__tests__/lib/page-audit-input.test.d.ts.map +1 -0
  53. package/dist/__tests__/lib/page-audit-input.test.js +122 -0
  54. package/dist/__tests__/lib/page-audit-input.test.js.map +1 -0
  55. package/dist/__tests__/lib/page-editor-service.test.js +2 -0
  56. package/dist/__tests__/lib/page-editor-service.test.js.map +1 -1
  57. package/dist/__tests__/lib/page-redirect.test.d.ts +2 -0
  58. package/dist/__tests__/lib/page-redirect.test.d.ts.map +1 -0
  59. package/dist/__tests__/lib/page-redirect.test.js +26 -0
  60. package/dist/__tests__/lib/page-redirect.test.js.map +1 -0
  61. package/dist/__tests__/lib/rail-width.test.d.ts +2 -0
  62. package/dist/__tests__/lib/rail-width.test.d.ts.map +1 -0
  63. package/dist/__tests__/lib/rail-width.test.js +69 -0
  64. package/dist/__tests__/lib/rail-width.test.js.map +1 -0
  65. package/dist/__tests__/lib/reflow-baseline.test.d.ts +2 -0
  66. package/dist/__tests__/lib/reflow-baseline.test.d.ts.map +1 -0
  67. package/dist/__tests__/lib/reflow-baseline.test.js +56 -0
  68. package/dist/__tests__/lib/reflow-baseline.test.js.map +1 -0
  69. package/dist/__tests__/lib/reflow-probe.test.d.ts +2 -0
  70. package/dist/__tests__/lib/reflow-probe.test.d.ts.map +1 -0
  71. package/dist/__tests__/lib/reflow-probe.test.js +73 -0
  72. package/dist/__tests__/lib/reflow-probe.test.js.map +1 -0
  73. package/dist/__tests__/lib/version-diff.test.d.ts +2 -0
  74. package/dist/__tests__/lib/version-diff.test.d.ts.map +1 -0
  75. package/dist/__tests__/lib/version-diff.test.js +230 -0
  76. package/dist/__tests__/lib/version-diff.test.js.map +1 -0
  77. package/dist/__tests__/lib/version-history.test.d.ts +2 -0
  78. package/dist/__tests__/lib/version-history.test.d.ts.map +1 -0
  79. package/dist/__tests__/lib/version-history.test.js +125 -0
  80. package/dist/__tests__/lib/version-history.test.js.map +1 -0
  81. package/dist/__tests__/styles/canvas-container-queries.test.d.ts +2 -0
  82. package/dist/__tests__/styles/canvas-container-queries.test.d.ts.map +1 -0
  83. package/dist/__tests__/styles/canvas-container-queries.test.js +87 -0
  84. package/dist/__tests__/styles/canvas-container-queries.test.js.map +1 -0
  85. package/dist/__tests__/styles/packaging.test.d.ts +2 -0
  86. package/dist/__tests__/styles/packaging.test.d.ts.map +1 -0
  87. package/dist/__tests__/styles/packaging.test.js +31 -0
  88. package/dist/__tests__/styles/packaging.test.js.map +1 -0
  89. package/dist/__tests__/styles/responsive-layer.test.d.ts +2 -0
  90. package/dist/__tests__/styles/responsive-layer.test.d.ts.map +1 -0
  91. package/dist/__tests__/styles/responsive-layer.test.js +127 -0
  92. package/dist/__tests__/styles/responsive-layer.test.js.map +1 -0
  93. package/dist/__tests__/styles/tokens-drift.test.d.ts +2 -0
  94. package/dist/__tests__/styles/tokens-drift.test.d.ts.map +1 -0
  95. package/dist/__tests__/styles/tokens-drift.test.js +92 -0
  96. package/dist/__tests__/styles/tokens-drift.test.js.map +1 -0
  97. package/dist/__tests__/views/admin-renderer-compat.test.d.ts +2 -0
  98. package/dist/__tests__/views/admin-renderer-compat.test.d.ts.map +1 -0
  99. package/dist/__tests__/views/admin-renderer-compat.test.js +43 -0
  100. package/dist/__tests__/views/admin-renderer-compat.test.js.map +1 -0
  101. package/dist/__tests__/views/admin-section-renderers.test.js +52 -4
  102. package/dist/__tests__/views/admin-section-renderers.test.js.map +1 -1
  103. package/dist/__tests__/views/canvas-review-mode.render.test.d.ts +2 -0
  104. package/dist/__tests__/views/canvas-review-mode.render.test.d.ts.map +1 -0
  105. package/dist/__tests__/views/canvas-review-mode.render.test.js +70 -0
  106. package/dist/__tests__/views/canvas-review-mode.render.test.js.map +1 -0
  107. package/dist/__tests__/views/editor-top-bar.render.test.js +30 -1
  108. package/dist/__tests__/views/editor-top-bar.render.test.js.map +1 -1
  109. package/dist/__tests__/views/page-tab.render.test.d.ts +2 -0
  110. package/dist/__tests__/views/page-tab.render.test.d.ts.map +1 -0
  111. package/dist/__tests__/views/page-tab.render.test.js +151 -0
  112. package/dist/__tests__/views/page-tab.render.test.js.map +1 -0
  113. package/dist/__tests__/views/section-class-parity.test.d.ts +2 -0
  114. package/dist/__tests__/views/section-class-parity.test.d.ts.map +1 -0
  115. package/dist/__tests__/views/section-class-parity.test.js +81 -0
  116. package/dist/__tests__/views/section-class-parity.test.js.map +1 -0
  117. package/dist/__tests__/views/sections-panel-design-owned.render.test.d.ts +2 -0
  118. package/dist/__tests__/views/sections-panel-design-owned.render.test.d.ts.map +1 -0
  119. package/dist/__tests__/views/sections-panel-design-owned.render.test.js +86 -0
  120. package/dist/__tests__/views/sections-panel-design-owned.render.test.js.map +1 -0
  121. package/dist/__tests__/views/version-history-panel.render.test.d.ts +2 -0
  122. package/dist/__tests__/views/version-history-panel.render.test.d.ts.map +1 -0
  123. package/dist/__tests__/views/version-history-panel.render.test.js +153 -0
  124. package/dist/__tests__/views/version-history-panel.render.test.js.map +1 -0
  125. package/dist/components/BreakpointPicker.d.ts +18 -0
  126. package/dist/components/BreakpointPicker.d.ts.map +1 -0
  127. package/dist/components/BreakpointPicker.js +31 -0
  128. package/dist/components/BreakpointPicker.js.map +1 -0
  129. package/dist/components/CanvasEditTip.d.ts +6 -0
  130. package/dist/components/CanvasEditTip.d.ts.map +1 -0
  131. package/dist/components/CanvasEditTip.js +22 -0
  132. package/dist/components/CanvasEditTip.js.map +1 -0
  133. package/dist/components/EditorRail.d.ts +36 -0
  134. package/dist/components/EditorRail.d.ts.map +1 -0
  135. package/dist/components/EditorRail.js +104 -0
  136. package/dist/components/EditorRail.js.map +1 -0
  137. package/dist/components/EditorRailTabs.d.ts +32 -0
  138. package/dist/components/EditorRailTabs.d.ts.map +1 -0
  139. package/dist/components/EditorRailTabs.js +45 -0
  140. package/dist/components/EditorRailTabs.js.map +1 -0
  141. package/dist/components/MediaBlock.d.ts +49 -0
  142. package/dist/components/MediaBlock.d.ts.map +1 -0
  143. package/dist/components/MediaBlock.js +50 -0
  144. package/dist/components/MediaBlock.js.map +1 -0
  145. package/dist/components/ReflowMeter.d.ts +28 -0
  146. package/dist/components/ReflowMeter.d.ts.map +1 -0
  147. package/dist/components/ReflowMeter.js +42 -0
  148. package/dist/components/ReflowMeter.js.map +1 -0
  149. package/dist/components/ZoomChip.d.ts +17 -0
  150. package/dist/components/ZoomChip.d.ts.map +1 -0
  151. package/dist/components/ZoomChip.js +17 -0
  152. package/dist/components/ZoomChip.js.map +1 -0
  153. package/dist/components/breakpoint-icons.d.ts +3 -0
  154. package/dist/components/breakpoint-icons.d.ts.map +1 -0
  155. package/dist/components/breakpoint-icons.js +16 -0
  156. package/dist/components/breakpoint-icons.js.map +1 -0
  157. package/dist/components/page-tab/AuthorPicker.d.ts +31 -0
  158. package/dist/components/page-tab/AuthorPicker.d.ts.map +1 -0
  159. package/dist/components/page-tab/AuthorPicker.js +95 -0
  160. package/dist/components/page-tab/AuthorPicker.js.map +1 -0
  161. package/dist/components/page-tab/DirectiveSwitch.d.ts +38 -0
  162. package/dist/components/page-tab/DirectiveSwitch.d.ts.map +1 -0
  163. package/dist/components/page-tab/DirectiveSwitch.js +33 -0
  164. package/dist/components/page-tab/DirectiveSwitch.js.map +1 -0
  165. package/dist/components/seo/EditorSeoScoreBadge.d.ts +8 -1
  166. package/dist/components/seo/EditorSeoScoreBadge.d.ts.map +1 -1
  167. package/dist/components/seo/EditorSeoScoreBadge.js +2 -2
  168. package/dist/components/seo/EditorSeoScoreBadge.js.map +1 -1
  169. package/dist/components/seo/PageAuditPanel.d.ts +14 -0
  170. package/dist/components/seo/PageAuditPanel.d.ts.map +1 -0
  171. package/dist/components/seo/PageAuditPanel.js +59 -0
  172. package/dist/components/seo/PageAuditPanel.js.map +1 -0
  173. package/dist/components/seo/SeoCharCount.d.ts +19 -7
  174. package/dist/components/seo/SeoCharCount.d.ts.map +1 -1
  175. package/dist/components/seo/SeoCharCount.js +30 -16
  176. package/dist/components/seo/SeoCharCount.js.map +1 -1
  177. package/dist/components/seo/SeoEditorPane.d.ts +15 -1
  178. package/dist/components/seo/SeoEditorPane.d.ts.map +1 -1
  179. package/dist/components/seo/SeoEditorPane.js +118 -21
  180. package/dist/components/seo/SeoEditorPane.js.map +1 -1
  181. package/dist/components/seo/SerpPreview.d.ts +20 -0
  182. package/dist/components/seo/SerpPreview.d.ts.map +1 -0
  183. package/dist/components/seo/SerpPreview.js +6 -0
  184. package/dist/components/seo/SerpPreview.js.map +1 -0
  185. package/dist/hooks/usePageAudit.d.ts +41 -0
  186. package/dist/hooks/usePageAudit.d.ts.map +1 -0
  187. package/dist/hooks/usePageAudit.js +68 -0
  188. package/dist/hooks/usePageAudit.js.map +1 -0
  189. package/dist/hooks/useReflowGuard.d.ts +47 -0
  190. package/dist/hooks/useReflowGuard.d.ts.map +1 -0
  191. package/dist/hooks/useReflowGuard.js +52 -0
  192. package/dist/hooks/useReflowGuard.js.map +1 -0
  193. package/dist/layout/primitives/AdminShell.d.ts.map +1 -1
  194. package/dist/layout/primitives/AdminShell.js +2 -2
  195. package/dist/layout/primitives/AdminShell.js.map +1 -1
  196. package/dist/lib/breakpoints.d.ts +51 -0
  197. package/dist/lib/breakpoints.d.ts.map +1 -0
  198. package/dist/lib/breakpoints.js +84 -0
  199. package/dist/lib/breakpoints.js.map +1 -0
  200. package/dist/lib/canvas-edit-chrome.d.ts +22 -0
  201. package/dist/lib/canvas-edit-chrome.d.ts.map +1 -0
  202. package/dist/lib/canvas-edit-chrome.js +81 -0
  203. package/dist/lib/canvas-edit-chrome.js.map +1 -0
  204. package/dist/lib/media-format.d.ts +55 -0
  205. package/dist/lib/media-format.d.ts.map +1 -0
  206. package/dist/lib/media-format.js +93 -0
  207. package/dist/lib/media-format.js.map +1 -0
  208. package/dist/lib/page-audit-input.d.ts +45 -0
  209. package/dist/lib/page-audit-input.d.ts.map +1 -0
  210. package/dist/lib/page-audit-input.js +53 -0
  211. package/dist/lib/page-audit-input.js.map +1 -0
  212. package/dist/lib/page-editor-service.d.ts +12 -0
  213. package/dist/lib/page-editor-service.d.ts.map +1 -1
  214. package/dist/lib/page-editor-service.js +6 -0
  215. package/dist/lib/page-editor-service.js.map +1 -1
  216. package/dist/lib/page-redirect.d.ts +39 -0
  217. package/dist/lib/page-redirect.d.ts.map +1 -0
  218. package/dist/lib/page-redirect.js +38 -0
  219. package/dist/lib/page-redirect.js.map +1 -0
  220. package/dist/lib/rail-width.d.ts +23 -0
  221. package/dist/lib/rail-width.d.ts.map +1 -0
  222. package/dist/lib/rail-width.js +59 -0
  223. package/dist/lib/rail-width.js.map +1 -0
  224. package/dist/lib/reflow-baseline.d.ts +45 -0
  225. package/dist/lib/reflow-baseline.d.ts.map +1 -0
  226. package/dist/lib/reflow-baseline.js +38 -0
  227. package/dist/lib/reflow-baseline.js.map +1 -0
  228. package/dist/lib/reflow-probe.d.ts +159 -0
  229. package/dist/lib/reflow-probe.d.ts.map +1 -0
  230. package/dist/lib/reflow-probe.js +228 -0
  231. package/dist/lib/reflow-probe.js.map +1 -0
  232. package/dist/lib/seo-service.d.ts +10 -0
  233. package/dist/lib/seo-service.d.ts.map +1 -1
  234. package/dist/lib/seo-service.js.map +1 -1
  235. package/dist/lib/version-diff.d.ts +50 -0
  236. package/dist/lib/version-diff.d.ts.map +1 -0
  237. package/dist/lib/version-diff.js +294 -0
  238. package/dist/lib/version-diff.js.map +1 -0
  239. package/dist/lib/version-history.d.ts +73 -0
  240. package/dist/lib/version-history.d.ts.map +1 -0
  241. package/dist/lib/version-history.js +126 -0
  242. package/dist/lib/version-history.js.map +1 -0
  243. package/dist/prenta-admin.css +1 -1
  244. package/dist/views/page-editor/CanvasMetaLine.d.ts +19 -0
  245. package/dist/views/page-editor/CanvasMetaLine.d.ts.map +1 -0
  246. package/dist/views/page-editor/CanvasMetaLine.js +23 -0
  247. package/dist/views/page-editor/CanvasMetaLine.js.map +1 -0
  248. package/dist/views/page-editor/EditorCanvas.d.ts +47 -8
  249. package/dist/views/page-editor/EditorCanvas.d.ts.map +1 -1
  250. package/dist/views/page-editor/EditorCanvas.js +68 -34
  251. package/dist/views/page-editor/EditorCanvas.js.map +1 -1
  252. package/dist/views/page-editor/EditorTopBar.d.ts +21 -2
  253. package/dist/views/page-editor/EditorTopBar.d.ts.map +1 -1
  254. package/dist/views/page-editor/EditorTopBar.js +13 -20
  255. package/dist/views/page-editor/EditorTopBar.js.map +1 -1
  256. package/dist/views/page-editor/PageSectionEditor.d.ts.map +1 -1
  257. package/dist/views/page-editor/PageSectionEditor.js +383 -78
  258. package/dist/views/page-editor/PageSectionEditor.js.map +1 -1
  259. package/dist/views/page-editor/PageTab.d.ts +36 -0
  260. package/dist/views/page-editor/PageTab.d.ts.map +1 -0
  261. package/dist/views/page-editor/PageTab.js +65 -0
  262. package/dist/views/page-editor/PageTab.js.map +1 -0
  263. package/dist/views/page-editor/ReviewBar.d.ts +21 -0
  264. package/dist/views/page-editor/ReviewBar.d.ts.map +1 -0
  265. package/dist/views/page-editor/ReviewBar.js +22 -0
  266. package/dist/views/page-editor/ReviewBar.js.map +1 -0
  267. package/dist/views/page-editor/SectionInspector.d.ts.map +1 -1
  268. package/dist/views/page-editor/SectionInspector.js +64 -20
  269. package/dist/views/page-editor/SectionInspector.js.map +1 -1
  270. package/dist/views/page-editor/SectionsPanel.d.ts +30 -5
  271. package/dist/views/page-editor/SectionsPanel.d.ts.map +1 -1
  272. package/dist/views/page-editor/SectionsPanel.js +38 -7
  273. package/dist/views/page-editor/SectionsPanel.js.map +1 -1
  274. package/dist/views/page-editor/SitePreviewFrame.d.ts.map +1 -1
  275. package/dist/views/page-editor/SitePreviewFrame.js +3 -0
  276. package/dist/views/page-editor/SitePreviewFrame.js.map +1 -1
  277. package/dist/views/page-editor/VersionHistoryPanel.d.ts +29 -0
  278. package/dist/views/page-editor/VersionHistoryPanel.d.ts.map +1 -0
  279. package/dist/views/page-editor/VersionHistoryPanel.js +81 -0
  280. package/dist/views/page-editor/VersionHistoryPanel.js.map +1 -0
  281. package/dist/views/page-editor/reflow-context.d.ts +28 -0
  282. package/dist/views/page-editor/reflow-context.d.ts.map +1 -0
  283. package/dist/views/page-editor/reflow-context.js +14 -0
  284. package/dist/views/page-editor/reflow-context.js.map +1 -0
  285. package/dist/views/page-editor/sections/ByTheNumbersSection.d.ts.map +1 -1
  286. package/dist/views/page-editor/sections/ByTheNumbersSection.js +1 -1
  287. package/dist/views/page-editor/sections/ByTheNumbersSection.js.map +1 -1
  288. package/dist/views/page-editor/sections/CtaBannerSection.d.ts.map +1 -1
  289. package/dist/views/page-editor/sections/CtaBannerSection.js +1 -1
  290. package/dist/views/page-editor/sections/CtaBannerSection.js.map +1 -1
  291. package/dist/views/page-editor/sections/FeatureHighlightSection.d.ts.map +1 -1
  292. package/dist/views/page-editor/sections/FeatureHighlightSection.js +2 -2
  293. package/dist/views/page-editor/sections/FeatureHighlightSection.js.map +1 -1
  294. package/dist/views/page-editor/sections/GallerySection.d.ts.map +1 -1
  295. package/dist/views/page-editor/sections/GallerySection.js +7 -3
  296. package/dist/views/page-editor/sections/GallerySection.js.map +1 -1
  297. package/dist/views/page-editor/sections/HeroBannerSection.js +1 -1
  298. package/dist/views/page-editor/sections/HeroBannerSection.js.map +1 -1
  299. package/dist/views/page-editor/sections/MissionSection.d.ts.map +1 -1
  300. package/dist/views/page-editor/sections/MissionSection.js +1 -1
  301. package/dist/views/page-editor/sections/MissionSection.js.map +1 -1
  302. package/dist/views/page-editor/sections/PullQuoteSection.d.ts.map +1 -1
  303. package/dist/views/page-editor/sections/PullQuoteSection.js +1 -1
  304. package/dist/views/page-editor/sections/PullQuoteSection.js.map +1 -1
  305. package/dist/views/page-editor/sections/RelatedPostsSection.d.ts.map +1 -1
  306. package/dist/views/page-editor/sections/RelatedPostsSection.js +1 -1
  307. package/dist/views/page-editor/sections/RelatedPostsSection.js.map +1 -1
  308. package/dist/views/page-editor/sections/SectionRenderer.d.ts +13 -1
  309. package/dist/views/page-editor/sections/SectionRenderer.d.ts.map +1 -1
  310. package/dist/views/page-editor/sections/SectionRenderer.js +66 -26
  311. package/dist/views/page-editor/sections/SectionRenderer.js.map +1 -1
  312. package/dist/views/page-editor/sections/admin-renderers.d.ts +47 -15
  313. package/dist/views/page-editor/sections/admin-renderers.d.ts.map +1 -1
  314. package/dist/views/page-editor/sections/admin-renderers.js +27 -15
  315. package/dist/views/page-editor/sections/admin-renderers.js.map +1 -1
  316. package/dist/views/page-editor/sections/parts.d.ts +0 -1
  317. package/dist/views/page-editor/sections/parts.d.ts.map +1 -1
  318. package/dist/views/page-editor/sections/parts.js +41 -16
  319. package/dist/views/page-editor/sections/parts.js.map +1 -1
  320. package/dist/views/page-editor/viewports.d.ts +7 -14
  321. package/dist/views/page-editor/viewports.d.ts.map +1 -1
  322. package/dist/views/page-editor/viewports.js +7 -12
  323. package/dist/views/page-editor/viewports.js.map +1 -1
  324. package/dist/views/post-editor/PostEditorCanvas.d.ts +2 -1
  325. package/dist/views/post-editor/PostEditorCanvas.d.ts.map +1 -1
  326. package/dist/views/post-editor/PostEditorCanvas.js +5 -2
  327. package/dist/views/post-editor/PostEditorCanvas.js.map +1 -1
  328. package/dist/views/post-editor/PostSectionEditor.d.ts.map +1 -1
  329. package/dist/views/post-editor/PostSectionEditor.js +2 -20
  330. package/dist/views/post-editor/PostSectionEditor.js.map +1 -1
  331. package/dist/views/post-editor/PostTemplateEditor.d.ts.map +1 -1
  332. package/dist/views/post-editor/PostTemplateEditor.js +4 -1
  333. package/dist/views/post-editor/PostTemplateEditor.js.map +1 -1
  334. package/package.json +5 -3
  335. package/src/AdminRoot.tsx +27 -6
  336. package/src/__tests__/components/breakpoint-controls.render.test.tsx +57 -0
  337. package/src/__tests__/components/canvas-edit-tip.render.test.tsx +41 -0
  338. package/src/__tests__/components/editor-rail.render.test.tsx +192 -0
  339. package/src/__tests__/components/media-block.render.test.tsx +126 -0
  340. package/src/__tests__/components/page-audit-panel.render.test.tsx +64 -0
  341. package/src/__tests__/components/reflow-meter.render.test.tsx +144 -0
  342. package/src/__tests__/components/seo-char-count.test.tsx +26 -6
  343. package/src/__tests__/components/serp-preview.render.test.tsx +32 -0
  344. package/src/__tests__/lib/breakpoints.test.ts +84 -0
  345. package/src/__tests__/lib/canvas-edit-chrome.test.ts +56 -0
  346. package/src/__tests__/lib/media-format.test.ts +89 -0
  347. package/src/__tests__/lib/page-audit-input.test.ts +144 -0
  348. package/src/__tests__/lib/page-editor-service.test.ts +2 -0
  349. package/src/__tests__/lib/page-redirect.test.ts +29 -0
  350. package/src/__tests__/lib/rail-width.test.ts +86 -0
  351. package/src/__tests__/lib/reflow-baseline.test.ts +64 -0
  352. package/src/__tests__/lib/reflow-probe.test.ts +95 -0
  353. package/src/__tests__/lib/version-diff.test.ts +278 -0
  354. package/src/__tests__/lib/version-history.test.ts +166 -0
  355. package/src/__tests__/styles/canvas-container-queries.test.ts +103 -0
  356. package/src/__tests__/styles/packaging.test.ts +38 -0
  357. package/src/__tests__/styles/responsive-layer.test.ts +152 -0
  358. package/src/__tests__/styles/tokens-drift.test.ts +110 -0
  359. package/src/__tests__/views/admin-renderer-compat.test.ts +48 -0
  360. package/src/__tests__/views/admin-section-renderers.test.tsx +70 -4
  361. package/src/__tests__/views/canvas-review-mode.render.test.tsx +94 -0
  362. package/src/__tests__/views/editor-top-bar.render.test.tsx +43 -1
  363. package/src/__tests__/views/page-tab.render.test.tsx +226 -0
  364. package/src/__tests__/views/section-class-parity.test.ts +98 -0
  365. package/src/__tests__/views/sections-panel-design-owned.render.test.tsx +104 -0
  366. package/src/__tests__/views/version-history-panel.render.test.tsx +195 -0
  367. package/src/components/BreakpointPicker.tsx +114 -0
  368. package/src/components/CanvasEditTip.tsx +46 -0
  369. package/src/components/EditorRail.tsx +219 -0
  370. package/src/components/EditorRailTabs.tsx +117 -0
  371. package/src/components/MediaBlock.tsx +223 -0
  372. package/src/components/ReflowMeter.tsx +125 -0
  373. package/src/components/ZoomChip.tsx +39 -0
  374. package/src/components/breakpoint-icons.ts +17 -0
  375. package/src/components/page-tab/AuthorPicker.tsx +240 -0
  376. package/src/components/page-tab/DirectiveSwitch.tsx +89 -0
  377. package/src/components/seo/EditorSeoScoreBadge.tsx +9 -1
  378. package/src/components/seo/PageAuditPanel.tsx +192 -0
  379. package/src/components/seo/SeoCharCount.tsx +55 -24
  380. package/src/components/seo/SeoEditorPane.tsx +213 -31
  381. package/src/components/seo/SerpPreview.tsx +41 -0
  382. package/src/hooks/usePageAudit.ts +98 -0
  383. package/src/hooks/useReflowGuard.ts +96 -0
  384. package/src/layout/primitives/AdminShell.tsx +13 -1
  385. package/src/lib/breakpoints.ts +107 -0
  386. package/src/lib/canvas-edit-chrome.ts +82 -0
  387. package/src/lib/media-format.ts +99 -0
  388. package/src/lib/page-audit-input.ts +104 -0
  389. package/src/lib/page-editor-service.ts +18 -0
  390. package/src/lib/page-redirect.ts +60 -0
  391. package/src/lib/rail-width.ts +58 -0
  392. package/src/lib/reflow-baseline.ts +70 -0
  393. package/src/lib/reflow-probe.ts +299 -0
  394. package/src/lib/seo-service.ts +10 -0
  395. package/src/lib/version-diff.ts +376 -0
  396. package/src/lib/version-history.ts +192 -0
  397. package/src/styles/prenta-tokens.css +120 -42
  398. package/src/styles/responsive.css +281 -0
  399. package/src/styles/theme.css +138 -0
  400. package/src/views/page-editor/CanvasMetaLine.tsx +50 -0
  401. package/src/views/page-editor/EditorCanvas.tsx +140 -54
  402. package/src/views/page-editor/EditorTopBar.tsx +55 -51
  403. package/src/views/page-editor/PageSectionEditor.tsx +575 -185
  404. package/src/views/page-editor/PageTab.tsx +433 -0
  405. package/src/views/page-editor/ReviewBar.tsx +76 -0
  406. package/src/views/page-editor/SectionInspector.tsx +84 -42
  407. package/src/views/page-editor/SectionsPanel.tsx +282 -141
  408. package/src/views/page-editor/SitePreviewFrame.tsx +3 -0
  409. package/src/views/page-editor/VersionHistoryPanel.tsx +302 -0
  410. package/src/views/page-editor/reflow-context.ts +43 -0
  411. package/src/views/page-editor/sections/ByTheNumbersSection.tsx +3 -2
  412. package/src/views/page-editor/sections/CtaBannerSection.tsx +3 -1
  413. package/src/views/page-editor/sections/FeatureHighlightSection.tsx +3 -2
  414. package/src/views/page-editor/sections/GallerySection.tsx +7 -3
  415. package/src/views/page-editor/sections/HeroBannerSection.tsx +2 -2
  416. package/src/views/page-editor/sections/MissionSection.tsx +4 -2
  417. package/src/views/page-editor/sections/PullQuoteSection.tsx +3 -1
  418. package/src/views/page-editor/sections/RelatedPostsSection.tsx +2 -1
  419. package/src/views/page-editor/sections/SectionRenderer.tsx +115 -34
  420. package/src/views/page-editor/sections/admin-renderers.tsx +54 -15
  421. package/src/views/page-editor/sections/parts.tsx +46 -18
  422. package/src/views/page-editor/viewports.ts +13 -26
  423. package/src/views/post-editor/PostEditorCanvas.tsx +18 -11
  424. package/src/views/post-editor/PostSectionEditor.tsx +1 -56
  425. package/src/views/post-editor/PostTemplateEditor.tsx +3 -0
@@ -37,24 +37,161 @@ interface SectionsPanelProps {
37
37
  selectedId: string | null
38
38
  canEdit: boolean
39
39
  onSelect: (id: string) => void
40
- onReorder: (orderedIds: string[]) => void
41
40
  onToggleVisibility: (id: string) => void
42
- onDuplicate: (id: string) => void
43
- onRequestDelete: (id: string) => void
44
- onAdd: () => void
41
+ /**
42
+ * Permit structural editing — add, reorder, duplicate, delete.
43
+ *
44
+ * Defaults to FALSE. Pages and posts are design-owned: their section list
45
+ * comes from the template in code, and an editor changes copy, CTAs and
46
+ * imagery, never layout or order. Only the template editor — the surface
47
+ * that authors the template itself — opts in.
48
+ *
49
+ * The default is the restrictive one on purpose: a new consumer of this
50
+ * panel that forgets the flag gets the safe behaviour, not an editor that
51
+ * can quietly restructure a design-owned page.
52
+ */
53
+ structural?: boolean
54
+ /** Required when `structural`. */
55
+ onReorder?: (orderedIds: string[]) => void
56
+ onDuplicate?: (id: string) => void
57
+ onRequestDelete?: (id: string) => void
58
+ onAdd?: () => void
45
59
  }
46
60
 
47
- export function SectionsPanel({
61
+ /**
62
+ * Standalone panel — its own aside, header, and width. Used by the post
63
+ * TEMPLATE editor, which has no rail. The page and post editors render
64
+ * `SectionsList` inside `EditorRail` instead, so the rail owns the chrome.
65
+ */
66
+ export function SectionsPanel(props: SectionsPanelProps) {
67
+ return (
68
+ <aside
69
+ className="bg-card border-border flex h-full w-72 shrink-0 flex-col border-r"
70
+ aria-label="Page sections"
71
+ >
72
+ <div className="border-border flex items-center justify-between border-b px-6 py-4">
73
+ <div className="flex items-center gap-2">
74
+ <h2 className="text-foreground text-sm font-medium">Sections</h2>
75
+ <span className="bg-muted text-muted-foreground rounded-full px-2 py-0.5 text-xs font-medium tabular-nums">
76
+ {props.sections.length}
77
+ </span>
78
+ </div>
79
+ </div>
80
+ <SectionsList {...props} />
81
+ </aside>
82
+ )
83
+ }
84
+
85
+ /**
86
+ * The section outline itself — list plus footer. Fills whatever container it
87
+ * is given, so it works both inside the standalone panel above and inside the
88
+ * editor rail's Sections tab.
89
+ */
90
+ export function SectionsList({
48
91
  sections,
49
92
  selectedId,
50
93
  canEdit,
51
94
  onSelect,
52
- onReorder,
53
95
  onToggleVisibility,
96
+ structural = false,
97
+ onReorder,
54
98
  onDuplicate,
55
99
  onRequestDelete,
56
100
  onAdd,
57
101
  }: SectionsPanelProps) {
102
+ return (
103
+ <>
104
+ <div className="min-h-0 flex-1 overflow-y-auto p-2">
105
+ {sections.length === 0 ? (
106
+ <p className="text-muted-foreground px-2 py-6 text-center text-sm">
107
+ {structural
108
+ ? 'No sections yet. Add one below to get started.'
109
+ : 'This template renders no sections.'}
110
+ </p>
111
+ ) : structural ? (
112
+ <StructuralList
113
+ sections={sections}
114
+ selectedId={selectedId}
115
+ canEdit={canEdit}
116
+ onSelect={onSelect}
117
+ onReorder={onReorder}
118
+ onToggleVisibility={onToggleVisibility}
119
+ onDuplicate={onDuplicate}
120
+ onRequestDelete={onRequestDelete}
121
+ />
122
+ ) : (
123
+ <ul className="space-y-1">
124
+ {sections.map((section) => (
125
+ <SectionRow
126
+ key={section.id}
127
+ section={section}
128
+ selected={section.id === selectedId}
129
+ canEdit={canEdit}
130
+ structural={false}
131
+ onSelect={onSelect}
132
+ onToggleVisibility={onToggleVisibility}
133
+ />
134
+ ))}
135
+ </ul>
136
+ )}
137
+ </div>
138
+
139
+ {structural ? (
140
+ <div className="border-border border-t p-3">
141
+ <button
142
+ type="button"
143
+ onClick={onAdd}
144
+ disabled={!canEdit}
145
+ className="border-border text-foreground hover:bg-accent flex w-full items-center justify-center gap-2 rounded-lg border border-dashed px-3 py-2 text-sm font-medium transition-colors disabled:cursor-not-allowed disabled:opacity-50"
146
+ >
147
+ <Plus className="h-4 w-4" aria-hidden />
148
+ Add Section
149
+ </button>
150
+ </div>
151
+ ) : (
152
+ <DesignOwnedNote />
153
+ )}
154
+ </>
155
+ )
156
+ }
157
+
158
+ /**
159
+ * Explains the absence of add / reorder / delete. Without it the panel reads
160
+ * as broken rather than deliberate — "where did Add Section go" is the first
161
+ * question a returning editor asks.
162
+ */
163
+ function DesignOwnedNote() {
164
+ return (
165
+ <div className="border-border bg-background text-muted-foreground flex gap-2 border-t px-3 py-3 text-[11.5px] leading-normal">
166
+ <Lock className="mt-0.5 h-3.5 w-3.5 shrink-0" aria-hidden />
167
+ <p>
168
+ <strong className="text-foreground font-semibold">Layout is design-owned.</strong> Sections
169
+ and styling are built in code — here you edit headings, body copy, CTAs, and imagery. Hide a
170
+ section to drop it from the live page.
171
+ </p>
172
+ </div>
173
+ )
174
+ }
175
+
176
+ function StructuralList({
177
+ sections,
178
+ selectedId,
179
+ canEdit,
180
+ onSelect,
181
+ onReorder,
182
+ onToggleVisibility,
183
+ onDuplicate,
184
+ onRequestDelete,
185
+ }: {
186
+ sections: PageSection[]
187
+ selectedId: string | null
188
+ canEdit: boolean
189
+ onSelect: (id: string) => void
190
+ onReorder?: (orderedIds: string[]) => void
191
+ onToggleVisibility: (id: string) => void
192
+ onDuplicate?: (id: string) => void
193
+ onRequestDelete?: (id: string) => void
194
+ }) {
58
195
  const sensors = useSensors(
59
196
  useSensor(PointerSensor, { activationConstraint: { distance: 4 } }),
60
197
  useSensor(KeyboardSensor, { coordinateGetter: sortableKeyboardCoordinates }),
@@ -70,171 +207,121 @@ export function SectionsPanel({
70
207
  const next = ids.slice()
71
208
  const [moved] = next.splice(from, 1)
72
209
  next.splice(to, 0, moved!)
73
- onReorder(next)
210
+ onReorder?.(next)
74
211
  }
75
212
 
76
213
  return (
77
- <aside
78
- className="bg-card border-border flex h-full w-72 shrink-0 flex-col border-r"
79
- aria-label="Page sections"
80
- >
81
- <div className="border-border flex items-center justify-between border-b px-6 py-4">
82
- <div className="flex items-center gap-2">
83
- <h2 className="text-foreground text-sm font-medium">Sections</h2>
84
- <span className="bg-muted text-muted-foreground rounded-full px-2 py-0.5 text-xs font-medium tabular-nums">
85
- {sections.length}
86
- </span>
87
- </div>
88
- </div>
89
-
90
- <div className="flex-1 overflow-y-auto p-2">
91
- {sections.length === 0 ? (
92
- <p className="text-muted-foreground px-2 py-6 text-center text-sm">
93
- No sections yet. Add one below to get started.
94
- </p>
95
- ) : (
96
- <DndContext
97
- sensors={sensors}
98
- collisionDetection={closestCenter}
99
- onDragEnd={handleDragEnd}
100
- >
101
- <SortableContext
102
- items={sections.map((s) => s.id)}
103
- strategy={verticalListSortingStrategy}
104
- >
105
- <ul className="space-y-1">
106
- {sections.map((section) => (
107
- <SortableSectionItem
108
- key={section.id}
109
- section={section}
110
- selected={section.id === selectedId}
111
- canEdit={canEdit}
112
- onSelect={onSelect}
113
- onToggleVisibility={onToggleVisibility}
114
- onDuplicate={onDuplicate}
115
- onRequestDelete={onRequestDelete}
116
- />
117
- ))}
118
- </ul>
119
- </SortableContext>
120
- </DndContext>
121
- )}
122
- </div>
123
-
124
- <div className="border-border border-t p-3">
125
- <button
126
- type="button"
127
- onClick={onAdd}
128
- disabled={!canEdit}
129
- className="border-border text-foreground hover:bg-accent flex w-full items-center justify-center gap-2 rounded-lg border border-dashed px-3 py-2 text-sm font-medium transition-colors disabled:cursor-not-allowed disabled:opacity-50"
130
- >
131
- <Plus className="h-4 w-4" aria-hidden />
132
- Add Section
133
- </button>
134
- </div>
135
- </aside>
214
+ <DndContext sensors={sensors} collisionDetection={closestCenter} onDragEnd={handleDragEnd}>
215
+ <SortableContext items={sections.map((s) => s.id)} strategy={verticalListSortingStrategy}>
216
+ <ul className="space-y-1">
217
+ {sections.map((section) => (
218
+ <SortableSectionItem
219
+ key={section.id}
220
+ section={section}
221
+ selected={section.id === selectedId}
222
+ canEdit={canEdit}
223
+ onSelect={onSelect}
224
+ onToggleVisibility={onToggleVisibility}
225
+ onDuplicate={onDuplicate}
226
+ onRequestDelete={onRequestDelete}
227
+ />
228
+ ))}
229
+ </ul>
230
+ </SortableContext>
231
+ </DndContext>
136
232
  )
137
233
  }
138
234
 
139
- interface SortableItemProps {
235
+ interface RowProps {
140
236
  section: PageSection
141
237
  selected: boolean
142
238
  canEdit: boolean
239
+ structural: boolean
143
240
  onSelect: (id: string) => void
144
241
  onToggleVisibility: (id: string) => void
145
- onDuplicate: (id: string) => void
146
- onRequestDelete: (id: string) => void
242
+ onDuplicate?: (id: string) => void
243
+ onRequestDelete?: (id: string) => void
244
+ /** Drag affordance, supplied only by the sortable wrapper. */
245
+ dragHandle?: React.ReactNode
246
+ dragging?: boolean
147
247
  }
148
248
 
149
- function SortableSectionItem({
249
+ function SectionRow({
150
250
  section,
151
251
  selected,
152
252
  canEdit,
253
+ structural,
153
254
  onSelect,
154
255
  onToggleVisibility,
155
256
  onDuplicate,
156
257
  onRequestDelete,
157
- }: SortableItemProps) {
158
- // Unmanaged (externally-managed) sections are read-only: no drag, duplicate,
159
- // delete, or visibility toggle — only selectable to view the read-only notice.
258
+ dragHandle,
259
+ dragging,
260
+ }: RowProps) {
261
+ // Unmanaged (externally-managed) sections are read-only even in a structural
262
+ // panel: no drag, duplicate, delete, or visibility toggle — only selectable
263
+ // to view the read-only notice.
160
264
  const locked = section.unmanaged === true
161
- const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({
162
- id: section.id,
163
- disabled: !canEdit || locked,
164
- })
165
265
  const Icon = sectionIconFor(section.sectionType)
166
266
 
167
- const style = {
168
- transform: CSS.Transform.toString(transform),
169
- transition,
170
- zIndex: isDragging ? 10 : undefined,
171
- }
172
-
173
267
  return (
174
- <li ref={setNodeRef} style={style}>
175
- <div
176
- className={`group flex items-center gap-2 rounded-lg border px-2 py-2 ${
177
- selected ? 'border-primary bg-accent' : 'hover:bg-accent/60 border-transparent'
178
- } ${isDragging ? 'shadow-md' : ''}`}
268
+ <div
269
+ className={`group flex items-center gap-2 rounded-lg border px-2 py-2 ${
270
+ selected ? 'border-primary bg-accent' : 'hover:bg-accent/60 border-transparent'
271
+ } ${dragging ? 'shadow-md' : ''}`}
272
+ >
273
+ {dragHandle}
274
+
275
+ <button
276
+ type="button"
277
+ onClick={() => onSelect(section.id)}
278
+ className="flex min-w-0 flex-1 items-center gap-2 text-left"
179
279
  >
180
- <button
181
- type="button"
182
- className="text-muted-foreground hover:text-foreground shrink-0 cursor-grab touch-none disabled:cursor-not-allowed disabled:opacity-40"
183
- aria-label={`Drag to reorder ${section.name}`}
184
- disabled={!canEdit || locked}
185
- {...attributes}
186
- {...listeners}
280
+ <span className="bg-muted text-muted-foreground flex h-7 w-7 shrink-0 items-center justify-center rounded-md">
281
+ <Icon className="h-4 w-4" aria-hidden />
282
+ </span>
283
+ <span
284
+ className={`truncate text-sm ${section.visible ? 'text-foreground' : 'text-muted-foreground line-through'}`}
187
285
  >
188
- <GripVertical className="h-4 w-4" aria-hidden />
189
- </button>
286
+ {section.name}
287
+ </span>
288
+ </button>
190
289
 
191
- <button
192
- type="button"
193
- onClick={() => onSelect(section.id)}
194
- className="flex min-w-0 flex-1 items-center gap-2 text-left"
290
+ {locked ? (
291
+ <span
292
+ className="text-muted-foreground shrink-0 p-1"
293
+ title="Managed outside the editor read-only"
294
+ aria-label={`${section.name} is managed outside the editor and is read-only`}
195
295
  >
196
- <span className="bg-muted text-muted-foreground flex h-7 w-7 shrink-0 items-center justify-center rounded-md">
197
- <Icon className="h-4 w-4" aria-hidden />
198
- </span>
199
- <span
200
- className={`truncate text-sm ${section.visible ? 'text-foreground' : 'text-muted-foreground line-through'}`}
201
- >
202
- {section.name}
203
- </span>
204
- </button>
205
-
206
- {locked ? (
207
- <span
208
- className="text-muted-foreground shrink-0 p-1"
209
- title="Managed outside the editor — read-only"
210
- aria-label={`${section.name} is managed outside the editor and is read-only`}
296
+ <Lock className="h-4 w-4" aria-hidden />
297
+ </span>
298
+ ) : (
299
+ <>
300
+ {/* Visibility survives the design-owned lockdown: `visible` is the one
301
+ structural property the content model gives an editor. */}
302
+ <button
303
+ type="button"
304
+ onClick={() => onToggleVisibility(section.id)}
305
+ disabled={!canEdit}
306
+ aria-pressed={!section.visible}
307
+ aria-label={section.visible ? `Hide ${section.name}` : `Show ${section.name}`}
308
+ className="prenta-touch-target text-muted-foreground hover:text-foreground shrink-0 rounded p-1 disabled:opacity-40"
211
309
  >
212
- <Lock className="h-4 w-4" aria-hidden />
213
- </span>
214
- ) : (
215
- <>
216
- <button
217
- type="button"
218
- onClick={() => onToggleVisibility(section.id)}
219
- disabled={!canEdit}
220
- aria-pressed={!section.visible}
221
- aria-label={section.visible ? `Hide ${section.name}` : `Show ${section.name}`}
222
- className="text-muted-foreground hover:text-foreground shrink-0 rounded p-1 disabled:opacity-40"
223
- >
224
- {section.visible ? (
225
- <Eye className="h-4 w-4" aria-hidden />
226
- ) : (
227
- <EyeOff className="h-4 w-4" aria-hidden />
228
- )}
229
- </button>
310
+ {section.visible ? (
311
+ <Eye className="h-4 w-4" aria-hidden />
312
+ ) : (
313
+ <EyeOff className="h-4 w-4" aria-hidden />
314
+ )}
315
+ </button>
230
316
 
317
+ {structural && (
231
318
  <DropdownMenu.Root>
232
319
  <DropdownMenu.Trigger asChild>
233
320
  <button
234
321
  type="button"
235
322
  disabled={!canEdit}
236
323
  aria-label={`More actions for ${section.name}`}
237
- className="text-muted-foreground hover:text-foreground shrink-0 rounded p-1 disabled:opacity-40"
324
+ className="prenta-touch-target text-muted-foreground hover:text-foreground shrink-0 rounded p-1 disabled:opacity-40"
238
325
  >
239
326
  <MoreVertical className="h-4 w-4" aria-hidden />
240
327
  </button>
@@ -243,21 +330,75 @@ function SortableSectionItem({
243
330
  <DropdownMenu.Content
244
331
  align="end"
245
332
  sideOffset={4}
246
- className="border-border bg-popover z-[70] min-w-44 rounded-lg border p-1 shadow-md"
333
+ className="border-border bg-popover z-70 min-w-44 rounded-lg border p-1 shadow-md"
247
334
  >
248
- <MenuItem onSelect={() => onDuplicate(section.id)} icon={Copy}>
335
+ <MenuItem onSelect={() => onDuplicate?.(section.id)} icon={Copy}>
249
336
  Duplicate
250
337
  </MenuItem>
251
338
  <DropdownMenu.Separator className="bg-border my-1 h-px" />
252
- <MenuItem onSelect={() => onRequestDelete(section.id)} icon={Trash2} destructive>
339
+ <MenuItem
340
+ onSelect={() => onRequestDelete?.(section.id)}
341
+ icon={Trash2}
342
+ destructive
343
+ >
253
344
  Delete
254
345
  </MenuItem>
255
346
  </DropdownMenu.Content>
256
347
  </DropdownMenu.Portal>
257
348
  </DropdownMenu.Root>
258
- </>
259
- )}
260
- </div>
349
+ )}
350
+ </>
351
+ )}
352
+ </div>
353
+ )
354
+ }
355
+
356
+ function SortableSectionItem({
357
+ section,
358
+ selected,
359
+ canEdit,
360
+ onSelect,
361
+ onToggleVisibility,
362
+ onDuplicate,
363
+ onRequestDelete,
364
+ }: Omit<RowProps, 'structural' | 'dragHandle' | 'dragging'>) {
365
+ const locked = section.unmanaged === true
366
+ const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({
367
+ id: section.id,
368
+ disabled: !canEdit || locked,
369
+ })
370
+
371
+ const style = {
372
+ transform: CSS.Transform.toString(transform),
373
+ transition,
374
+ zIndex: isDragging ? 10 : undefined,
375
+ }
376
+
377
+ return (
378
+ <li ref={setNodeRef} style={style}>
379
+ <SectionRow
380
+ section={section}
381
+ selected={selected}
382
+ canEdit={canEdit}
383
+ structural
384
+ onSelect={onSelect}
385
+ onToggleVisibility={onToggleVisibility}
386
+ onDuplicate={onDuplicate}
387
+ onRequestDelete={onRequestDelete}
388
+ dragging={isDragging}
389
+ dragHandle={
390
+ <button
391
+ type="button"
392
+ className="text-muted-foreground hover:text-foreground shrink-0 cursor-grab touch-none disabled:cursor-not-allowed disabled:opacity-40"
393
+ aria-label={`Drag to reorder ${section.name}`}
394
+ disabled={!canEdit || locked}
395
+ {...attributes}
396
+ {...listeners}
397
+ >
398
+ <GripVertical className="h-4 w-4" aria-hidden />
399
+ </button>
400
+ }
401
+ />
261
402
  </li>
262
403
  )
263
404
  }
@@ -2,6 +2,7 @@
2
2
 
3
3
  import { useEffect, useLayoutEffect, useRef, useState } from 'react'
4
4
  import { Loader2 } from 'lucide-react'
5
+ import { injectPreviewEditChrome } from '../../lib/canvas-edit-chrome.js'
5
6
  import {
6
7
  canvasOriginFromSrc,
7
8
  isPreviewBridgeMessage,
@@ -145,6 +146,8 @@ export function SitePreviewFrame({
145
146
  editing: true,
146
147
  }
147
148
  win.postMessage(msg, canvasOrigin)
149
+ // Same-origin only — cross-origin previews skip silently.
150
+ injectPreviewEditChrome(iframeRef.current)
148
151
  }, [canvasOrigin, loaded, canvasReady, reloadKey])
149
152
 
150
153
  // Admin → canvas: highlight the selected section.