@delmaredigital/payload-puck 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (565) hide show
  1. package/README.md +349 -1370
  2. package/dist/admin/EditWithPuckButton.d.ts +74 -0
  3. package/dist/admin/EditWithPuckButton.d.ts.map +1 -0
  4. package/dist/admin/EditWithPuckButton.js +114 -0
  5. package/dist/admin/EditWithPuckButton.js.map +1 -0
  6. package/dist/admin/EditWithPuckCell.d.ts +43 -0
  7. package/dist/admin/EditWithPuckCell.d.ts.map +1 -0
  8. package/dist/admin/EditWithPuckCell.js +66 -0
  9. package/dist/admin/EditWithPuckCell.js.map +1 -0
  10. package/dist/admin/PuckEditorView.d.ts +85 -0
  11. package/dist/admin/PuckEditorView.d.ts.map +1 -0
  12. package/dist/admin/PuckEditorView.js +135 -0
  13. package/dist/admin/PuckEditorView.js.map +1 -0
  14. package/dist/admin/client.d.ts +8 -104
  15. package/dist/admin/client.d.ts.map +1 -0
  16. package/dist/admin/client.js +14 -176
  17. package/dist/admin/client.js.map +1 -0
  18. package/dist/admin/generateAdminComponents.d.ts +51 -0
  19. package/dist/admin/generateAdminComponents.d.ts.map +1 -0
  20. package/dist/admin/generateAdminComponents.js +42 -0
  21. package/dist/admin/generateAdminComponents.js.map +1 -0
  22. package/dist/admin/index.d.ts +14 -150
  23. package/dist/admin/index.d.ts.map +1 -0
  24. package/dist/admin/index.js +17 -30
  25. package/dist/admin/index.js.map +1 -0
  26. package/dist/api/createPuckApiRoutes.d.ts +31 -0
  27. package/dist/api/createPuckApiRoutes.d.ts.map +1 -0
  28. package/dist/api/createPuckApiRoutes.js +193 -0
  29. package/dist/api/createPuckApiRoutes.js.map +1 -0
  30. package/dist/api/createPuckApiRoutesVersions.d.ts +28 -0
  31. package/dist/api/createPuckApiRoutesVersions.d.ts.map +1 -0
  32. package/dist/api/createPuckApiRoutesVersions.js +144 -0
  33. package/dist/api/createPuckApiRoutesVersions.js.map +1 -0
  34. package/dist/api/createPuckApiRoutesWithId.d.ts +34 -0
  35. package/dist/api/createPuckApiRoutesWithId.d.ts.map +1 -0
  36. package/dist/api/createPuckApiRoutesWithId.js +251 -0
  37. package/dist/api/createPuckApiRoutesWithId.js.map +1 -0
  38. package/dist/api/index.d.ts +11 -431
  39. package/dist/api/index.d.ts.map +1 -0
  40. package/dist/api/index.js +40 -587
  41. package/dist/api/index.js.map +1 -0
  42. package/dist/api/types.d.ts +302 -0
  43. package/dist/api/types.d.ts.map +1 -0
  44. package/dist/api/types.js +2 -0
  45. package/dist/api/types.js.map +1 -0
  46. package/dist/api/utils/mapRootProps.d.ts +76 -0
  47. package/dist/api/utils/mapRootProps.d.ts.map +1 -0
  48. package/dist/api/utils/mapRootProps.js +169 -0
  49. package/dist/api/utils/mapRootProps.js.map +1 -0
  50. package/dist/collections/Templates.d.ts +9 -0
  51. package/dist/collections/Templates.d.ts.map +1 -0
  52. package/dist/collections/Templates.js +62 -0
  53. package/dist/collections/Templates.js.map +1 -0
  54. package/dist/components/AccordionClient.d.ts +20 -0
  55. package/dist/components/AccordionClient.d.ts.map +1 -0
  56. package/dist/components/AccordionClient.js +67 -0
  57. package/dist/components/AccordionClient.js.map +1 -0
  58. package/dist/components/AnimatedWrapper.d.ts +33 -0
  59. package/dist/components/AnimatedWrapper.d.ts.map +1 -0
  60. package/dist/components/AnimatedWrapper.js +61 -0
  61. package/dist/components/AnimatedWrapper.js.map +1 -0
  62. package/dist/components/exports.d.ts +54 -0
  63. package/dist/components/exports.d.ts.map +1 -0
  64. package/dist/components/exports.js +71 -0
  65. package/dist/components/exports.js.map +1 -0
  66. package/dist/components/index.d.ts +8 -216
  67. package/dist/components/index.d.ts.map +1 -0
  68. package/dist/components/index.js +15 -9262
  69. package/dist/components/index.js.map +1 -0
  70. package/dist/components/interactive/Accordion.d.ts +28 -0
  71. package/dist/components/interactive/Accordion.d.ts.map +1 -0
  72. package/dist/components/interactive/Accordion.js +159 -0
  73. package/dist/components/interactive/Accordion.js.map +1 -0
  74. package/dist/components/interactive/Accordion.server.d.ts +29 -0
  75. package/dist/components/interactive/Accordion.server.d.ts.map +1 -0
  76. package/dist/components/interactive/Accordion.server.js +30 -0
  77. package/dist/components/interactive/Accordion.server.js.map +1 -0
  78. package/dist/components/interactive/Button.d.ts +26 -0
  79. package/dist/components/interactive/Button.d.ts.map +1 -0
  80. package/dist/components/interactive/Button.js +133 -0
  81. package/dist/components/interactive/Button.js.map +1 -0
  82. package/dist/components/interactive/Button.server.d.ts +28 -0
  83. package/dist/components/interactive/Button.server.d.ts.map +1 -0
  84. package/dist/components/interactive/Button.server.js +96 -0
  85. package/dist/components/interactive/Button.server.js.map +1 -0
  86. package/dist/components/interactive/Card.d.ts +27 -0
  87. package/dist/components/interactive/Card.d.ts.map +1 -0
  88. package/dist/components/interactive/Card.js +128 -0
  89. package/dist/components/interactive/Card.js.map +1 -0
  90. package/dist/components/interactive/Card.server.d.ts +29 -0
  91. package/dist/components/interactive/Card.server.d.ts.map +1 -0
  92. package/dist/components/interactive/Card.server.js +77 -0
  93. package/dist/components/interactive/Card.server.js.map +1 -0
  94. package/dist/components/interactive/Divider.d.ts +18 -0
  95. package/dist/components/interactive/Divider.d.ts.map +1 -0
  96. package/dist/components/interactive/Divider.js +68 -0
  97. package/dist/components/interactive/Divider.js.map +1 -0
  98. package/dist/components/interactive/Divider.server.d.ts +20 -0
  99. package/dist/components/interactive/Divider.server.d.ts.map +1 -0
  100. package/dist/components/interactive/Divider.server.js +50 -0
  101. package/dist/components/interactive/Divider.server.js.map +1 -0
  102. package/dist/components/interactive/index.d.ts +10 -0
  103. package/dist/components/interactive/index.d.ts.map +1 -0
  104. package/dist/components/interactive/index.js +10 -0
  105. package/dist/components/interactive/index.js.map +1 -0
  106. package/dist/components/layout/Container.d.ts +29 -0
  107. package/dist/components/layout/Container.d.ts.map +1 -0
  108. package/dist/components/layout/Container.js +166 -0
  109. package/dist/components/layout/Container.js.map +1 -0
  110. package/dist/components/layout/Container.server.d.ts +32 -0
  111. package/dist/components/layout/Container.server.d.ts.map +1 -0
  112. package/dist/components/layout/Container.server.js +105 -0
  113. package/dist/components/layout/Container.server.js.map +1 -0
  114. package/dist/components/layout/Flex.d.ts +36 -0
  115. package/dist/components/layout/Flex.d.ts.map +1 -0
  116. package/dist/components/layout/Flex.js +183 -0
  117. package/dist/components/layout/Flex.js.map +1 -0
  118. package/dist/components/layout/Flex.server.d.ts +36 -0
  119. package/dist/components/layout/Flex.server.d.ts.map +1 -0
  120. package/dist/components/layout/Flex.server.js +97 -0
  121. package/dist/components/layout/Flex.server.js.map +1 -0
  122. package/dist/components/layout/Grid.d.ts +31 -0
  123. package/dist/components/layout/Grid.d.ts.map +1 -0
  124. package/dist/components/layout/Grid.js +164 -0
  125. package/dist/components/layout/Grid.js.map +1 -0
  126. package/dist/components/layout/Grid.server.d.ts +32 -0
  127. package/dist/components/layout/Grid.server.d.ts.map +1 -0
  128. package/dist/components/layout/Grid.server.js +92 -0
  129. package/dist/components/layout/Grid.server.js.map +1 -0
  130. package/dist/components/layout/Section.d.ts +35 -0
  131. package/dist/components/layout/Section.d.ts.map +1 -0
  132. package/dist/components/layout/Section.js +212 -0
  133. package/dist/components/layout/Section.js.map +1 -0
  134. package/dist/components/layout/Section.server.d.ts +35 -0
  135. package/dist/components/layout/Section.server.d.ts.map +1 -0
  136. package/dist/components/layout/Section.server.js +144 -0
  137. package/dist/components/layout/Section.server.js.map +1 -0
  138. package/dist/components/layout/Spacer.d.ts +18 -0
  139. package/dist/components/layout/Spacer.d.ts.map +1 -0
  140. package/dist/components/layout/Spacer.js +99 -0
  141. package/dist/components/layout/Spacer.js.map +1 -0
  142. package/dist/components/layout/Spacer.server.d.ts +21 -0
  143. package/dist/components/layout/Spacer.server.d.ts.map +1 -0
  144. package/dist/components/layout/Spacer.server.js +61 -0
  145. package/dist/components/layout/Spacer.server.js.map +1 -0
  146. package/dist/components/layout/Template.d.ts +35 -0
  147. package/dist/components/layout/Template.d.ts.map +1 -0
  148. package/dist/components/layout/Template.js +124 -0
  149. package/dist/components/layout/Template.js.map +1 -0
  150. package/dist/components/layout/Template.server.d.ts +32 -0
  151. package/dist/components/layout/Template.server.d.ts.map +1 -0
  152. package/dist/components/layout/Template.server.js +75 -0
  153. package/dist/components/layout/Template.server.js.map +1 -0
  154. package/dist/components/layout/index.d.ts +14 -0
  155. package/dist/components/layout/index.d.ts.map +1 -0
  156. package/dist/components/layout/index.js +13 -0
  157. package/dist/components/layout/index.js.map +1 -0
  158. package/dist/components/media/Image.d.ts +30 -0
  159. package/dist/components/media/Image.d.ts.map +1 -0
  160. package/dist/components/media/Image.js +123 -0
  161. package/dist/components/media/Image.js.map +1 -0
  162. package/dist/components/media/Image.server.d.ts +28 -0
  163. package/dist/components/media/Image.server.d.ts.map +1 -0
  164. package/dist/components/media/Image.server.js +76 -0
  165. package/dist/components/media/Image.server.js.map +1 -0
  166. package/dist/components/media/index.d.ts +7 -0
  167. package/dist/components/media/index.d.ts.map +1 -0
  168. package/dist/components/media/index.js +7 -0
  169. package/dist/components/media/index.js.map +1 -0
  170. package/dist/components/typography/Heading.d.ts +21 -0
  171. package/dist/components/typography/Heading.d.ts.map +1 -0
  172. package/dist/components/typography/Heading.js +71 -0
  173. package/dist/components/typography/Heading.js.map +1 -0
  174. package/dist/components/typography/Heading.server.d.ts +21 -0
  175. package/dist/components/typography/Heading.server.d.ts.map +1 -0
  176. package/dist/components/typography/Heading.server.js +49 -0
  177. package/dist/components/typography/Heading.server.js.map +1 -0
  178. package/dist/components/typography/RichText.d.ts +20 -0
  179. package/dist/components/typography/RichText.d.ts.map +1 -0
  180. package/dist/components/typography/RichText.editor.d.ts +11 -0
  181. package/dist/components/typography/RichText.editor.d.ts.map +1 -0
  182. package/dist/components/typography/RichText.editor.js +67 -0
  183. package/dist/components/typography/RichText.editor.js.map +1 -0
  184. package/dist/components/typography/RichText.js +73 -0
  185. package/dist/components/typography/RichText.js.map +1 -0
  186. package/dist/components/typography/RichText.server.d.ts +22 -0
  187. package/dist/components/typography/RichText.server.d.ts.map +1 -0
  188. package/dist/components/typography/RichText.server.js +52 -0
  189. package/dist/components/typography/RichText.server.js.map +1 -0
  190. package/dist/components/typography/Text.d.ts +20 -0
  191. package/dist/components/typography/Text.d.ts.map +1 -0
  192. package/dist/components/typography/Text.js +61 -0
  193. package/dist/components/typography/Text.js.map +1 -0
  194. package/dist/components/typography/Text.server.d.ts +21 -0
  195. package/dist/components/typography/Text.server.d.ts.map +1 -0
  196. package/dist/components/typography/Text.server.js +39 -0
  197. package/dist/components/typography/Text.server.js.map +1 -0
  198. package/dist/components/typography/index.d.ts +10 -0
  199. package/dist/components/typography/index.d.ts.map +1 -0
  200. package/dist/components/typography/index.js +10 -0
  201. package/dist/components/typography/index.js.map +1 -0
  202. package/dist/config/config.editor.d.ts +15 -56
  203. package/dist/config/config.editor.d.ts.map +1 -0
  204. package/dist/config/config.editor.js +125 -9462
  205. package/dist/config/config.editor.js.map +1 -0
  206. package/dist/config/index.d.ts +7 -33
  207. package/dist/config/index.d.ts.map +1 -0
  208. package/dist/config/index.js +110 -2119
  209. package/dist/config/index.js.map +1 -0
  210. package/dist/config/merge.d.ts +23 -0
  211. package/dist/config/merge.d.ts.map +1 -0
  212. package/dist/config/merge.js +80 -0
  213. package/dist/config/merge.js.map +1 -0
  214. package/dist/config/presets.d.ts +342 -0
  215. package/dist/config/presets.d.ts.map +1 -0
  216. package/dist/config/presets.js +247 -0
  217. package/dist/config/presets.js.map +1 -0
  218. package/dist/editor/PuckEditor.client.d.ts +131 -0
  219. package/dist/editor/PuckEditor.client.d.ts.map +1 -0
  220. package/dist/editor/PuckEditor.client.js +42 -0
  221. package/dist/editor/PuckEditor.client.js.map +1 -0
  222. package/dist/editor/PuckEditorCore.client.d.ts +141 -0
  223. package/dist/editor/PuckEditorCore.client.d.ts.map +1 -0
  224. package/dist/editor/PuckEditorCore.client.js +306 -0
  225. package/dist/editor/PuckEditorCore.client.js.map +1 -0
  226. package/dist/editor/components/HeaderActions.d.ts +109 -0
  227. package/dist/editor/components/HeaderActions.d.ts.map +1 -0
  228. package/dist/editor/components/HeaderActions.js +254 -0
  229. package/dist/editor/components/HeaderActions.js.map +1 -0
  230. package/dist/editor/components/IframeWrapper.d.ts +77 -0
  231. package/dist/editor/components/IframeWrapper.d.ts.map +1 -0
  232. package/dist/editor/components/IframeWrapper.js +257 -0
  233. package/dist/editor/components/IframeWrapper.js.map +1 -0
  234. package/dist/editor/components/LoadingState.d.ts +14 -0
  235. package/dist/editor/components/LoadingState.d.ts.map +1 -0
  236. package/dist/editor/components/LoadingState.js +12 -0
  237. package/dist/editor/components/LoadingState.js.map +1 -0
  238. package/dist/editor/components/PreviewModal.d.ts +54 -0
  239. package/dist/editor/components/PreviewModal.d.ts.map +1 -0
  240. package/dist/editor/components/PreviewModal.js +298 -0
  241. package/dist/editor/components/PreviewModal.js.map +1 -0
  242. package/dist/editor/components/VersionHistory.d.ts +44 -0
  243. package/dist/editor/components/VersionHistory.d.ts.map +1 -0
  244. package/dist/editor/components/VersionHistory.js +308 -0
  245. package/dist/editor/components/VersionHistory.js.map +1 -0
  246. package/dist/editor/hooks/useUnsavedChanges.d.ts +27 -0
  247. package/dist/editor/hooks/useUnsavedChanges.d.ts.map +1 -0
  248. package/dist/editor/hooks/useUnsavedChanges.js +55 -0
  249. package/dist/editor/hooks/useUnsavedChanges.js.map +1 -0
  250. package/dist/editor/index.d.ts +16 -756
  251. package/dist/editor/index.d.ts.map +1 -0
  252. package/dist/editor/index.js +49 -4625
  253. package/dist/editor/index.js.map +1 -0
  254. package/dist/editor/plugins/index.d.ts +12 -0
  255. package/dist/editor/plugins/index.d.ts.map +1 -0
  256. package/dist/editor/plugins/index.js +12 -0
  257. package/dist/editor/plugins/index.js.map +1 -0
  258. package/dist/endpoints/index.d.ts +46 -0
  259. package/dist/endpoints/index.d.ts.map +1 -0
  260. package/dist/endpoints/index.js +204 -0
  261. package/dist/endpoints/index.js.map +1 -0
  262. package/dist/exports/client.d.ts +19 -0
  263. package/dist/exports/client.d.ts.map +1 -0
  264. package/dist/exports/client.js +21 -0
  265. package/dist/exports/client.js.map +1 -0
  266. package/dist/exports/rsc.d.ts +19 -0
  267. package/dist/exports/rsc.d.ts.map +1 -0
  268. package/dist/exports/rsc.js +19 -0
  269. package/dist/exports/rsc.js.map +1 -0
  270. package/dist/fields/AlignmentField.d.ts +36 -0
  271. package/dist/fields/AlignmentField.d.ts.map +1 -0
  272. package/dist/fields/AlignmentField.js +120 -0
  273. package/dist/fields/AlignmentField.js.map +1 -0
  274. package/dist/fields/AnimationField.d.ts +44 -0
  275. package/dist/fields/AnimationField.d.ts.map +1 -0
  276. package/dist/fields/AnimationField.js +329 -0
  277. package/dist/fields/AnimationField.js.map +1 -0
  278. package/dist/fields/BackgroundField.d.ts +40 -0
  279. package/dist/fields/BackgroundField.d.ts.map +1 -0
  280. package/dist/fields/BackgroundField.js +413 -0
  281. package/dist/fields/BackgroundField.js.map +1 -0
  282. package/dist/fields/BorderField.d.ts +29 -0
  283. package/dist/fields/BorderField.d.ts.map +1 -0
  284. package/dist/fields/BorderField.js +264 -0
  285. package/dist/fields/BorderField.js.map +1 -0
  286. package/dist/fields/ColorPickerField.d.ts +43 -0
  287. package/dist/fields/ColorPickerField.d.ts.map +1 -0
  288. package/dist/fields/ColorPickerField.js +285 -0
  289. package/dist/fields/ColorPickerField.js.map +1 -0
  290. package/dist/fields/DimensionsField.d.ts +43 -0
  291. package/dist/fields/DimensionsField.d.ts.map +1 -0
  292. package/dist/fields/DimensionsField.js +532 -0
  293. package/dist/fields/DimensionsField.js.map +1 -0
  294. package/dist/fields/FlexAlignmentField.d.ts +61 -0
  295. package/dist/fields/FlexAlignmentField.d.ts.map +1 -0
  296. package/dist/fields/FlexAlignmentField.js +166 -0
  297. package/dist/fields/FlexAlignmentField.js.map +1 -0
  298. package/dist/fields/FolderPickerField.d.ts +17 -0
  299. package/dist/fields/FolderPickerField.d.ts.map +1 -0
  300. package/dist/fields/FolderPickerField.js +282 -0
  301. package/dist/fields/FolderPickerField.js.map +1 -0
  302. package/dist/fields/GradientEditor.d.ts +22 -0
  303. package/dist/fields/GradientEditor.d.ts.map +1 -0
  304. package/dist/fields/GradientEditor.js +322 -0
  305. package/dist/fields/GradientEditor.js.map +1 -0
  306. package/dist/fields/LockedField.d.ts +67 -0
  307. package/dist/fields/LockedField.d.ts.map +1 -0
  308. package/dist/fields/LockedField.js +170 -0
  309. package/dist/fields/LockedField.js.map +1 -0
  310. package/dist/fields/MarginField.d.ts +31 -0
  311. package/dist/fields/MarginField.d.ts.map +1 -0
  312. package/dist/fields/MarginField.js +233 -0
  313. package/dist/fields/MarginField.js.map +1 -0
  314. package/dist/fields/MediaField.d.ts +33 -0
  315. package/dist/fields/MediaField.d.ts.map +1 -0
  316. package/dist/fields/MediaField.js +677 -0
  317. package/dist/fields/MediaField.js.map +1 -0
  318. package/dist/fields/PaddingField.d.ts +29 -0
  319. package/dist/fields/PaddingField.d.ts.map +1 -0
  320. package/dist/fields/PaddingField.js +232 -0
  321. package/dist/fields/PaddingField.js.map +1 -0
  322. package/dist/fields/PageSegmentField.d.ts +17 -0
  323. package/dist/fields/PageSegmentField.d.ts.map +1 -0
  324. package/dist/fields/PageSegmentField.js +92 -0
  325. package/dist/fields/PageSegmentField.js.map +1 -0
  326. package/dist/fields/ResetField.d.ts +27 -0
  327. package/dist/fields/ResetField.d.ts.map +1 -0
  328. package/dist/fields/ResetField.js +122 -0
  329. package/dist/fields/ResetField.js.map +1 -0
  330. package/dist/fields/ResponsiveField.d.ts +38 -0
  331. package/dist/fields/ResponsiveField.d.ts.map +1 -0
  332. package/dist/fields/ResponsiveField.js +275 -0
  333. package/dist/fields/ResponsiveField.js.map +1 -0
  334. package/dist/fields/ResponsiveVisibilityField.d.ts +34 -0
  335. package/dist/fields/ResponsiveVisibilityField.d.ts.map +1 -0
  336. package/dist/fields/ResponsiveVisibilityField.js +145 -0
  337. package/dist/fields/ResponsiveVisibilityField.js.map +1 -0
  338. package/dist/fields/SizeField.d.ts +54 -0
  339. package/dist/fields/SizeField.d.ts.map +1 -0
  340. package/dist/fields/SizeField.js +255 -0
  341. package/dist/fields/SizeField.js.map +1 -0
  342. package/dist/fields/SlugPreviewField.d.ts +16 -0
  343. package/dist/fields/SlugPreviewField.d.ts.map +1 -0
  344. package/dist/fields/SlugPreviewField.js +49 -0
  345. package/dist/fields/SlugPreviewField.js.map +1 -0
  346. package/dist/fields/TemplateField.d.ts +31 -0
  347. package/dist/fields/TemplateField.d.ts.map +1 -0
  348. package/dist/fields/TemplateField.js +428 -0
  349. package/dist/fields/TemplateField.js.map +1 -0
  350. package/dist/fields/TiptapField.d.ts +40 -0
  351. package/dist/fields/TiptapField.d.ts.map +1 -0
  352. package/dist/fields/TiptapField.js +857 -0
  353. package/dist/fields/TiptapField.js.map +1 -0
  354. package/dist/fields/TiptapModal.d.ts +10 -0
  355. package/dist/fields/TiptapModal.d.ts.map +1 -0
  356. package/dist/fields/TiptapModal.js +114 -0
  357. package/dist/fields/TiptapModal.js.map +1 -0
  358. package/dist/fields/TiptapModalField.d.ts +23 -0
  359. package/dist/fields/TiptapModalField.d.ts.map +1 -0
  360. package/dist/fields/TiptapModalField.js +55 -0
  361. package/dist/fields/TiptapModalField.js.map +1 -0
  362. package/dist/fields/TransformField.d.ts +31 -0
  363. package/dist/fields/TransformField.d.ts.map +1 -0
  364. package/dist/fields/TransformField.js +384 -0
  365. package/dist/fields/TransformField.js.map +1 -0
  366. package/dist/fields/VerticalAlignmentField.d.ts +35 -0
  367. package/dist/fields/VerticalAlignmentField.d.ts.map +1 -0
  368. package/dist/fields/VerticalAlignmentField.js +120 -0
  369. package/dist/fields/VerticalAlignmentField.js.map +1 -0
  370. package/dist/fields/WidthField.d.ts +28 -0
  371. package/dist/fields/WidthField.d.ts.map +1 -0
  372. package/dist/fields/WidthField.js +339 -0
  373. package/dist/fields/WidthField.js.map +1 -0
  374. package/dist/fields/index.d.ts +44 -559
  375. package/dist/fields/index.d.ts.map +1 -0
  376. package/dist/fields/index.js +91 -7704
  377. package/dist/fields/index.js.map +1 -0
  378. package/dist/fields/richtext-output.css +219 -0
  379. package/dist/{shared-X9UpCJKW.d.mts → fields/shared.d.ts} +111 -132
  380. package/dist/fields/shared.d.ts.map +1 -0
  381. package/dist/fields/shared.js +1542 -0
  382. package/dist/fields/shared.js.map +1 -0
  383. package/dist/fields/{index.css → tiptap-styles.css} +75 -166
  384. package/dist/hooks/index.d.ts +8 -0
  385. package/dist/hooks/index.d.ts.map +1 -0
  386. package/dist/hooks/index.js +8 -0
  387. package/dist/hooks/index.js.map +1 -0
  388. package/dist/hooks/useResponsiveStyles.d.ts +51 -0
  389. package/dist/hooks/useResponsiveStyles.d.ts.map +1 -0
  390. package/dist/hooks/useResponsiveStyles.js +149 -0
  391. package/dist/hooks/useResponsiveStyles.js.map +1 -0
  392. package/dist/hooks/useScrollAnimation.d.ts +56 -0
  393. package/dist/hooks/useScrollAnimation.d.ts.map +1 -0
  394. package/dist/hooks/useScrollAnimation.js +116 -0
  395. package/dist/hooks/useScrollAnimation.js.map +1 -0
  396. package/dist/index.d.ts +66 -6
  397. package/dist/index.d.ts.map +1 -0
  398. package/dist/index.js +67 -568
  399. package/dist/index.js.map +1 -0
  400. package/dist/layouts/LayoutWrapper.d.ts +33 -0
  401. package/dist/layouts/LayoutWrapper.d.ts.map +1 -0
  402. package/dist/layouts/LayoutWrapper.js +112 -0
  403. package/dist/layouts/LayoutWrapper.js.map +1 -0
  404. package/dist/layouts/defaults.d.ts +40 -0
  405. package/dist/layouts/defaults.d.ts.map +1 -0
  406. package/dist/layouts/defaults.js +106 -0
  407. package/dist/layouts/defaults.js.map +1 -0
  408. package/dist/layouts/index.d.ts +27 -94
  409. package/dist/layouts/index.d.ts.map +1 -0
  410. package/dist/layouts/index.js +30 -393
  411. package/dist/layouts/index.js.map +1 -0
  412. package/dist/{types-D7D3rZ1J.d.ts → layouts/types.d.ts} +8 -11
  413. package/dist/layouts/types.d.ts.map +1 -0
  414. package/dist/layouts/types.js +7 -0
  415. package/dist/layouts/types.js.map +1 -0
  416. package/dist/layouts/utils.d.ts +42 -0
  417. package/dist/layouts/utils.d.ts.map +1 -0
  418. package/dist/layouts/utils.js +83 -0
  419. package/dist/layouts/utils.js.map +1 -0
  420. package/dist/plugin/collections/Pages.d.ts +8 -0
  421. package/dist/plugin/collections/Pages.d.ts.map +1 -0
  422. package/dist/plugin/collections/Pages.js +117 -0
  423. package/dist/plugin/collections/Pages.js.map +1 -0
  424. package/dist/plugin/fields/index.d.ts +153 -0
  425. package/dist/plugin/fields/index.d.ts.map +1 -0
  426. package/dist/plugin/fields/index.js +364 -0
  427. package/dist/plugin/fields/index.js.map +1 -0
  428. package/dist/plugin/fields/types.d.ts +108 -0
  429. package/dist/plugin/fields/types.d.ts.map +1 -0
  430. package/dist/plugin/fields/types.js +7 -0
  431. package/dist/plugin/fields/types.js.map +1 -0
  432. package/dist/plugin/index.d.ts +13 -255
  433. package/dist/plugin/index.d.ts.map +1 -0
  434. package/dist/plugin/index.js +276 -553
  435. package/dist/plugin/index.js.map +1 -0
  436. package/dist/render/HybridPageRenderer.d.ts +85 -0
  437. package/dist/render/HybridPageRenderer.d.ts.map +1 -0
  438. package/dist/render/HybridPageRenderer.js +29 -0
  439. package/dist/render/HybridPageRenderer.js.map +1 -0
  440. package/dist/render/PageRenderer.d.ts +51 -0
  441. package/dist/render/PageRenderer.d.ts.map +1 -0
  442. package/dist/render/PageRenderer.js +61 -0
  443. package/dist/render/PageRenderer.js.map +1 -0
  444. package/dist/render/PuckEditor.client.d.ts +66 -0
  445. package/dist/render/PuckEditor.client.d.ts.map +1 -0
  446. package/dist/render/PuckEditor.client.js +66 -0
  447. package/dist/render/PuckEditor.client.js.map +1 -0
  448. package/dist/render/index.d.ts +8 -106
  449. package/dist/render/index.d.ts.map +1 -0
  450. package/dist/render/index.js +10 -2253
  451. package/dist/render/index.js.map +1 -0
  452. package/dist/theme/context.d.ts +59 -0
  453. package/dist/theme/context.d.ts.map +1 -0
  454. package/dist/theme/context.js +73 -0
  455. package/dist/theme/context.js.map +1 -0
  456. package/dist/theme/defaults.d.ts +39 -0
  457. package/dist/theme/defaults.d.ts.map +1 -0
  458. package/dist/theme/defaults.js +72 -0
  459. package/dist/theme/defaults.js.map +1 -0
  460. package/dist/theme/example.d.ts +30 -0
  461. package/dist/theme/example.d.ts.map +1 -0
  462. package/dist/theme/example.js +89 -0
  463. package/dist/theme/example.js.map +1 -0
  464. package/dist/theme/index.d.ts +17 -140
  465. package/dist/theme/index.d.ts.map +1 -0
  466. package/dist/theme/index.js +34 -200
  467. package/dist/theme/index.js.map +1 -0
  468. package/dist/{types-_6MvjyKv.d.ts → theme/types.d.ts} +8 -9
  469. package/dist/theme/types.d.ts.map +1 -0
  470. package/dist/theme/types.js +9 -0
  471. package/dist/theme/types.js.map +1 -0
  472. package/dist/theme/utils.d.ts +30 -0
  473. package/dist/theme/utils.d.ts.map +1 -0
  474. package/dist/theme/utils.js +84 -0
  475. package/dist/theme/utils.js.map +1 -0
  476. package/dist/{index-CQu6SzDg.d.mts → types/index.d.ts} +120 -115
  477. package/dist/types/index.d.ts.map +1 -0
  478. package/dist/types/index.js +2 -0
  479. package/dist/types/index.js.map +1 -0
  480. package/dist/utils/index.d.ts +23 -257
  481. package/dist/utils/index.d.ts.map +1 -0
  482. package/dist/utils/index.js +56 -425
  483. package/dist/utils/index.js.map +1 -0
  484. package/dist/utils/{index.d.mts → migration.d.ts} +16 -112
  485. package/dist/utils/migration.d.ts.map +1 -0
  486. package/dist/utils/migration.js +309 -0
  487. package/dist/utils/migration.js.map +1 -0
  488. package/dist/utils/validation.d.ts +89 -0
  489. package/dist/utils/validation.d.ts.map +1 -0
  490. package/dist/utils/validation.js +247 -0
  491. package/dist/utils/validation.js.map +1 -0
  492. package/dist/views/PuckConfigContext.d.ts +71 -0
  493. package/dist/views/PuckConfigContext.d.ts.map +1 -0
  494. package/dist/views/PuckConfigContext.js +45 -0
  495. package/dist/views/PuckConfigContext.js.map +1 -0
  496. package/dist/views/PuckEditorClient.d.ts +73 -0
  497. package/dist/views/PuckEditorClient.d.ts.map +1 -0
  498. package/dist/views/PuckEditorClient.js +130 -0
  499. package/dist/views/PuckEditorClient.js.map +1 -0
  500. package/dist/views/PuckEditorView.d.ts +19 -0
  501. package/dist/views/PuckEditorView.d.ts.map +1 -0
  502. package/dist/views/PuckEditorView.js +106 -0
  503. package/dist/views/PuckEditorView.js.map +1 -0
  504. package/dist/views/index.d.ts +10 -0
  505. package/dist/views/index.d.ts.map +1 -0
  506. package/dist/views/index.js +10 -0
  507. package/dist/views/index.js.map +1 -0
  508. package/package.json +51 -74
  509. package/dist/AccordionClient.d.mts +0 -24
  510. package/dist/AccordionClient.d.ts +0 -24
  511. package/dist/AccordionClient.js +0 -786
  512. package/dist/AccordionClient.mjs +0 -784
  513. package/dist/AnimatedWrapper.d.mts +0 -30
  514. package/dist/AnimatedWrapper.d.ts +0 -30
  515. package/dist/AnimatedWrapper.js +0 -379
  516. package/dist/AnimatedWrapper.mjs +0 -377
  517. package/dist/admin/client.d.mts +0 -108
  518. package/dist/admin/client.mjs +0 -173
  519. package/dist/admin/index.d.mts +0 -157
  520. package/dist/admin/index.mjs +0 -29
  521. package/dist/api/index.d.mts +0 -460
  522. package/dist/api/index.mjs +0 -578
  523. package/dist/components/index.css +0 -339
  524. package/dist/components/index.d.mts +0 -219
  525. package/dist/components/index.mjs +0 -9216
  526. package/dist/config/config.editor.css +0 -339
  527. package/dist/config/config.editor.d.mts +0 -153
  528. package/dist/config/config.editor.mjs +0 -9445
  529. package/dist/config/index.d.mts +0 -68
  530. package/dist/config/index.mjs +0 -2099
  531. package/dist/editor/index.d.mts +0 -784
  532. package/dist/editor/index.mjs +0 -4592
  533. package/dist/fields/index.d.mts +0 -600
  534. package/dist/fields/index.mjs +0 -7588
  535. package/dist/index-CoUQnyC3.d.ts +0 -327
  536. package/dist/index.d.mts +0 -6
  537. package/dist/index.mjs +0 -555
  538. package/dist/layouts/index.d.mts +0 -96
  539. package/dist/layouts/index.mjs +0 -378
  540. package/dist/plugin/index.d.mts +0 -289
  541. package/dist/plugin/index.mjs +0 -555
  542. package/dist/render/index.d.mts +0 -109
  543. package/dist/render/index.mjs +0 -2231
  544. package/dist/shared-X9UpCJKW.d.ts +0 -548
  545. package/dist/theme/index.d.mts +0 -155
  546. package/dist/theme/index.mjs +0 -186
  547. package/dist/types-D7D3rZ1J.d.mts +0 -116
  548. package/dist/types-_6MvjyKv.d.mts +0 -104
  549. package/dist/utils/index.mjs +0 -412
  550. package/dist/utils-DaRs9t0J.d.mts +0 -85
  551. package/dist/utils-gAvt0Vhw.d.ts +0 -85
  552. package/examples/README.md +0 -247
  553. package/examples/api/puck/pages/[id]/route.ts +0 -64
  554. package/examples/api/puck/pages/[id]/versions/route.ts +0 -47
  555. package/examples/api/puck/pages/route.ts +0 -45
  556. package/examples/app/(frontend)/page.tsx +0 -94
  557. package/examples/app/(manage)/layout.tsx +0 -31
  558. package/examples/app/[...slug]/page.tsx +0 -101
  559. package/examples/app/pages/[id]/edit/page.tsx +0 -148
  560. package/examples/components/CustomBanner.tsx +0 -368
  561. package/examples/config/custom-config.ts +0 -223
  562. package/examples/config/payload.config.example.ts +0 -64
  563. package/examples/lib/puck-layouts.ts +0 -258
  564. package/examples/lib/puck-theme.ts +0 -94
  565. package/examples/styles/puck-theme.css +0 -171
package/README.md CHANGED
@@ -9,17 +9,14 @@ A PayloadCMS plugin for integrating [Puck](https://puckeditor.com) visual page b
9
9
  - [Installation](#installation)
10
10
  - [Quick Start](#quick-start)
11
11
  - [Styling Setup](#styling-setup)
12
- - [Setup Checklist](#setup-checklist)
13
12
  - [Core Concepts](#core-concepts)
14
13
  - [Components](#components)
15
- - [Configuration](#configuration)
16
14
  - [Custom Fields](#custom-fields)
17
15
  - [Theming](#theming)
18
16
  - [Layouts](#layouts)
19
- - [API Routes](#api-routes)
20
- - [SEO Fields](#seo-fields)
21
- - [Plugin Options](#plugin-options)
17
+ - [Page-Tree Integration](#page-tree-integration)
22
18
  - [Hybrid Integration](#hybrid-integration)
19
+ - [Advanced Configuration](#advanced-configuration)
23
20
  - [License](#license)
24
21
 
25
22
  ---
@@ -32,65 +29,24 @@ A PayloadCMS plugin for integrating [Puck](https://puckeditor.com) visual page b
32
29
  |------------|---------|---------|
33
30
  | `@measured/puck` | >= 0.20.0 | Visual editor core |
34
31
  | `payload` | >= 3.0.0 | CMS backend |
35
- | `next` | >= 15.4.8 | React framework |
32
+ | `@payloadcms/next` | >= 3.0.0 | Payload Next.js integration |
33
+ | `next` | >= 14.0.0 | React framework |
36
34
  | `react` | >= 18.0.0 | UI library |
37
35
  | `@tailwindcss/typography` | >= 0.5.0 | RichText component styling |
38
36
 
39
- > **⚠️ Don't skip the styling setup!** After Quick Start, you must configure Tailwind to scan this package. See [Styling Setup](#styling-setup).
40
-
41
37
  ### Install
42
38
 
43
39
  ```bash
44
40
  pnpm add @delmaredigital/payload-puck @measured/puck
45
41
  ```
46
42
 
47
- Or install from GitHub:
48
-
49
- ```bash
50
- pnpm add github:delmaredigital/payload-puck#main @measured/puck
51
- ```
52
-
53
43
  ---
54
44
 
55
45
  ## Quick Start
56
46
 
57
- > **📋 Important:** After completing these steps, continue to [Styling Setup](#styling-setup) and verify with the [Setup Checklist](#setup-checklist).
58
-
59
- <details>
60
- <summary><strong>Option A: Copy Boilerplate (Fastest)</strong></summary>
61
-
62
- The package includes ready-to-use example files:
63
-
64
- ```bash
65
- # Copy API routes
66
- cp -r node_modules/@delmaredigital/payload-puck/examples/api/puck src/app/api/
67
-
68
- # Copy editor layout (REQUIRED - imports Tailwind CSS) and page
69
- mkdir -p src/app/\(manage\)/pages/\[id\]/edit
70
- cp node_modules/@delmaredigital/payload-puck/examples/app/\(manage\)/layout.tsx src/app/\(manage\)/
71
- cp node_modules/@delmaredigital/payload-puck/examples/app/pages/\[id\]/edit/page.tsx src/app/\(manage\)/pages/\[id\]/edit/
72
-
73
- # Copy frontend routes (homepage + dynamic pages)
74
- mkdir -p src/app/\(frontend\)
75
- cp node_modules/@delmaredigital/payload-puck/examples/app/\(frontend\)/page.tsx src/app/\(frontend\)/
76
- mkdir -p src/app/\(frontend\)/\[...slug\]
77
- cp node_modules/@delmaredigital/payload-puck/examples/app/\[...slug\]/page.tsx src/app/\(frontend\)/\[...slug\]/
78
-
79
- # Copy theme config (optional)
80
- mkdir -p src/lib
81
- cp node_modules/@delmaredigital/payload-puck/examples/lib/puck-theme.ts src/lib/
82
- ```
83
-
84
- > **Important:** Update the CSS import path in `src/app/(manage)/layout.tsx` to match your project's globals.css location.
85
-
86
- See `examples/README.md` for detailed customization instructions.
87
-
88
- </details>
89
-
90
- <details>
91
- <summary><strong>Option B: Manual Setup</strong></summary>
47
+ The plugin integrates directly into Payload's admin UI with minimal configuration. API endpoints and admin views are registered automatically.
92
48
 
93
- #### Step 1: Add the Plugin
49
+ ### Step 1: Add the Plugin
94
50
 
95
51
  ```typescript
96
52
  // payload.config.ts
@@ -107,254 +63,146 @@ export default buildConfig({
107
63
  })
108
64
  ```
109
65
 
110
- #### Step 2: Create API Routes
111
-
112
- ```typescript
113
- // app/api/puck/pages/route.ts
114
- import { createPuckApiRoutes } from '@delmaredigital/payload-puck/api'
115
- import { getPayload } from 'payload'
116
- import config from '@payload-config'
117
- import { headers } from 'next/headers'
118
-
119
- export const { GET, POST } = createPuckApiRoutes({
120
- collection: 'pages',
121
- payloadConfig: config,
122
- auth: {
123
- authenticate: async (request) => {
124
- const payload = await getPayload({ config })
125
- const { user } = await payload.auth({ headers: await headers() })
126
- if (!user) return { authenticated: false }
127
- return { authenticated: true, user: { id: user.id } }
128
- },
129
- },
130
- })
131
- ```
132
-
133
- ```typescript
134
- // app/api/puck/pages/[id]/route.ts
135
- import { createPuckApiRoutesWithId } from '@delmaredigital/payload-puck/api'
136
- import config from '@payload-config'
137
-
138
- export const { GET, PATCH, DELETE } = createPuckApiRoutesWithId({
139
- collection: 'pages',
140
- payloadConfig: config,
141
- auth: {
142
- authenticate: async (request) => {
143
- // Same auth logic as above
144
- },
145
- },
146
- })
147
- ```
148
-
149
- #### Step 3: Create the Editor Layout & Page
66
+ This automatically:
67
+ - Creates a `pages` collection with Puck fields (or adds fields to your existing collection)
68
+ - Registers API endpoints at `/api/puck/:collection`
69
+ - Adds the Puck editor view at `/admin/puck-editor/:collection/:id`
70
+ - Adds "Edit with Puck" buttons to the admin UI
150
71
 
151
- First, create a layout that imports your Tailwind CSS:
72
+ ### Step 2: Provide Puck Configuration
152
73
 
153
- ```typescript
154
- // app/(manage)/layout.tsx
155
- import '@/app/(frontend)/globals.css' // Adjust path to your CSS
156
-
157
- export const metadata = {
158
- title: 'Puck Editor',
159
- description: 'Visual page editor',
160
- }
161
-
162
- export default function ManageLayout({ children }: { children: React.ReactNode }) {
163
- return (
164
- // data-theme may be required if your CSS hides content until theme is set
165
- <html lang="en" data-theme="light">
166
- <body>{children}</body>
167
- </html>
168
- )
169
- }
170
- ```
171
-
172
- Then create the editor page:
74
+ Wrap your app with `PuckConfigProvider` to supply the Puck configuration. This is required because Puck configs contain React components that cannot be serialized from server to client.
173
75
 
174
76
  ```typescript
175
- // app/(manage)/pages/[id]/edit/page.tsx
176
- 'use client'
177
-
178
- import { PuckEditorView } from '@delmaredigital/payload-puck/editor'
77
+ // app/(app)/layout.tsx (covers both admin and frontend)
78
+ import { PuckConfigProvider } from '@delmaredigital/payload-puck/client'
179
79
  import { editorConfig } from '@delmaredigital/payload-puck/config/editor'
180
80
 
181
- export default function EditorPage() {
81
+ export default function RootLayout({ children }: { children: React.ReactNode }) {
182
82
  return (
183
- <PuckEditorView
184
- config={editorConfig}
185
- collectionSlug="pages"
186
- apiBasePath="/api/puck"
187
- backUrl="/admin/collections/pages"
188
- previewUrl={(slug) => `/${slug}`}
189
- />
83
+ <html lang="en">
84
+ <body>
85
+ <PuckConfigProvider config={editorConfig}>
86
+ {children}
87
+ </PuckConfigProvider>
88
+ </body>
89
+ </html>
190
90
  )
191
91
  }
192
92
  ```
193
93
 
194
- The editor includes:
195
- - **Save Draft** - Saves without publishing
196
- - **Publish** - Publishes the page
197
- - **Draft/Published badge** - Shows current document status
198
- - **Unsaved changes warning** - Prevents accidental navigation
199
- - **Heading Analyzer** - WCAG-compliant heading outline visualization (enabled by default)
200
-
201
- **Heading Analyzer Plugin**
202
-
203
- The heading analyzer plugin is included by default and displays a heading outline in the editor sidebar. It helps identify accessibility issues like skipped heading levels (e.g., jumping from H1 to H3).
204
-
205
- To add additional plugins or disable the default:
94
+ ### Step 3: Create a Frontend Route
206
95
 
207
- ```typescript
208
- // Add additional plugins (headingAnalyzer is still included)
209
- <PuckEditorView
210
- plugins={[myCustomPlugin]}
211
- // ...
212
- />
213
-
214
- // Disable all default plugins
215
- <PuckEditorView
216
- plugins={false}
217
- // ...
218
- />
219
- ```
96
+ The plugin can't auto-create frontend routes (Next.js App Router is file-based), but here's copy-paste ready code:
220
97
 
221
- #### Step 4: Create a Frontend Route
98
+ <details>
99
+ <summary><strong>📄 app/(frontend)/[[...slug]]/page.tsx</strong> (click to expand)</summary>
222
100
 
223
101
  ```typescript
224
- // app/(frontend)/[...slug]/page.tsx
225
102
  import { getPayload } from 'payload'
226
103
  import config from '@payload-config'
227
104
  import { PageRenderer } from '@delmaredigital/payload-puck/render'
228
105
  import { baseConfig } from '@delmaredigital/payload-puck/config'
229
106
  import { notFound } from 'next/navigation'
107
+ import type { Metadata } from 'next'
230
108
 
231
- export default async function Page({ params }: { params: Promise<{ slug: string[] }> }) {
232
- const { slug } = await params
109
+ // Fetch page by slug (or homepage if no slug)
110
+ async function getPage(slug?: string[]) {
233
111
  const payload = await getPayload({ config })
112
+ const slugPath = slug?.join('/') || ''
234
113
 
114
+ // Try to find by slug, or find homepage
235
115
  const { docs } = await payload.find({
236
116
  collection: 'pages',
237
- where: { slug: { equals: slug.join('/') } },
117
+ where: slugPath
118
+ ? { slug: { equals: slugPath } }
119
+ : { isHomepage: { equals: true } },
238
120
  limit: 1,
239
121
  })
240
122
 
241
- const page = docs[0]
123
+ return docs[0] || null
124
+ }
125
+
126
+ // Generate metadata from page SEO fields
127
+ export async function generateMetadata({
128
+ params
129
+ }: {
130
+ params: Promise<{ slug?: string[] }>
131
+ }): Promise<Metadata> {
132
+ const { slug } = await params
133
+ const page = await getPage(slug)
134
+
135
+ if (!page) return {}
136
+
137
+ return {
138
+ title: page.meta?.title || page.title,
139
+ description: page.meta?.description,
140
+ }
141
+ }
142
+
143
+ // Render the page
144
+ export default async function Page({
145
+ params
146
+ }: {
147
+ params: Promise<{ slug?: string[] }>
148
+ }) {
149
+ const { slug } = await params
150
+ const page = await getPage(slug)
151
+
242
152
  if (!page) notFound()
243
153
 
244
154
  return <PageRenderer config={baseConfig} data={page.puckData} />
245
155
  }
246
156
  ```
247
157
 
248
- #### Step 5: Enable Version History (Optional)
249
-
250
- ```typescript
251
- // app/api/puck/pages/[id]/versions/route.ts
252
- import { createPuckApiRoutesVersions } from '@delmaredigital/payload-puck/api'
253
- import config from '@payload-config'
158
+ </details>
254
159
 
255
- export const { GET, POST } = createPuckApiRoutesVersions({
256
- collection: 'pages',
257
- payloadConfig: config,
258
- auth: {
259
- authenticate: async (request) => {
260
- // Same auth logic as your main routes
261
- },
262
- },
263
- })
264
- ```
160
+ > **Note:** The `[[...slug]]` pattern with double brackets makes the slug optional, so this handles both `/` (homepage) and `/any/path`.
265
161
 
266
- The History button automatically appears when this route exists.
162
+ ### That's It!
267
163
 
268
- </details>
164
+ - The plugin registers the editor view at `/admin/puck-editor/:collection/:id`
165
+ - "Edit with Puck" buttons appear in the collection list view
166
+ - The editor runs inside Payload's admin UI with full navigation
167
+ - API endpoints are handled automatically via Payload's endpoint system
269
168
 
270
169
  ---
271
170
 
272
171
  ## Styling Setup
273
172
 
274
- > **⚠️ This section is critical.** Without proper styling setup, components will render with broken or missing styles.
275
-
276
- <details>
277
- <summary><strong>⚠️ Tailwind Typography</strong> — Required for RichText component</summary>
173
+ ### Tailwind Typography (Required)
278
174
 
279
- The RichText component uses the `prose` class from `@tailwindcss/typography`. **Without this, rich text content will be unstyled** — no proper heading sizes, list styles, blockquote formatting, etc.
175
+ The RichText component uses `@tailwindcss/typography`:
280
176
 
281
177
  ```bash
282
178
  pnpm add @tailwindcss/typography
283
179
  ```
284
180
 
285
- **Tailwind v4** — Add the `@plugin` directive to your main CSS file:
286
-
181
+ **Tailwind v4:**
287
182
  ```css
288
183
  @import "tailwindcss";
289
184
  @plugin "@tailwindcss/typography";
290
185
  ```
291
186
 
292
- **Tailwind v3** — Add to your Tailwind config:
293
-
187
+ **Tailwind v3:**
294
188
  ```javascript
295
189
  // tailwind.config.js
296
190
  module.exports = {
297
- plugins: [
298
- require('@tailwindcss/typography'),
299
- ],
191
+ plugins: [require('@tailwindcss/typography')],
300
192
  }
301
193
  ```
302
194
 
303
- </details>
304
-
305
- <details>
306
- <summary><strong>⚠️ Tailwind Source Scanning</strong> — Required for component styles</summary>
307
-
308
- **Without this, Tailwind won't include the plugin's CSS classes in your build.** Components will have missing styles.
195
+ ### Package Scanning (Required)
309
196
 
310
- The `@source` directive (v4) or `content` path (v3) tells Tailwind to scan the package for class names.
311
-
312
- **Tailwind v4**
313
-
314
- The path is relative to your CSS file's location and must resolve to your project's `node_modules`:
315
-
316
- | CSS file location | `@source` path |
317
- |-------------------|----------------|
318
- | `globals.css` (root) | `./node_modules/@delmaredigital/payload-puck` |
319
- | `src/globals.css` | `../node_modules/@delmaredigital/payload-puck` |
320
- | `src/styles/tailwind.css` | `../../node_modules/@delmaredigital/payload-puck` |
197
+ Tell Tailwind to scan the plugin's components:
321
198
 
199
+ **Tailwind v4:**
322
200
  ```css
323
- @import "tailwindcss";
324
- @plugin "@tailwindcss/typography";
325
-
326
- /* Adjust path based on your CSS file location */
201
+ /* Adjust path relative to your CSS file */
327
202
  @source "../node_modules/@delmaredigital/payload-puck";
328
-
329
- @theme inline {
330
- --color-background: var(--background);
331
- --color-foreground: var(--foreground);
332
- --color-primary: var(--primary);
333
- --color-primary-foreground: var(--primary-foreground);
334
- --color-secondary: var(--secondary);
335
- --color-secondary-foreground: var(--secondary-foreground);
336
- --color-muted: var(--muted);
337
- --color-muted-foreground: var(--muted-foreground);
338
- --color-accent: var(--accent);
339
- --color-accent-foreground: var(--accent-foreground);
340
- --color-destructive: var(--destructive);
341
- --color-destructive-foreground: var(--destructive-foreground);
342
- --color-border: var(--border);
343
- --color-input: var(--input);
344
- --color-ring: var(--ring);
345
- --color-popover: var(--popover);
346
- --color-popover-foreground: var(--popover-foreground);
347
- --color-card: var(--card);
348
- --color-card-foreground: var(--card-foreground);
349
- --radius-sm: calc(var(--radius) - 4px);
350
- --radius-md: calc(var(--radius) - 2px);
351
- --radius-lg: var(--radius);
352
- --radius-xl: calc(var(--radius) + 4px);
353
- }
354
203
  ```
355
204
 
356
- **Tailwind v3**
357
-
205
+ **Tailwind v3:**
358
206
  ```javascript
359
207
  // tailwind.config.js
360
208
  module.exports = {
@@ -365,118 +213,57 @@ module.exports = {
365
213
  }
366
214
  ```
367
215
 
368
- </details>
369
-
370
- <details>
371
- <summary><strong>⚠️ Theme CSS Variables</strong> — Required if not using shadcn/ui</summary>
372
-
373
- The field components use [shadcn/ui](https://ui.shadcn.com)-style CSS variables.
374
-
375
- **If you use shadcn/ui:** No action needed — components inherit your existing theme.
376
-
377
- **If you don't use shadcn/ui:** Copy the theme boilerplate:
378
-
379
- ```bash
380
- cp node_modules/@delmaredigital/payload-puck/examples/styles/puck-theme.css src/styles/
381
- ```
216
+ ### Theme CSS Variables
382
217
 
383
- Then import it:
218
+ The plugin uses [shadcn/ui](https://ui.shadcn.com)-style CSS variables. If you don't use shadcn/ui, define these in your CSS:
384
219
 
385
220
  ```css
386
- @import './puck-theme.css';
221
+ :root {
222
+ --background: 0 0% 100%;
223
+ --foreground: 222.2 84% 4.9%;
224
+ --primary: 222.2 47.4% 11.2%;
225
+ --primary-foreground: 210 40% 98%;
226
+ --secondary: 210 40% 96%;
227
+ --secondary-foreground: 222.2 47.4% 11.2%;
228
+ --muted: 210 40% 96%;
229
+ --muted-foreground: 215.4 16.3% 46.9%;
230
+ --accent: 210 40% 96%;
231
+ --accent-foreground: 222.2 47.4% 11.2%;
232
+ --destructive: 0 84.2% 60.2%;
233
+ --destructive-foreground: 210 40% 98%;
234
+ --border: 214.3 31.8% 91.4%;
235
+ --input: 214.3 31.8% 91.4%;
236
+ --ring: 222.2 84% 4.9%;
237
+ --radius: 0.5rem;
238
+ }
387
239
  ```
388
240
 
389
- <details>
390
- <summary>CSS Variable Reference</summary>
391
-
392
- | Variable | Purpose |
393
- |----------|---------|
394
- | `--background` | Page background color |
395
- | `--foreground` | Default text color |
396
- | `--primary` | Primary buttons, active states |
397
- | `--primary-foreground` | Text on primary backgrounds |
398
- | `--secondary` | Secondary buttons |
399
- | `--secondary-foreground` | Text on secondary backgrounds |
400
- | `--muted` | Subtle backgrounds, disabled states |
401
- | `--muted-foreground` | Muted text |
402
- | `--accent` | Hover states |
403
- | `--accent-foreground` | Text on accent backgrounds |
404
- | `--destructive` | Error messages, delete buttons |
405
- | `--destructive-foreground` | Text on destructive backgrounds |
406
- | `--border` | General borders |
407
- | `--input` | Form input borders |
408
- | `--ring` | Focus rings |
409
- | `--popover` | Dropdown/modal backgrounds |
410
- | `--popover-foreground` | Text in popovers |
411
- | `--card` | Card backgrounds |
412
- | `--card-foreground` | Text in cards |
413
- | `--radius` | Base border radius |
414
-
415
- </details>
416
-
417
- </details>
418
-
419
- ---
420
-
421
- ## Setup Checklist
422
-
423
- Use this checklist to verify your setup is complete.
424
-
425
- ### ✅ Core Setup
426
-
427
- - [ ] Install packages: `@delmaredigital/payload-puck` and `@measured/puck`
428
- - [ ] Add `createPuckPlugin()` to your Payload config
429
- - [ ] Create API routes (`/api/puck/pages` and `/api/puck/pages/[id]`)
430
- - [ ] Create editor route layout that imports Tailwind CSS (see examples)
431
- - [ ] Create the editor page component with `PuckEditorView`
432
- - [ ] Create a frontend route with `PageRenderer`
433
-
434
- ### ⚠️ Styling Setup
435
-
436
- - [ ] Install and configure `@tailwindcss/typography`
437
- - [ ] Add Tailwind `@source` directive (v4) or `content` path (v3)
438
- - [ ] Set up theme CSS variables (if not using shadcn/ui)
439
-
440
- ### ⚙️ Collection Config
441
-
442
- - [ ] Enable `versions: { drafts: true }` on your pages collection
443
-
444
- ### 📦 Optional
445
-
446
- - [ ] Version history API route (`/api/puck/pages/[id]/versions`)
447
- - [ ] Custom theme configuration via `ThemeProvider`
448
- - [ ] Custom layouts with headers/footers
449
- - [ ] Custom components
450
-
451
241
  ---
452
242
 
453
- <details>
454
- <summary><strong>Core Concepts</strong> — Server vs Client configs, Draft system</summary>
243
+ ## Core Concepts
455
244
 
456
245
  ### Server vs Client Configuration
457
246
 
458
- The plugin provides two configurations to handle React Server Components:
247
+ The plugin provides two configurations for React Server Components:
459
248
 
460
249
  | Config | Import | Use Case |
461
250
  |--------|--------|----------|
462
251
  | `baseConfig` | `@delmaredigital/payload-puck/config` | Server-safe rendering with `PageRenderer` |
463
- | `editorConfig` | `@delmaredigital/payload-puck/config/editor` | Client-side editing with full TipTap support |
252
+ | `editorConfig` | `@delmaredigital/payload-puck/config/editor` | Client-side editing with full interactivity |
464
253
 
465
254
  ```typescript
466
255
  // Server component - use baseConfig
467
256
  import { baseConfig } from '@delmaredigital/payload-puck/config'
468
257
  <PageRenderer config={baseConfig} data={page.puckData} />
469
258
 
470
- // Client component - use editorConfig
259
+ // PuckConfigProvider - use editorConfig
471
260
  import { editorConfig } from '@delmaredigital/payload-puck/config/editor'
472
- <PuckEditor config={editorConfig} ... />
261
+ <PuckConfigProvider config={editorConfig}>
473
262
  ```
474
263
 
475
264
  ### Draft System
476
265
 
477
- The editor uses Payload's native draft system.
478
-
479
- > **⚠️ Required:** Without `drafts: true`, the Save Draft and Publish buttons won't work correctly.
266
+ The editor uses Payload's native draft system. The plugin automatically enables drafts on the pages collection. You can also enable it manually:
480
267
 
481
268
  ```typescript
482
269
  {
@@ -487,978 +274,306 @@ The editor uses Payload's native draft system.
487
274
  }
488
275
  ```
489
276
 
490
- </details>
491
-
492
277
  ---
493
278
 
494
- <details>
495
- <summary><strong>Components</strong> — Layout, Typography, Media, Interactive</summary>
279
+ ## Components
496
280
 
497
281
  ### Layout
498
282
 
499
- | Component | Description | Responsive Controls |
500
- |-----------|-------------|---------------------|
501
- | **Container** | Content wrapper with max-width and background options | Dimensions, Padding, Margin, Visibility |
502
- | **Flex** | Flexible box layout with direction and alignment | Dimensions, Padding, Margin, Visibility |
503
- | **Grid** | CSS Grid layout with responsive columns | Dimensions, Padding, Margin, Visibility |
504
- | **Section** | Full-width section with slot for nested content | Dimensions, Padding, Margin, Visibility |
505
- | **Spacer** | Vertical/horizontal spacing element | Visibility |
506
- | **Template** | Reusable component arrangements - save and load templates | Dimensions, Padding, Margin, Visibility |
283
+ | Component | Description |
284
+ |-----------|-------------|
285
+ | **Container** | Content wrapper with max-width and background |
286
+ | **Flex** | Flexible box layout with direction and alignment |
287
+ | **Grid** | CSS Grid layout with responsive columns |
288
+ | **Section** | Two-layer: full-bleed section + constrained content area |
289
+ | **Spacer** | Vertical/horizontal spacing element |
290
+ | **Template** | Save/load reusable component arrangements |
507
291
 
508
292
  ### Typography
509
293
 
510
- | Component | Description | Responsive Controls |
511
- |-----------|-------------|---------------------|
512
- | **Heading** | H1-H6 headings with size and alignment options | — |
513
- | **Text** | Paragraph text with styling options | — |
514
- | **RichText** | TipTap-powered WYSIWYG editor | — |
515
-
516
- > **⚠️ RichText requires `@tailwindcss/typography`** — see [Styling Setup](#styling-setup). Without it, content renders without proper formatting.
517
-
518
- ### Media
294
+ | Component | Description |
295
+ |-----------|-------------|
296
+ | **Heading** | H1-H6 headings with size and alignment |
297
+ | **Text** | Paragraph text with styling options |
298
+ | **RichText** | TipTap-powered WYSIWYG editor |
519
299
 
520
- | Component | Description | Responsive Controls |
521
- |-----------|-------------|---------------------|
522
- | **Image** | Responsive image with alt text and sizing | Visibility |
300
+ ### Media & Interactive
523
301
 
524
- ### Interactive
525
-
526
- | Component | Description | Responsive Controls |
527
- |-----------|-------------|---------------------|
528
- | **Button** | Styled button/link with variants | |
529
- | **Card** | Content card with optional image header | — |
530
- | **Divider** | Horizontal rule with style options | — |
531
- | **Accordion** | Expandable content sections | — |
302
+ | Component | Description |
303
+ |-----------|-------------|
304
+ | **Image** | Responsive image with alt text |
305
+ | **Button** | Styled button/link with variants |
306
+ | **Card** | Content card with optional image |
307
+ | **Divider** | Horizontal rule with styles |
308
+ | **Accordion** | Expandable content sections |
532
309
 
533
310
  ### Responsive Controls
534
311
 
535
- Components with responsive controls allow you to customize their behavior at different breakpoints (mobile, tablet, desktop). Available controls:
312
+ Layout components support per-breakpoint customization:
313
+ - **Dimensions** - Width, max-width, height constraints
314
+ - **Padding/Margin** - Spacing per breakpoint
315
+ - **Visibility** - Show/hide at specific breakpoints
536
316
 
537
- - **Dimensions** - Width, max-width, height constraints per breakpoint
538
- - **Padding** - Inner spacing per breakpoint
539
- - **Margin** - Outer spacing per breakpoint
540
- - **Visibility** - Show/hide components at specific breakpoints
317
+ ---
541
318
 
542
- Breakpoints follow Tailwind CSS conventions:
543
- | Breakpoint | Min Width | Description |
544
- |------------|-----------|-------------|
545
- | base | 0px | Mobile (default) |
546
- | sm | 640px | Small tablets |
547
- | md | 768px | Tablets |
548
- | lg | 1024px | Laptops |
549
- | xl | 1280px | Desktops |
319
+ ## Custom Fields
550
320
 
551
- ### Template Component
321
+ All fields are imported from `@delmaredigital/payload-puck/fields`.
552
322
 
553
- The Template component allows saving groups of components as reusable templates. The plugin automatically creates a `puck-templates` collection in Payload.
323
+ ### Field Reference
554
324
 
555
- **Saving a template:**
556
- 1. Add a Template component to your page
557
- 2. Add child components inside the Template slot
558
- 3. Click "Save as Template" and give it a name/category
325
+ | Field | Description |
326
+ |-------|-------------|
327
+ | **MediaField** | Payload media library integration |
328
+ | **TiptapField** | Rich text editor with formatting |
329
+ | **ColorPickerField** | Color picker with opacity and presets |
330
+ | **BackgroundField** | Solid colors, gradients, images |
331
+ | **PaddingField / MarginField** | Visual spacing editors |
332
+ | **BorderField** | Border width, style, color, radius |
333
+ | **DimensionsField** | Width/height with constraints |
334
+ | **AlignmentField** | Text alignment options |
335
+ | **AnimationField** | Entrance animations |
336
+ | **ResponsiveVisibilityField** | Show/hide per breakpoint |
337
+ | **FolderPickerField** | Hierarchical folder selection (page-tree) |
338
+ | **PageSegmentField** | URL segment with slugification (page-tree) |
339
+ | **SlugPreviewField** | Read-only computed slug (page-tree) |
340
+
341
+ ### Usage Example
342
+
343
+ ```typescript
344
+ import { createMediaField, createBackgroundField, backgroundValueToCSS } from '@delmaredigital/payload-puck/fields'
345
+
346
+ const HeroConfig = {
347
+ fields: {
348
+ image: createMediaField({ label: 'Background Image' }),
349
+ background: createBackgroundField({ label: 'Overlay' }),
350
+ },
351
+ render: ({ image, background }) => (
352
+ <section style={{ background: backgroundValueToCSS(background) }}>
353
+ {/* content */}
354
+ </section>
355
+ ),
356
+ }
357
+ ```
559
358
 
560
- **Loading a template:**
561
- 1. Add a Template component to your page
562
- 2. Select a saved template from the dropdown
563
- 3. The template's components are loaded into the slot
359
+ ### CSS Helper Functions
564
360
 
565
- </details>
361
+ ```typescript
362
+ import {
363
+ backgroundValueToCSS,
364
+ dimensionsValueToCSS,
365
+ animationValueToCSS,
366
+ visibilityValueToCSS,
367
+ } from '@delmaredigital/payload-puck/fields'
368
+ ```
566
369
 
567
370
  ---
568
371
 
569
- <details>
570
- <summary><strong>Configuration</strong> — Merging configs, Custom components</summary>
372
+ ## Theming
571
373
 
572
- ### Merging Custom Components
374
+ Customize button styles, color presets, and focus rings:
573
375
 
574
376
  ```typescript
575
- import { mergeConfigs } from '@delmaredigital/payload-puck/config'
576
- import { baseConfig } from '@delmaredigital/payload-puck/config'
577
- import { MyCustomComponent } from './components/MyCustomComponent'
377
+ import { PageRenderer } from '@delmaredigital/payload-puck/render'
378
+ import { ThemeProvider } from '@delmaredigital/payload-puck/theme'
578
379
 
579
- const customConfig = mergeConfigs({
580
- base: baseConfig,
581
- components: {
582
- MyCustomComponent,
583
- },
584
- categories: {
585
- custom: { title: 'Custom', components: ['MyCustomComponent'] },
380
+ <ThemeProvider theme={{
381
+ buttonVariants: {
382
+ default: { classes: 'bg-primary text-white hover:bg-primary/90' },
383
+ secondary: { classes: 'bg-secondary text-foreground hover:bg-secondary/90' },
586
384
  },
587
- exclude: ['Spacer'], // Optionally remove components
588
- })
385
+ focusRingColor: 'focus:ring-primary',
386
+ colorPresets: [
387
+ { hex: '#3b82f6', label: 'Brand Blue' },
388
+ { hex: '#10b981', label: 'Success' },
389
+ ],
390
+ }}>
391
+ <PageRenderer config={baseConfig} data={page.puckData} />
392
+ </ThemeProvider>
589
393
  ```
590
394
 
591
- ### Creating Custom Components
592
-
593
- Components need two variants to work across server rendering and the editor:
594
-
595
- | File | Purpose | Used By |
596
- |------|---------|---------|
597
- | `MyComponent.server.tsx` | Server-safe render (no hooks/interactivity) | `baseConfig` → `PageRenderer` |
598
- | `MyComponent.tsx` or `.editor.tsx` | Full interactivity + field definitions | `editorConfig` → `PuckEditor` |
395
+ ---
599
396
 
600
- **Server variant** (`MyComponent.server.tsx`):
601
- - No `'use client'` directive
602
- - No React hooks (`useState`, `useEffect`, etc.)
603
- - No event handlers that require client JS
604
- - **If component has slots**: Must include `fields: { content: { type: 'slot' } }` (Puck needs this to transform slot data into a renderable component)
605
- - Other fields can be omitted (not used in rendering)
397
+ ## Layouts
606
398
 
607
- **Editor variant** (`MyComponent.tsx`):
608
- - Can use `'use client'` if needed
609
- - Full interactivity with hooks
610
- - Includes all `fields` for the Puck sidebar
399
+ Define page layouts with headers, footers, and styling:
611
400
 
612
- <details>
613
- <summary><strong>Example: Interactive Component</strong></summary>
401
+ ```typescript
402
+ // lib/puck-layouts.ts
403
+ import type { LayoutDefinition } from '@delmaredigital/payload-puck/layouts'
404
+ import { SiteHeader } from '@/components/header'
405
+ import { SiteFooter } from '@/components/footer'
614
406
 
615
- ```tsx
616
- // components/Tabs.server.tsx - Server-safe version
617
- import type { ComponentConfig } from '@measured/puck'
407
+ export const siteLayouts: LayoutDefinition[] = [
408
+ {
409
+ value: 'default',
410
+ label: 'Default',
411
+ description: 'Standard page with header and footer',
412
+ maxWidth: '1200px',
413
+ header: SiteHeader,
414
+ footer: SiteFooter,
415
+ stickyHeaderHeight: 80,
416
+ },
417
+ {
418
+ value: 'landing',
419
+ label: 'Landing',
420
+ description: 'Full-width landing page',
421
+ fullWidth: true,
422
+ },
423
+ ]
424
+ ```
618
425
 
619
- export interface TabsProps {
620
- items: { title: string; content: string }[]
621
- defaultTab: number
622
- }
426
+ Pass layouts to the `PuckConfigProvider`:
623
427
 
624
- export const TabsConfig: ComponentConfig<TabsProps> = {
625
- label: 'Tabs',
626
- defaultProps: {
627
- items: [{ title: 'Tab 1', content: 'Content 1' }],
628
- defaultTab: 0,
629
- },
630
- // No fields - server version only renders
631
- render: ({ items, defaultTab }) => (
632
- <div>
633
- {/* Render only the default tab statically */}
634
- <div className="flex border-b">
635
- {items.map((item, i) => (
636
- <div key={i} className={i === defaultTab ? 'border-b-2 border-primary' : ''}>
637
- {item.title}
638
- </div>
639
- ))}
640
- </div>
641
- <div>{items[defaultTab]?.content}</div>
642
- </div>
643
- ),
644
- }
428
+ ```typescript
429
+ <PuckConfigProvider config={editorConfig} layouts={siteLayouts}>
430
+ {children}
431
+ </PuckConfigProvider>
645
432
  ```
646
433
 
647
- ```tsx
648
- // components/Tabs.tsx - Editor version with interactivity
649
- 'use client'
434
+ And use them with `PageRenderer`:
650
435
 
651
- import type { ComponentConfig } from '@measured/puck'
652
- import { useState } from 'react'
436
+ ```typescript
437
+ import { LayoutWrapper } from '@delmaredigital/payload-puck/layouts'
653
438
 
654
- export interface TabsProps {
655
- items: { title: string; content: string }[]
656
- defaultTab: number
657
- }
439
+ const layout = siteLayouts.find(l => l.value === page.puckData?.root?.props?.pageLayout)
658
440
 
659
- export const TabsConfig: ComponentConfig<TabsProps> = {
660
- label: 'Tabs',
661
- fields: {
662
- items: {
663
- type: 'array',
664
- label: 'Tabs',
665
- arrayFields: {
666
- title: { type: 'text', label: 'Title' },
667
- content: { type: 'textarea', label: 'Content' },
668
- },
669
- },
670
- defaultTab: { type: 'number', label: 'Default Tab' },
671
- },
672
- defaultProps: {
673
- items: [{ title: 'Tab 1', content: 'Content 1' }],
674
- defaultTab: 0,
675
- },
676
- render: ({ items, defaultTab }) => {
677
- const [activeTab, setActiveTab] = useState(defaultTab)
678
-
679
- return (
680
- <div>
681
- <div className="flex border-b">
682
- {items.map((item, i) => (
683
- <button
684
- key={i}
685
- onClick={() => setActiveTab(i)}
686
- className={i === activeTab ? 'border-b-2 border-primary' : ''}
687
- >
688
- {item.title}
689
- </button>
690
- ))}
691
- </div>
692
- <div>{items[activeTab]?.content}</div>
693
- </div>
694
- )
695
- },
696
- }
441
+ <LayoutWrapper layout={layout}>
442
+ <PageRenderer config={baseConfig} data={page.puckData} />
443
+ </LayoutWrapper>
697
444
  ```
698
445
 
699
- Then register both:
700
- ```tsx
701
- // In your custom baseConfig
702
- import { TabsConfig } from './components/Tabs.server'
446
+ ---
703
447
 
704
- // In your custom editorConfig
705
- import { TabsConfig } from './components/Tabs'
706
- ```
707
- </details>
448
+ ## Page-Tree Integration
708
449
 
709
- <details>
710
- <summary><strong>Example: Component with Slot (nested components)</strong></summary>
450
+ When `@delmaredigital/payload-page-tree` is detected, the plugin automatically adds folder management to the Puck sidebar.
711
451
 
712
- ```tsx
713
- // components/Card.server.tsx - Server-safe version WITH slot field
714
- import type { ComponentConfig } from '@measured/puck'
452
+ ### How It Works
715
453
 
716
- export interface CardProps {
717
- content: unknown // Slot for nested components
718
- title: string
719
- }
454
+ The plugin checks if your collection has a `pageSegment` field (page-tree's signature). When detected:
720
455
 
721
- export const CardConfig: ComponentConfig<CardProps> = {
722
- label: 'Card',
723
- // CRITICAL: Slot field MUST be defined for Puck to transform data into component
724
- fields: {
725
- content: { type: 'slot' },
726
- },
727
- defaultProps: {
728
- content: [],
729
- title: 'Card Title',
730
- },
731
- render: ({ content: Content, title }) => (
732
- <div className="border rounded-lg p-4">
733
- <h3 className="font-bold mb-2">{title}</h3>
734
- <Content /> {/* Renders nested components */}
735
- </div>
736
- ),
737
- }
738
- ```
456
+ 1. **Folder Picker** - Select a folder from the hierarchy
457
+ 2. **Page Segment** - Edit the page's URL segment
458
+ 3. **Slug Preview** - See the computed slug (folder path + segment)
739
459
 
740
- ```tsx
741
- // components/Card.tsx - Editor version with all fields
742
- import type { ComponentConfig } from '@measured/puck'
460
+ ### Configuration
743
461
 
744
- export interface CardProps {
745
- content: unknown
746
- title: string
747
- }
462
+ ```typescript
463
+ createPuckPlugin({
464
+ // Auto-detect (default)
465
+ pageTreeIntegration: undefined,
748
466
 
749
- export const CardConfig: ComponentConfig<CardProps> = {
750
- label: 'Card',
751
- fields: {
752
- title: { type: 'text', label: 'Title' },
753
- content: { type: 'slot' },
754
- },
755
- defaultProps: {
756
- content: [],
757
- title: 'Card Title',
467
+ // Explicitly enable with custom config
468
+ pageTreeIntegration: {
469
+ folderSlug: 'payload-folders',
470
+ pageSegmentFieldName: 'pageSegment',
758
471
  },
759
- render: ({ content: Content, title }) => (
760
- <div className="border rounded-lg p-4">
761
- <h3 className="font-bold mb-2">{title}</h3>
762
- <Content />
763
- </div>
764
- ),
765
- }
472
+
473
+ // Explicitly disable
474
+ pageTreeIntegration: false,
475
+ })
766
476
  ```
767
477
 
768
- **Why slots need the field definition:** Puck stores slot content as an array of component data. The `fields: { content: { type: 'slot' } }` tells Puck to transform this array into a renderable `<Content />` component before passing it to `render()`. Without this, you'll get "Element type is invalid: got array" errors.
769
- </details>
478
+ ### Performance
770
479
 
771
- </details>
480
+ Detection is instant - it reads the in-memory collection config, no database queries.
772
481
 
773
482
  ---
774
483
 
775
- <details>
776
- <summary><strong>Custom Fields</strong> — 19 field types with usage examples</summary>
484
+ ## Hybrid Integration
777
485
 
778
- All fields are imported from `@delmaredigital/payload-puck/fields`.
486
+ Add Puck to existing collections with legacy blocks.
779
487
 
780
- ### Field Reference
488
+ ### Automatic (Recommended)
781
489
 
782
- | Field | Description |
783
- |-------|-------------|
784
- | **MediaField** | Payload media library integration with upload/browse |
785
- | **TiptapField** | Rich text editor with formatting toolbar |
786
- | **ColorPickerField** | Color picker with presets and transparency |
787
- | **BackgroundField** | Backgrounds with solid colors, gradients, and images |
788
- | **PaddingField** | Visual padding editor with per-side controls |
789
- | **MarginField** | Visual margin editor with per-side controls |
790
- | **BorderField** | Border editor with width, style, color, radius |
791
- | **DimensionsField** | Width/height with min/max constraints |
792
- | **SizeField** | Preset sizes (sm, md, lg) or custom values |
793
- | **AlignmentField** | Text alignment (left, center, right, justify) |
794
- | **JustifyContentField** | Flexbox justify-content options |
795
- | **AlignItemsField** | Flexbox align-items options |
796
- | **VerticalAlignmentField** | Vertical alignment (top, center, bottom) |
797
- | **LockedTextField** | Protected text field with edit confirmation |
798
- | **LockedRadioField** | Protected radio field with edit confirmation |
799
- | **ResponsiveField** | Per-breakpoint values for responsive design |
800
- | **ResponsiveVisibilityField** | Show/hide toggle per breakpoint (Divi/Elementor-style) |
801
- | **AnimationField** | Entrance animations with easing/duration |
802
- | **TransformField** | CSS transforms (rotate, scale, translate) |
803
- | **GradientEditor** | Visual gradient builder |
804
-
805
- ### Usage Examples
806
-
807
- <details>
808
- <summary><strong>MediaField</strong></summary>
809
-
810
- Integrates with Payload's media collection:
811
-
812
- ```typescript
813
- import { createMediaField } from '@delmaredigital/payload-puck/fields'
814
-
815
- const config = {
816
- components: {
817
- Hero: {
818
- fields: {
819
- backgroundImage: createMediaField({
820
- label: 'Background Image',
821
- collection: 'media', // Default: 'media'
822
- }),
823
- },
824
- },
825
- },
826
- }
827
- ```
828
- </details>
829
-
830
- <details>
831
- <summary><strong>TiptapField</strong></summary>
832
-
833
- Rich text editor with formatting toolbar:
834
-
835
- ```typescript
836
- import { createTiptapField } from '@delmaredigital/payload-puck/fields'
837
-
838
- const config = {
839
- components: {
840
- TextBlock: {
841
- fields: {
842
- content: createTiptapField({ label: 'Content' }),
843
- },
844
- },
845
- },
846
- }
847
- ```
848
- </details>
849
-
850
- <details>
851
- <summary><strong>ColorPickerField</strong></summary>
852
-
853
- Color picker with presets and alpha channel:
854
-
855
- ```typescript
856
- import { createColorPickerField } from '@delmaredigital/payload-puck/fields'
857
-
858
- const config = {
859
- components: {
860
- Section: {
861
- fields: {
862
- backgroundColor: createColorPickerField({
863
- label: 'Background Color',
864
- }),
865
- },
866
- },
867
- },
868
- }
869
- ```
870
- </details>
871
-
872
- <details>
873
- <summary><strong>BackgroundField</strong></summary>
874
-
875
- Full background editor with solid colors, gradients, and images:
876
-
877
- ```typescript
878
- import { createBackgroundField, backgroundValueToCSS } from '@delmaredigital/payload-puck/fields'
879
-
880
- const config = {
881
- components: {
882
- Section: {
883
- fields: {
884
- background: createBackgroundField({ label: 'Background' }),
885
- },
886
- render: ({ background }) => (
887
- <section style={{ background: backgroundValueToCSS(background) }}>
888
- {/* content */}
889
- </section>
890
- ),
891
- },
892
- },
893
- }
894
- ```
895
- </details>
896
-
897
- <details>
898
- <summary><strong>DimensionsField</strong></summary>
899
-
900
- Width/height with min/max constraints and alignment:
901
-
902
- ```typescript
903
- import { createDimensionsField, dimensionsValueToCSS } from '@delmaredigital/payload-puck/fields'
904
-
905
- const config = {
906
- components: {
907
- Container: {
908
- fields: {
909
- dimensions: createDimensionsField({ label: 'Size' }),
910
- },
911
- render: ({ dimensions, children }) => (
912
- <div style={dimensionsValueToCSS(dimensions)}>
913
- {children}
914
- </div>
915
- ),
916
- },
917
- },
918
- }
919
- ```
920
- </details>
921
-
922
- <details>
923
- <summary><strong>PaddingField & MarginField</strong></summary>
924
-
925
- Visual spacing editors:
490
+ If you already have a `pages` collection, the plugin adds only the Puck-specific fields:
926
491
 
927
492
  ```typescript
928
- import { createPaddingField, createMarginField } from '@delmaredigital/payload-puck/fields'
929
-
930
- const config = {
931
- components: {
932
- Box: {
933
- fields: {
934
- padding: createPaddingField({ label: 'Padding' }),
935
- margin: createMarginField({ label: 'Margin' }),
936
- },
937
- },
938
- },
939
- }
940
- ```
941
- </details>
942
-
943
- <details>
944
- <summary><strong>LockedTextField & LockedRadioField</strong></summary>
945
-
946
- Protected fields that require confirmation before editing:
947
-
948
- ```typescript
949
- import {
950
- createLockedTextField,
951
- createLockedRadioField,
952
- lockedSlugField, // Pre-built slug field
953
- lockedHomepageField, // Pre-built homepage toggle
954
- } from '@delmaredigital/payload-puck/fields'
955
-
956
- // Use pre-built fields
957
- const config = {
958
- root: {
959
- fields: {
960
- slug: lockedSlugField,
961
- isHomepage: lockedHomepageField,
493
+ // payload.config.ts
494
+ export default buildConfig({
495
+ collections: [
496
+ {
497
+ slug: 'pages',
498
+ fields: [
499
+ { name: 'title', type: 'text', required: true },
500
+ { name: 'layout', type: 'blocks', blocks: [HeroBlock, CTABlock] },
501
+ ],
962
502
  },
963
- },
964
- }
965
-
966
- // Or create custom locked fields
967
- const customLockedField = createLockedTextField({
968
- label: 'API Key',
969
- placeholder: 'Enter API key',
970
- warningMessage: 'Changing this will break integrations.',
503
+ ],
504
+ plugins: [
505
+ createPuckPlugin({ pagesCollection: 'pages' }),
506
+ ],
971
507
  })
972
508
  ```
973
- </details>
974
-
975
- <details>
976
- <summary><strong>AnimationField</strong></summary>
977
-
978
- Entrance animations with customizable timing:
979
-
980
- ```typescript
981
- import { createAnimationField, getEntranceAnimationClasses } from '@delmaredigital/payload-puck/fields'
982
-
983
- const config = {
984
- components: {
985
- AnimatedSection: {
986
- fields: {
987
- animation: createAnimationField({ label: 'Entrance Animation' }),
988
- },
989
- render: ({ animation, children }) => (
990
- <div className={getEntranceAnimationClasses(animation)}>
991
- {children}
992
- </div>
993
- ),
994
- },
995
- },
996
- }
997
- ```
998
- </details>
999
-
1000
- <details>
1001
- <summary><strong>ResponsiveField</strong></summary>
1002
-
1003
- Values that change per breakpoint:
1004
-
1005
- ```typescript
1006
- import { createResponsiveField, BREAKPOINTS } from '@delmaredigital/payload-puck/fields'
1007
-
1008
- const config = {
1009
- components: {
1010
- Grid: {
1011
- fields: {
1012
- columns: createResponsiveField({
1013
- label: 'Columns',
1014
- field: { type: 'number' },
1015
- defaultValue: { sm: 1, md: 2, lg: 3 },
1016
- }),
1017
- },
1018
- },
1019
- },
1020
- }
1021
- ```
1022
- </details>
1023
-
1024
- <details>
1025
- <summary><strong>ResponsiveVisibilityField</strong></summary>
1026
-
1027
- Show/hide components at different breakpoints (like Divi/Elementor):
1028
-
1029
- ```typescript
1030
- import { createResponsiveVisibilityField, visibilityValueToCSS } from '@delmaredigital/payload-puck/fields'
1031
-
1032
- const config = {
1033
- components: {
1034
- MobileOnlyBanner: {
1035
- fields: {
1036
- visibility: createResponsiveVisibilityField({ label: 'Visibility' }),
1037
- },
1038
- render: ({ visibility, children }) => {
1039
- const visibilityCSS = visibilityValueToCSS(visibility, 'mobile-banner')
1040
- return (
1041
- <>
1042
- {visibilityCSS && <style>{visibilityCSS}</style>}
1043
- <div className="mobile-banner">{children}</div>
1044
- </>
1045
- )
1046
- },
1047
- },
1048
- },
1049
- }
1050
- ```
1051
-
1052
- The field displays device icons with visibility toggles. Green = visible, Red = hidden at that breakpoint.
1053
- </details>
1054
-
1055
- ### CSS Helper Functions
1056
-
1057
- Convert field values to CSS:
1058
-
1059
- ```typescript
1060
- import {
1061
- backgroundValueToCSS,
1062
- dimensionsValueToCSS,
1063
- animationValueToCSS,
1064
- transformValueToCSS,
1065
- gradientValueToCSS,
1066
- sizeValueToCSS,
1067
- // Responsive helpers
1068
- responsiveValueToCSS,
1069
- visibilityValueToCSS,
1070
- } from '@delmaredigital/payload-puck/fields'
1071
-
1072
- const styles = {
1073
- background: backgroundValueToCSS(background),
1074
- ...dimensionsValueToCSS(dimensions),
1075
- animation: animationValueToCSS(animation),
1076
- transform: transformValueToCSS(transform),
1077
- }
1078
-
1079
- // Responsive values generate CSS media queries
1080
- const uniqueId = 'my-component-123'
1081
- const { baseStyles, mediaQueryCSS } = responsiveValueToCSS(
1082
- dimensions, // ResponsiveValue<T> or T
1083
- dimensionsValueToCSS, // Converter function
1084
- uniqueId // CSS class selector
1085
- )
1086
-
1087
- // Visibility generates show/hide media queries
1088
- const visibilityCSS = visibilityValueToCSS(visibility, uniqueId)
1089
-
1090
- // Render with media queries
1091
- return (
1092
- <>
1093
- {mediaQueryCSS && <style>{mediaQueryCSS}</style>}
1094
- {visibilityCSS && <style>{visibilityCSS}</style>}
1095
- <div className={uniqueId} style={baseStyles}>{children}</div>
1096
- </>
1097
- )
1098
- ```
1099
-
1100
- </details>
1101
509
 
1102
- ---
1103
-
1104
- <details>
1105
- <summary><strong>Theming</strong> — Button variants, color presets, focus rings</summary>
1106
-
1107
- Customize button styles, color presets, and focus rings to match your design system.
1108
-
1109
- ### Basic Usage
1110
-
1111
- Wrap your `PageRenderer` with `ThemeProvider` to apply custom theming:
1112
-
1113
- ```typescript
1114
- import { PageRenderer } from '@delmaredigital/payload-puck/render'
1115
- import { ThemeProvider } from '@delmaredigital/payload-puck/theme'
1116
-
1117
- <ThemeProvider theme={{
1118
- buttonVariants: {
1119
- default: { classes: 'bg-primary text-primary-foreground hover:bg-primary/90' },
1120
- secondary: { classes: 'bg-secondary text-secondary-foreground hover:bg-secondary/90' },
1121
- },
1122
- focusRingColor: 'focus:ring-primary',
1123
- }}>
1124
- <PageRenderer config={baseConfig} data={page.puckData} />
1125
- </ThemeProvider>
1126
- ```
510
+ The `editorVersion` field auto-detects whether pages use legacy blocks or Puck.
1127
511
 
1128
- ### Using the Example Theme
512
+ ### Manual with `getPuckFields()`
1129
513
 
1130
514
  ```typescript
1131
- import { ThemeProvider, exampleTheme } from '@delmaredigital/payload-puck/theme'
1132
-
1133
- <ThemeProvider theme={exampleTheme}>
1134
- <PageRenderer data={page.puckData} />
1135
- </ThemeProvider>
1136
-
1137
- // Or customize specific values
1138
- <ThemeProvider theme={{
1139
- ...exampleTheme,
1140
- focusRingColor: 'focus:ring-brand',
1141
- }}>
1142
- <PageRenderer data={page.puckData} />
1143
- </ThemeProvider>
1144
- ```
1145
-
1146
- ### Theme Options
1147
-
1148
- | Option | Description |
1149
- |--------|-------------|
1150
- | `buttonVariants` | Button component variant styles (default, secondary, outline, ghost) |
1151
- | `ctaButtonVariants` | CallToAction button styles (primary, secondary, outline) |
1152
- | `ctaBackgroundStyles` | CallToAction background styles (default, dark, light) |
1153
- | `colorPresets` | Color picker preset swatches |
1154
- | `extendColorPresets` | If true, adds to defaults instead of replacing |
1155
- | `focusRingColor` | Focus ring class (e.g., `focus:ring-primary`) |
1156
-
1157
- ### Custom Color Presets
515
+ import { getPuckFields } from '@delmaredigital/payload-puck'
1158
516
 
1159
- ```typescript
1160
- <ThemeProvider theme={{
1161
- colorPresets: [
1162
- { hex: '#3b82f6', label: 'Brand Blue' },
1163
- { hex: '#10b981', label: 'Success' },
1164
- { hex: '#ef4444', label: 'Danger' },
517
+ export const Pages: CollectionConfig = {
518
+ slug: 'pages',
519
+ fields: [
520
+ { name: 'title', type: 'text' },
521
+ { name: 'layout', type: 'blocks', blocks: [...] },
522
+ ...getPuckFields({
523
+ includeSEO: true,
524
+ includeEditorVersion: true,
525
+ includePageLayout: true,
526
+ }),
1165
527
  ],
1166
- extendColorPresets: false, // Replace defaults
1167
- }}>
1168
- <PageRenderer data={page.puckData} />
1169
- </ThemeProvider>
1170
- ```
1171
-
1172
- ### Direct Theme Imports
1173
-
1174
- ```typescript
1175
- import {
1176
- ThemeProvider,
1177
- useTheme,
1178
- getVariantClasses,
1179
- DEFAULT_THEME,
1180
- } from '@delmaredigital/payload-puck/theme'
1181
-
1182
- function MyButton({ variant }) {
1183
- const theme = useTheme()
1184
- const classes = getVariantClasses(theme.buttonVariants, variant)
1185
- return <button className={classes}>Click me</button>
1186
528
  }
1187
529
  ```
1188
530
 
1189
- </details>
1190
-
1191
- ---
1192
-
1193
- <details>
1194
- <summary><strong>Layouts</strong> — Page structure, headers/footers, responsive controls</summary>
1195
-
1196
- The layout system controls page structure, max-width constraints, and optional header/footer rendering. Layouts are selected per-page in the Puck editor's "Page Setup" panel.
1197
-
1198
- ### Built-in Layouts
1199
-
1200
- | Layout | Description |
1201
- |--------|-------------|
1202
- | **Default** | Standard page with max-width container (1200px) |
1203
- | **Landing** | Full-width sections, no container constraints |
1204
- | **Full Width** | Edge-to-edge content |
1205
-
1206
- ### Defining Custom Layouts
531
+ ### Rendering Hybrid Pages
1207
532
 
1208
533
  ```typescript
1209
- // lib/puck-layouts.ts
1210
- import type { LayoutDefinition } from '@delmaredigital/payload-puck/layouts'
1211
- import { SiteHeader } from '@/components/header'
1212
- import { SiteFooter } from '@/components/footer'
1213
-
1214
- export const siteLayouts: LayoutDefinition[] = [
1215
- {
1216
- value: 'default',
1217
- label: 'Default',
1218
- description: 'Standard page with header and footer',
1219
- maxWidth: '1200px',
1220
- header: SiteHeader,
1221
- footer: SiteFooter,
1222
- editorBackground: '#ffffff',
1223
- editorDarkMode: false,
1224
- stickyHeaderHeight: 80,
1225
- // Default background for frontend (overridden by pageBackground in Puck)
1226
- styles: {
1227
- wrapper: {
1228
- background: 'var(--site-bg)',
1229
- backgroundAttachment: 'fixed',
1230
- },
1231
- },
1232
- },
1233
- {
1234
- value: 'landing',
1235
- label: 'Landing',
1236
- description: 'Full-width landing page',
1237
- fullWidth: true,
1238
- editorBackground: '#f8fafc',
1239
- styles: {
1240
- wrapper: {
1241
- background: 'linear-gradient(180deg, #f8fafc 0%, #e2e8f0 100%)',
1242
- },
1243
- },
1244
- },
1245
- {
1246
- value: 'full-width',
1247
- label: 'Full Width',
1248
- description: 'Edge-to-edge content',
1249
- fullWidth: true,
1250
- },
1251
- ]
1252
- ```
1253
-
1254
- > **Background priority:** If a user sets `pageBackground` in the Puck editor, it overrides the layout's `styles.wrapper.background`. This allows layouts to define sensible defaults while letting individual pages customize their appearance.
1255
-
1256
- ### Using Layouts in the Editor
534
+ import { HybridPageRenderer } from '@delmaredigital/payload-puck/render'
535
+ import { LegacyBlockRenderer } from '@/components/LegacyBlockRenderer'
1257
536
 
1258
- ```typescript
1259
- import { PuckEditor } from '@delmaredigital/payload-puck/editor'
1260
- import { siteLayouts } from '@/lib/puck-layouts'
1261
-
1262
- <PuckEditor
1263
- config={editorConfig}
1264
- pageId={page.id}
1265
- initialData={page.puckData}
1266
- layouts={siteLayouts}
537
+ <HybridPageRenderer
538
+ page={page}
539
+ config={puckConfig}
540
+ legacyRenderer={(blocks) => <LegacyBlockRenderer blocks={blocks} />}
1267
541
  />
1268
542
  ```
1269
543
 
1270
- ### Using Layouts on the Frontend
1271
-
1272
- ```typescript
1273
- import { PageRenderer } from '@delmaredigital/payload-puck/render'
1274
- import { LayoutWrapper, DEFAULT_LAYOUTS } from '@delmaredigital/payload-puck/layouts'
1275
-
1276
- export default async function Page({ params }) {
1277
- const page = await getPage(params.slug)
1278
- const layout = DEFAULT_LAYOUTS.find(l => l.value === page.puckData?.root?.props?.pageLayout)
1279
-
1280
- return (
1281
- <LayoutWrapper layout={layout}>
1282
- <PageRenderer config={baseConfig} data={page.puckData} />
1283
- </LayoutWrapper>
1284
- )
1285
- }
1286
- ```
1287
-
1288
- ### Layout Definition Options
1289
-
1290
- | Option | Type | Default | Description |
1291
- |--------|------|---------|-------------|
1292
- | `value` | `string` | — | Unique identifier |
1293
- | `label` | `string` | — | Display name in editor |
1294
- | `description` | `string` | — | Optional description |
1295
- | `maxWidth` | `string` | — | Container max-width (e.g., `'1200px'`) |
1296
- | `fullWidth` | `boolean` | `false` | If true, no container constraints |
1297
- | `classes` | `object` | — | CSS classes for wrapper/container/content |
1298
- | `styles` | `object` | — | Inline styles for wrapper/container/content |
1299
- | `header` | `ComponentType` | — | Header component for editor preview and frontend |
1300
- | `footer` | `ComponentType` | — | Footer component for editor preview and frontend |
1301
- | `editorBackground` | `string` | `'#ffffff'` | Background color/gradient for editor preview |
1302
- | `editorDarkMode` | `boolean` | `false` | Whether to use dark mode styling in editor preview |
1303
- | `stickyHeaderHeight` | `number` | — | Height in px of sticky/fixed header for proper content offset |
1304
- | `stickyFooter` | `boolean` | `true` | Push footer to bottom of viewport even with minimal content. Set to `false` to let footer flow naturally after content |
1305
-
1306
- ### Page-Level Settings
1307
-
1308
- The editor automatically includes page-level controls that allow overriding layout defaults per-page:
1309
-
1310
- | Field | Options | Description |
1311
- |-------|---------|-------------|
1312
- | `showHeader` | `default`, `show`, `hide` | Override header visibility for this page |
1313
- | `showFooter` | `default`, `show`, `hide` | Override footer visibility for this page |
1314
- | `pageBackground` | Background field | Custom page background color/gradient/image |
1315
- | `pageMaxWidth` | Select | Override layout's max-width constraint |
1316
-
1317
- These settings appear in the editor's "Page Setup" panel and are applied in both the editor preview and frontend rendering.
1318
-
1319
- </details>
1320
-
1321
- ---
1322
-
1323
- <details>
1324
- <summary><strong>API Routes</strong> — Auth configuration, root props mapping</summary>
1325
-
1326
- ### Auth Configuration
1327
-
1328
- The API routes require an `auth` configuration with permission hooks:
1329
-
1330
- ```typescript
1331
- const auth = {
1332
- // Required: Authenticate the request
1333
- authenticate: async (request) => {
1334
- const session = await getSession(request)
1335
- if (!session?.user) return { authenticated: false }
1336
- return { authenticated: true, user: session.user }
1337
- },
1338
-
1339
- // Optional permission hooks
1340
- canList: async (user) => ({ allowed: true }),
1341
- canView: async (user, pageId) => ({ allowed: true }),
1342
- canEdit: async (user, pageId) => ({ allowed: user.role === 'editor' }),
1343
- canPublish: async (user, pageId) => ({ allowed: user.role === 'admin' }),
1344
- canDelete: async (user, pageId) => ({ allowed: user.role === 'admin' }),
1345
- }
1346
- ```
1347
-
1348
- ### Root Props Mapping
1349
-
1350
- Sync Puck root.props to Payload fields automatically:
1351
-
1352
- ```typescript
1353
- createPuckApiRoutesWithId({
1354
- // ...
1355
- rootPropsMapping: [
1356
- { from: 'title', to: 'meta.title' },
1357
- { from: 'description', to: 'meta.description' },
1358
- { from: 'pageLayout', to: 'pageLayout' },
1359
- ],
1360
- })
1361
- ```
1362
-
1363
- </details>
1364
-
1365
544
  ---
1366
545
 
1367
- <details>
1368
- <summary><strong>SEO Fields</strong> — Robots meta, sitemap integration</summary>
1369
-
1370
- The plugin adds SEO-related fields to each page in the `meta` group:
1371
-
1372
- | Field | Type | Description |
1373
- |-------|------|-------------|
1374
- | `meta.title` | text | Page title for search engines |
1375
- | `meta.description` | textarea | Meta description |
1376
- | `meta.image` | upload | Social sharing image |
1377
- | `meta.noindex` | checkbox | Prevent search engine indexing |
1378
- | `meta.nofollow` | checkbox | Prevent search engines from following links |
1379
- | `meta.excludeFromSitemap` | checkbox | Exclude page from XML sitemap |
1380
-
1381
- **These fields are not automatically wired to your frontend.** You need to implement them based on your setup.
1382
-
1383
- ### Robots Meta (Next.js App Router)
1384
-
1385
- In your page's `generateMetadata` function:
1386
-
1387
- ```typescript
1388
- // app/(frontend)/[...slug]/page.tsx
1389
- export async function generateMetadata({ params }): Promise<Metadata> {
1390
- const page = await getPage(params.slug)
1391
-
1392
- return {
1393
- title: page.meta?.title || page.title,
1394
- description: page.meta?.description,
1395
- robots: {
1396
- index: !page.meta?.noindex,
1397
- follow: !page.meta?.nofollow,
1398
- },
1399
- }
1400
- }
1401
- ```
1402
-
1403
- ### Dynamic Sitemap
546
+ ## Advanced Configuration
1404
547
 
1405
- Filter out pages marked as excluded in your `sitemap.ts`:
548
+ ### Plugin Options
1406
549
 
1407
- ```typescript
1408
- // app/sitemap.ts
1409
- import type { MetadataRoute } from 'next'
1410
- import { getPayload } from 'payload'
1411
- import config from '@payload-config'
1412
-
1413
- export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
1414
- const baseUrl = 'https://yoursite.com'
1415
- const payload = await getPayload({ config })
1416
-
1417
- const { docs: pages } = await payload.find({
1418
- collection: 'pages',
1419
- limit: 1000,
1420
- where: {
1421
- or: [
1422
- { 'meta.excludeFromSitemap': { equals: false } },
1423
- { 'meta.excludeFromSitemap': { exists: false } },
1424
- ],
1425
- },
1426
- select: {
1427
- slug: true,
1428
- updatedAt: true,
1429
- },
1430
- })
1431
-
1432
- return pages.map((page) => ({
1433
- url: `${baseUrl}/${page.slug}`,
1434
- lastModified: new Date(page.updatedAt),
1435
- }))
1436
- }
1437
- ```
1438
-
1439
- </details>
1440
-
1441
- ---
1442
-
1443
- <details>
1444
- <summary><strong>Plugin Options</strong> — Collection config, access control</summary>
550
+ | Option | Default | Description |
551
+ |--------|---------|-------------|
552
+ | `pagesCollection` | `'pages'` | Collection slug to use for pages |
553
+ | `autoGenerateCollection` | `true` | Create the collection if it doesn't exist, or add Puck fields to existing |
554
+ | `enableEndpoints` | `true` | Register API endpoints at `/api/puck/:collection` for the editor |
555
+ | `enableAdminView` | `true` | Register the Puck editor view in Payload admin |
556
+ | `adminViewPath` | `'/puck-editor'` | Path for the editor (full path: `/admin/puck-editor/:collection/:id`) |
557
+ | `pageTreeIntegration` | auto-detect | Integration with `@delmaredigital/payload-page-tree` |
558
+ | `layouts` | `undefined` | Layout definitions for page templates |
1445
559
 
1446
560
  ```typescript
1447
561
  createPuckPlugin({
1448
- // Collection slug for pages (default: 'pages')
1449
562
  pagesCollection: 'pages',
1450
-
1451
- // Auto-generate the Pages collection (default: true)
1452
563
  autoGenerateCollection: true,
564
+ enableEndpoints: true,
565
+ enableAdminView: true,
566
+ adminViewPath: '/puck-editor',
567
+ pageTreeIntegration: undefined, // auto-detects
1453
568
 
1454
- // Override collection config
569
+ // Collection overrides (merged with generated collection)
1455
570
  collectionOverrides: {
1456
571
  admin: {
1457
572
  defaultColumns: ['title', 'slug', 'updatedAt'],
1458
573
  },
1459
574
  },
1460
575
 
1461
- // Custom access control
576
+ // Access control
1462
577
  access: {
1463
578
  read: () => true,
1464
579
  create: ({ req }) => !!req.user,
@@ -1468,197 +583,61 @@ createPuckPlugin({
1468
583
  })
1469
584
  ```
1470
585
 
1471
- </details>
586
+ ### Custom API Routes (Advanced)
1472
587
 
1473
- ---
1474
-
1475
- <details>
1476
- <summary><strong>Hybrid Integration</strong> — Add Puck to existing collections with legacy blocks</summary>
1477
-
1478
- If you have an existing Pages collection with legacy Payload blocks, you can add Puck support without replacing your collection.
1479
-
1480
- ### Automatic (Recommended)
1481
-
1482
- If you already have a `pages` collection defined, the plugin automatically adds only the Puck-specific fields that don't already exist:
1483
-
1484
- ```typescript
1485
- // payload.config.ts
1486
- import { buildConfig } from 'payload'
1487
- import { createPuckPlugin } from '@delmaredigital/payload-puck/plugin'
1488
-
1489
- export default buildConfig({
1490
- collections: [
1491
- {
1492
- slug: 'pages',
1493
- fields: [
1494
- { name: 'title', type: 'text', required: true },
1495
- { name: 'slug', type: 'text', required: true },
1496
- { name: 'layout', type: 'blocks', blocks: [HeroBlock, CTABlock] },
1497
- ],
1498
- },
1499
- ],
1500
- plugins: [
1501
- createPuckPlugin({ pagesCollection: 'pages' }),
1502
- ],
1503
- })
1504
- ```
1505
-
1506
- The plugin adds: `puckData`, `editorVersion`, `pageLayout`, `meta` (SEO fields), and the "Edit with Puck" button.
1507
-
1508
- **Smart detection:** The `editorVersion` field automatically detects whether existing pages use legacy blocks or Puck data. Pages with legacy blocks are marked `'legacy'`, pages with Puck content are marked `'puck'`, and new empty pages use the configured default. This prevents migrations from incorrectly overwriting existing content.
1509
-
1510
- ### Manual with `getPuckFields()`
1511
-
1512
- For full control, disable auto-generation and use `getPuckFields()`:
1513
-
1514
- ```typescript
1515
- // collections/Pages.ts
1516
- import type { CollectionConfig } from 'payload'
1517
- import { getPuckFields } from '@delmaredigital/payload-puck'
1518
-
1519
- export const Pages: CollectionConfig = {
1520
- slug: 'pages',
1521
- versions: { drafts: true },
1522
- fields: [
1523
- { name: 'title', type: 'text', required: true },
1524
- { name: 'slug', type: 'text', required: true },
1525
- { name: 'layout', type: 'blocks', blocks: [HeroBlock, CTABlock] },
1526
-
1527
- ...getPuckFields({
1528
- includeSEO: false,
1529
- includeConversion: true,
1530
- // Custom conversion types (optional - defaults to standard types)
1531
- conversionTypeOptions: [
1532
- { label: 'Registration', value: 'registration' },
1533
- { label: 'Donation', value: 'donation' },
1534
- { label: 'Course Start', value: 'course_start' },
1535
- { label: 'Custom', value: 'custom' },
1536
- ],
1537
- includeEditorVersion: true,
1538
- includePageLayout: true,
1539
- includeIsHomepage: false,
1540
- // Custom layouts (only value/label needed for the field)
1541
- layouts: [
1542
- { value: 'default', label: 'Default' },
1543
- { value: 'landing', label: 'Landing' },
1544
- ],
1545
- }),
1546
- ],
1547
- }
1548
- ```
588
+ If you need custom API route handling beyond the built-in endpoints, you can disable automatic endpoints and create your own:
1549
589
 
1550
590
  ```typescript
1551
591
  // payload.config.ts
1552
592
  createPuckPlugin({
1553
- pagesCollection: 'pages',
1554
- autoGenerateCollection: false,
593
+ enableEndpoints: false, // Disable built-in endpoints
1555
594
  })
1556
595
  ```
1557
596
 
1558
- ### Individual Field Imports
597
+ Then create custom routes using the provided factories:
1559
598
 
1560
599
  ```typescript
1561
- import {
1562
- puckDataField,
1563
- editorVersionField,
1564
- createPageLayoutField,
1565
- seoFieldGroup,
1566
- conversionFieldGroup,
1567
- } from '@delmaredigital/payload-puck'
1568
-
1569
- const Pages: CollectionConfig = {
1570
- slug: 'pages',
1571
- fields: [
1572
- puckDataField,
1573
- editorVersionField,
1574
- createPageLayoutField(myCustomLayouts),
1575
- ],
1576
- }
1577
- ```
1578
-
1579
- ### Rendering Hybrid Pages
1580
-
1581
- **Option A: Using `HybridPageRenderer` (Recommended)**
1582
-
1583
- The `HybridPageRenderer` component handles the branching logic for you:
1584
-
1585
- ```typescript
1586
- // app/(frontend)/[...slug]/page.tsx
1587
- import { HybridPageRenderer } from '@delmaredigital/payload-puck/render'
1588
- import { puckConfig } from '@/puck/config'
1589
- import { siteLayouts } from '@/lib/puck-layouts'
1590
- import { LegacyBlockRenderer } from '@/components/LegacyBlockRenderer'
1591
-
1592
- export default async function Page({ params }) {
1593
- const page = await getPage(params.slug)
1594
-
1595
- return (
1596
- <HybridPageRenderer
1597
- page={page}
1598
- config={puckConfig}
1599
- layouts={siteLayouts}
1600
- legacyRenderer={(blocks) => <LegacyBlockRenderer blocks={blocks} />}
1601
- />
1602
- )
1603
- }
1604
- ```
1605
-
1606
- **Option B: Manual Branching**
1607
-
1608
- For more control, handle the branching yourself:
1609
-
1610
- ```typescript
1611
- // app/(frontend)/[...slug]/page.tsx
1612
- import { PageRenderer } from '@delmaredigital/payload-puck/render'
1613
- import { puckConfig } from '@/puck/config'
1614
- import { siteLayouts } from '@/lib/puck-layouts'
1615
- import { LegacyBlockRenderer } from '@/components/LegacyBlockRenderer'
1616
-
1617
- export default async function Page({ params }) {
1618
- const page = await getPage(params.slug)
1619
-
1620
- if (page.editorVersion === 'puck' && page.puckData) {
1621
- return (
1622
- <PageRenderer
1623
- config={puckConfig}
1624
- data={page.puckData}
1625
- layouts={siteLayouts}
1626
- />
1627
- )
1628
- }
600
+ // app/api/puck/[collection]/route.ts
601
+ import { createPuckApiRoutes } from '@delmaredigital/payload-puck/api'
602
+ import { getPayload } from 'payload'
603
+ import config from '@payload-config'
604
+ import { headers } from 'next/headers'
1629
605
 
1630
- return <LegacyBlockRenderer blocks={page.layout} />
1631
- }
606
+ export const { GET, POST } = createPuckApiRoutes({
607
+ payloadConfig: config,
608
+ auth: {
609
+ authenticate: async (request) => {
610
+ const payload = await getPayload({ config })
611
+ const { user } = await payload.auth({ headers: await headers() })
612
+ if (!user) return { authenticated: false }
613
+ return { authenticated: true, user: { id: user.id } }
614
+ },
615
+ },
616
+ })
1632
617
  ```
1633
618
 
1634
- ### Available Field Exports
1635
-
1636
- | Export | Description |
1637
- |--------|-------------|
1638
- | `getPuckFields(options)` | Returns array of Puck fields based on options |
1639
- | `puckDataField` | JSON field for Puck editor data (hidden) |
1640
- | `editorVersionField` | Select field: 'legacy' \| 'puck' (auto-detects based on content) |
1641
- | `createEditorVersionField(default, sidebar, legacyBlocksFieldName)` | Factory for custom editor version field |
1642
- | `pageLayoutField` | Layout selector with DEFAULT_LAYOUTS |
1643
- | `createPageLayoutField(layouts, sidebar)` | Factory for custom layout options |
1644
- | `isHomepageField` | Checkbox for homepage designation |
1645
- | `seoFieldGroup` | Group named `meta` with title, description, image, noindex, etc. |
1646
- | `conversionFieldGroup` | Group for conversion tracking analytics (default types) |
1647
- | `createConversionFieldGroup(types, sidebar)` | Factory for custom conversion types |
1648
- | `DEFAULT_CONVERSION_TYPES` | Default conversion types array |
1649
- | `generatePuckEditField(slug, config)` | Creates the "Edit with Puck" UI button |
1650
-
1651
- ### Available Render Exports
1652
-
1653
- | Export | Description |
1654
- |--------|-------------|
1655
- | `PageRenderer` | Renders Puck data with layout support |
1656
- | `HybridPageRenderer` | Renders either Puck or legacy pages based on `editorVersion` |
619
+ ---
1657
620
 
1658
- </details>
621
+ ## Export Reference
622
+
623
+ | Export Path | Description |
624
+ |-------------|-------------|
625
+ | `@delmaredigital/payload-puck` | Plugin creation, field utilities |
626
+ | `@delmaredigital/payload-puck/plugin` | `createPuckPlugin` |
627
+ | `@delmaredigital/payload-puck/config` | `baseConfig`, `createConfig()`, `extendConfig()` |
628
+ | `@delmaredigital/payload-puck/config/editor` | `editorConfig` for editing |
629
+ | `@delmaredigital/payload-puck/client` | `PuckConfigProvider`, `usePuckConfig`, client components |
630
+ | `@delmaredigital/payload-puck/rsc` | `PuckEditorView` for Payload admin views |
631
+ | `@delmaredigital/payload-puck/render` | `PageRenderer`, `HybridPageRenderer` |
632
+ | `@delmaredigital/payload-puck/fields` | Custom Puck fields and CSS helpers |
633
+ | `@delmaredigital/payload-puck/components` | Component configs for custom configurations |
634
+ | `@delmaredigital/payload-puck/theme` | `ThemeProvider`, theme utilities |
635
+ | `@delmaredigital/payload-puck/layouts` | Layout definitions, `LayoutWrapper` |
636
+ | `@delmaredigital/payload-puck/api` | API route factories (for custom implementations) |
637
+ | `@delmaredigital/payload-puck/admin/client` | `EditWithPuckButton`, `EditWithPuckCell` |
1659
638
 
1660
639
  ---
1661
640
 
1662
641
  ## License
1663
642
 
1664
- MIT
643
+ MIT