@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.
- package/README.md +349 -1370
- package/dist/admin/EditWithPuckButton.d.ts +74 -0
- package/dist/admin/EditWithPuckButton.d.ts.map +1 -0
- package/dist/admin/EditWithPuckButton.js +114 -0
- package/dist/admin/EditWithPuckButton.js.map +1 -0
- package/dist/admin/EditWithPuckCell.d.ts +43 -0
- package/dist/admin/EditWithPuckCell.d.ts.map +1 -0
- package/dist/admin/EditWithPuckCell.js +66 -0
- package/dist/admin/EditWithPuckCell.js.map +1 -0
- package/dist/admin/PuckEditorView.d.ts +85 -0
- package/dist/admin/PuckEditorView.d.ts.map +1 -0
- package/dist/admin/PuckEditorView.js +135 -0
- package/dist/admin/PuckEditorView.js.map +1 -0
- package/dist/admin/client.d.ts +8 -104
- package/dist/admin/client.d.ts.map +1 -0
- package/dist/admin/client.js +14 -176
- package/dist/admin/client.js.map +1 -0
- package/dist/admin/generateAdminComponents.d.ts +51 -0
- package/dist/admin/generateAdminComponents.d.ts.map +1 -0
- package/dist/admin/generateAdminComponents.js +42 -0
- package/dist/admin/generateAdminComponents.js.map +1 -0
- package/dist/admin/index.d.ts +14 -150
- package/dist/admin/index.d.ts.map +1 -0
- package/dist/admin/index.js +17 -30
- package/dist/admin/index.js.map +1 -0
- package/dist/api/createPuckApiRoutes.d.ts +31 -0
- package/dist/api/createPuckApiRoutes.d.ts.map +1 -0
- package/dist/api/createPuckApiRoutes.js +193 -0
- package/dist/api/createPuckApiRoutes.js.map +1 -0
- package/dist/api/createPuckApiRoutesVersions.d.ts +28 -0
- package/dist/api/createPuckApiRoutesVersions.d.ts.map +1 -0
- package/dist/api/createPuckApiRoutesVersions.js +144 -0
- package/dist/api/createPuckApiRoutesVersions.js.map +1 -0
- package/dist/api/createPuckApiRoutesWithId.d.ts +34 -0
- package/dist/api/createPuckApiRoutesWithId.d.ts.map +1 -0
- package/dist/api/createPuckApiRoutesWithId.js +251 -0
- package/dist/api/createPuckApiRoutesWithId.js.map +1 -0
- package/dist/api/index.d.ts +11 -431
- package/dist/api/index.d.ts.map +1 -0
- package/dist/api/index.js +40 -587
- package/dist/api/index.js.map +1 -0
- package/dist/api/types.d.ts +302 -0
- package/dist/api/types.d.ts.map +1 -0
- package/dist/api/types.js +2 -0
- package/dist/api/types.js.map +1 -0
- package/dist/api/utils/mapRootProps.d.ts +76 -0
- package/dist/api/utils/mapRootProps.d.ts.map +1 -0
- package/dist/api/utils/mapRootProps.js +169 -0
- package/dist/api/utils/mapRootProps.js.map +1 -0
- package/dist/collections/Templates.d.ts +9 -0
- package/dist/collections/Templates.d.ts.map +1 -0
- package/dist/collections/Templates.js +62 -0
- package/dist/collections/Templates.js.map +1 -0
- package/dist/components/AccordionClient.d.ts +20 -0
- package/dist/components/AccordionClient.d.ts.map +1 -0
- package/dist/components/AccordionClient.js +67 -0
- package/dist/components/AccordionClient.js.map +1 -0
- package/dist/components/AnimatedWrapper.d.ts +33 -0
- package/dist/components/AnimatedWrapper.d.ts.map +1 -0
- package/dist/components/AnimatedWrapper.js +61 -0
- package/dist/components/AnimatedWrapper.js.map +1 -0
- package/dist/components/exports.d.ts +54 -0
- package/dist/components/exports.d.ts.map +1 -0
- package/dist/components/exports.js +71 -0
- package/dist/components/exports.js.map +1 -0
- package/dist/components/index.d.ts +8 -216
- package/dist/components/index.d.ts.map +1 -0
- package/dist/components/index.js +15 -9262
- package/dist/components/index.js.map +1 -0
- package/dist/components/interactive/Accordion.d.ts +28 -0
- package/dist/components/interactive/Accordion.d.ts.map +1 -0
- package/dist/components/interactive/Accordion.js +159 -0
- package/dist/components/interactive/Accordion.js.map +1 -0
- package/dist/components/interactive/Accordion.server.d.ts +29 -0
- package/dist/components/interactive/Accordion.server.d.ts.map +1 -0
- package/dist/components/interactive/Accordion.server.js +30 -0
- package/dist/components/interactive/Accordion.server.js.map +1 -0
- package/dist/components/interactive/Button.d.ts +26 -0
- package/dist/components/interactive/Button.d.ts.map +1 -0
- package/dist/components/interactive/Button.js +133 -0
- package/dist/components/interactive/Button.js.map +1 -0
- package/dist/components/interactive/Button.server.d.ts +28 -0
- package/dist/components/interactive/Button.server.d.ts.map +1 -0
- package/dist/components/interactive/Button.server.js +96 -0
- package/dist/components/interactive/Button.server.js.map +1 -0
- package/dist/components/interactive/Card.d.ts +27 -0
- package/dist/components/interactive/Card.d.ts.map +1 -0
- package/dist/components/interactive/Card.js +128 -0
- package/dist/components/interactive/Card.js.map +1 -0
- package/dist/components/interactive/Card.server.d.ts +29 -0
- package/dist/components/interactive/Card.server.d.ts.map +1 -0
- package/dist/components/interactive/Card.server.js +77 -0
- package/dist/components/interactive/Card.server.js.map +1 -0
- package/dist/components/interactive/Divider.d.ts +18 -0
- package/dist/components/interactive/Divider.d.ts.map +1 -0
- package/dist/components/interactive/Divider.js +68 -0
- package/dist/components/interactive/Divider.js.map +1 -0
- package/dist/components/interactive/Divider.server.d.ts +20 -0
- package/dist/components/interactive/Divider.server.d.ts.map +1 -0
- package/dist/components/interactive/Divider.server.js +50 -0
- package/dist/components/interactive/Divider.server.js.map +1 -0
- package/dist/components/interactive/index.d.ts +10 -0
- package/dist/components/interactive/index.d.ts.map +1 -0
- package/dist/components/interactive/index.js +10 -0
- package/dist/components/interactive/index.js.map +1 -0
- package/dist/components/layout/Container.d.ts +29 -0
- package/dist/components/layout/Container.d.ts.map +1 -0
- package/dist/components/layout/Container.js +166 -0
- package/dist/components/layout/Container.js.map +1 -0
- package/dist/components/layout/Container.server.d.ts +32 -0
- package/dist/components/layout/Container.server.d.ts.map +1 -0
- package/dist/components/layout/Container.server.js +105 -0
- package/dist/components/layout/Container.server.js.map +1 -0
- package/dist/components/layout/Flex.d.ts +36 -0
- package/dist/components/layout/Flex.d.ts.map +1 -0
- package/dist/components/layout/Flex.js +183 -0
- package/dist/components/layout/Flex.js.map +1 -0
- package/dist/components/layout/Flex.server.d.ts +36 -0
- package/dist/components/layout/Flex.server.d.ts.map +1 -0
- package/dist/components/layout/Flex.server.js +97 -0
- package/dist/components/layout/Flex.server.js.map +1 -0
- package/dist/components/layout/Grid.d.ts +31 -0
- package/dist/components/layout/Grid.d.ts.map +1 -0
- package/dist/components/layout/Grid.js +164 -0
- package/dist/components/layout/Grid.js.map +1 -0
- package/dist/components/layout/Grid.server.d.ts +32 -0
- package/dist/components/layout/Grid.server.d.ts.map +1 -0
- package/dist/components/layout/Grid.server.js +92 -0
- package/dist/components/layout/Grid.server.js.map +1 -0
- package/dist/components/layout/Section.d.ts +35 -0
- package/dist/components/layout/Section.d.ts.map +1 -0
- package/dist/components/layout/Section.js +212 -0
- package/dist/components/layout/Section.js.map +1 -0
- package/dist/components/layout/Section.server.d.ts +35 -0
- package/dist/components/layout/Section.server.d.ts.map +1 -0
- package/dist/components/layout/Section.server.js +144 -0
- package/dist/components/layout/Section.server.js.map +1 -0
- package/dist/components/layout/Spacer.d.ts +18 -0
- package/dist/components/layout/Spacer.d.ts.map +1 -0
- package/dist/components/layout/Spacer.js +99 -0
- package/dist/components/layout/Spacer.js.map +1 -0
- package/dist/components/layout/Spacer.server.d.ts +21 -0
- package/dist/components/layout/Spacer.server.d.ts.map +1 -0
- package/dist/components/layout/Spacer.server.js +61 -0
- package/dist/components/layout/Spacer.server.js.map +1 -0
- package/dist/components/layout/Template.d.ts +35 -0
- package/dist/components/layout/Template.d.ts.map +1 -0
- package/dist/components/layout/Template.js +124 -0
- package/dist/components/layout/Template.js.map +1 -0
- package/dist/components/layout/Template.server.d.ts +32 -0
- package/dist/components/layout/Template.server.d.ts.map +1 -0
- package/dist/components/layout/Template.server.js +75 -0
- package/dist/components/layout/Template.server.js.map +1 -0
- package/dist/components/layout/index.d.ts +14 -0
- package/dist/components/layout/index.d.ts.map +1 -0
- package/dist/components/layout/index.js +13 -0
- package/dist/components/layout/index.js.map +1 -0
- package/dist/components/media/Image.d.ts +30 -0
- package/dist/components/media/Image.d.ts.map +1 -0
- package/dist/components/media/Image.js +123 -0
- package/dist/components/media/Image.js.map +1 -0
- package/dist/components/media/Image.server.d.ts +28 -0
- package/dist/components/media/Image.server.d.ts.map +1 -0
- package/dist/components/media/Image.server.js +76 -0
- package/dist/components/media/Image.server.js.map +1 -0
- package/dist/components/media/index.d.ts +7 -0
- package/dist/components/media/index.d.ts.map +1 -0
- package/dist/components/media/index.js +7 -0
- package/dist/components/media/index.js.map +1 -0
- package/dist/components/typography/Heading.d.ts +21 -0
- package/dist/components/typography/Heading.d.ts.map +1 -0
- package/dist/components/typography/Heading.js +71 -0
- package/dist/components/typography/Heading.js.map +1 -0
- package/dist/components/typography/Heading.server.d.ts +21 -0
- package/dist/components/typography/Heading.server.d.ts.map +1 -0
- package/dist/components/typography/Heading.server.js +49 -0
- package/dist/components/typography/Heading.server.js.map +1 -0
- package/dist/components/typography/RichText.d.ts +20 -0
- package/dist/components/typography/RichText.d.ts.map +1 -0
- package/dist/components/typography/RichText.editor.d.ts +11 -0
- package/dist/components/typography/RichText.editor.d.ts.map +1 -0
- package/dist/components/typography/RichText.editor.js +67 -0
- package/dist/components/typography/RichText.editor.js.map +1 -0
- package/dist/components/typography/RichText.js +73 -0
- package/dist/components/typography/RichText.js.map +1 -0
- package/dist/components/typography/RichText.server.d.ts +22 -0
- package/dist/components/typography/RichText.server.d.ts.map +1 -0
- package/dist/components/typography/RichText.server.js +52 -0
- package/dist/components/typography/RichText.server.js.map +1 -0
- package/dist/components/typography/Text.d.ts +20 -0
- package/dist/components/typography/Text.d.ts.map +1 -0
- package/dist/components/typography/Text.js +61 -0
- package/dist/components/typography/Text.js.map +1 -0
- package/dist/components/typography/Text.server.d.ts +21 -0
- package/dist/components/typography/Text.server.d.ts.map +1 -0
- package/dist/components/typography/Text.server.js +39 -0
- package/dist/components/typography/Text.server.js.map +1 -0
- package/dist/components/typography/index.d.ts +10 -0
- package/dist/components/typography/index.d.ts.map +1 -0
- package/dist/components/typography/index.js +10 -0
- package/dist/components/typography/index.js.map +1 -0
- package/dist/config/config.editor.d.ts +15 -56
- package/dist/config/config.editor.d.ts.map +1 -0
- package/dist/config/config.editor.js +125 -9462
- package/dist/config/config.editor.js.map +1 -0
- package/dist/config/index.d.ts +7 -33
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +110 -2119
- package/dist/config/index.js.map +1 -0
- package/dist/config/merge.d.ts +23 -0
- package/dist/config/merge.d.ts.map +1 -0
- package/dist/config/merge.js +80 -0
- package/dist/config/merge.js.map +1 -0
- package/dist/config/presets.d.ts +342 -0
- package/dist/config/presets.d.ts.map +1 -0
- package/dist/config/presets.js +247 -0
- package/dist/config/presets.js.map +1 -0
- package/dist/editor/PuckEditor.client.d.ts +131 -0
- package/dist/editor/PuckEditor.client.d.ts.map +1 -0
- package/dist/editor/PuckEditor.client.js +42 -0
- package/dist/editor/PuckEditor.client.js.map +1 -0
- package/dist/editor/PuckEditorCore.client.d.ts +141 -0
- package/dist/editor/PuckEditorCore.client.d.ts.map +1 -0
- package/dist/editor/PuckEditorCore.client.js +306 -0
- package/dist/editor/PuckEditorCore.client.js.map +1 -0
- package/dist/editor/components/HeaderActions.d.ts +109 -0
- package/dist/editor/components/HeaderActions.d.ts.map +1 -0
- package/dist/editor/components/HeaderActions.js +254 -0
- package/dist/editor/components/HeaderActions.js.map +1 -0
- package/dist/editor/components/IframeWrapper.d.ts +77 -0
- package/dist/editor/components/IframeWrapper.d.ts.map +1 -0
- package/dist/editor/components/IframeWrapper.js +257 -0
- package/dist/editor/components/IframeWrapper.js.map +1 -0
- package/dist/editor/components/LoadingState.d.ts +14 -0
- package/dist/editor/components/LoadingState.d.ts.map +1 -0
- package/dist/editor/components/LoadingState.js +12 -0
- package/dist/editor/components/LoadingState.js.map +1 -0
- package/dist/editor/components/PreviewModal.d.ts +54 -0
- package/dist/editor/components/PreviewModal.d.ts.map +1 -0
- package/dist/editor/components/PreviewModal.js +298 -0
- package/dist/editor/components/PreviewModal.js.map +1 -0
- package/dist/editor/components/VersionHistory.d.ts +44 -0
- package/dist/editor/components/VersionHistory.d.ts.map +1 -0
- package/dist/editor/components/VersionHistory.js +308 -0
- package/dist/editor/components/VersionHistory.js.map +1 -0
- package/dist/editor/hooks/useUnsavedChanges.d.ts +27 -0
- package/dist/editor/hooks/useUnsavedChanges.d.ts.map +1 -0
- package/dist/editor/hooks/useUnsavedChanges.js +55 -0
- package/dist/editor/hooks/useUnsavedChanges.js.map +1 -0
- package/dist/editor/index.d.ts +16 -756
- package/dist/editor/index.d.ts.map +1 -0
- package/dist/editor/index.js +49 -4625
- package/dist/editor/index.js.map +1 -0
- package/dist/editor/plugins/index.d.ts +12 -0
- package/dist/editor/plugins/index.d.ts.map +1 -0
- package/dist/editor/plugins/index.js +12 -0
- package/dist/editor/plugins/index.js.map +1 -0
- package/dist/endpoints/index.d.ts +46 -0
- package/dist/endpoints/index.d.ts.map +1 -0
- package/dist/endpoints/index.js +204 -0
- package/dist/endpoints/index.js.map +1 -0
- package/dist/exports/client.d.ts +19 -0
- package/dist/exports/client.d.ts.map +1 -0
- package/dist/exports/client.js +21 -0
- package/dist/exports/client.js.map +1 -0
- package/dist/exports/rsc.d.ts +19 -0
- package/dist/exports/rsc.d.ts.map +1 -0
- package/dist/exports/rsc.js +19 -0
- package/dist/exports/rsc.js.map +1 -0
- package/dist/fields/AlignmentField.d.ts +36 -0
- package/dist/fields/AlignmentField.d.ts.map +1 -0
- package/dist/fields/AlignmentField.js +120 -0
- package/dist/fields/AlignmentField.js.map +1 -0
- package/dist/fields/AnimationField.d.ts +44 -0
- package/dist/fields/AnimationField.d.ts.map +1 -0
- package/dist/fields/AnimationField.js +329 -0
- package/dist/fields/AnimationField.js.map +1 -0
- package/dist/fields/BackgroundField.d.ts +40 -0
- package/dist/fields/BackgroundField.d.ts.map +1 -0
- package/dist/fields/BackgroundField.js +413 -0
- package/dist/fields/BackgroundField.js.map +1 -0
- package/dist/fields/BorderField.d.ts +29 -0
- package/dist/fields/BorderField.d.ts.map +1 -0
- package/dist/fields/BorderField.js +264 -0
- package/dist/fields/BorderField.js.map +1 -0
- package/dist/fields/ColorPickerField.d.ts +43 -0
- package/dist/fields/ColorPickerField.d.ts.map +1 -0
- package/dist/fields/ColorPickerField.js +285 -0
- package/dist/fields/ColorPickerField.js.map +1 -0
- package/dist/fields/DimensionsField.d.ts +43 -0
- package/dist/fields/DimensionsField.d.ts.map +1 -0
- package/dist/fields/DimensionsField.js +532 -0
- package/dist/fields/DimensionsField.js.map +1 -0
- package/dist/fields/FlexAlignmentField.d.ts +61 -0
- package/dist/fields/FlexAlignmentField.d.ts.map +1 -0
- package/dist/fields/FlexAlignmentField.js +166 -0
- package/dist/fields/FlexAlignmentField.js.map +1 -0
- package/dist/fields/FolderPickerField.d.ts +17 -0
- package/dist/fields/FolderPickerField.d.ts.map +1 -0
- package/dist/fields/FolderPickerField.js +282 -0
- package/dist/fields/FolderPickerField.js.map +1 -0
- package/dist/fields/GradientEditor.d.ts +22 -0
- package/dist/fields/GradientEditor.d.ts.map +1 -0
- package/dist/fields/GradientEditor.js +322 -0
- package/dist/fields/GradientEditor.js.map +1 -0
- package/dist/fields/LockedField.d.ts +67 -0
- package/dist/fields/LockedField.d.ts.map +1 -0
- package/dist/fields/LockedField.js +170 -0
- package/dist/fields/LockedField.js.map +1 -0
- package/dist/fields/MarginField.d.ts +31 -0
- package/dist/fields/MarginField.d.ts.map +1 -0
- package/dist/fields/MarginField.js +233 -0
- package/dist/fields/MarginField.js.map +1 -0
- package/dist/fields/MediaField.d.ts +33 -0
- package/dist/fields/MediaField.d.ts.map +1 -0
- package/dist/fields/MediaField.js +677 -0
- package/dist/fields/MediaField.js.map +1 -0
- package/dist/fields/PaddingField.d.ts +29 -0
- package/dist/fields/PaddingField.d.ts.map +1 -0
- package/dist/fields/PaddingField.js +232 -0
- package/dist/fields/PaddingField.js.map +1 -0
- package/dist/fields/PageSegmentField.d.ts +17 -0
- package/dist/fields/PageSegmentField.d.ts.map +1 -0
- package/dist/fields/PageSegmentField.js +92 -0
- package/dist/fields/PageSegmentField.js.map +1 -0
- package/dist/fields/ResetField.d.ts +27 -0
- package/dist/fields/ResetField.d.ts.map +1 -0
- package/dist/fields/ResetField.js +122 -0
- package/dist/fields/ResetField.js.map +1 -0
- package/dist/fields/ResponsiveField.d.ts +38 -0
- package/dist/fields/ResponsiveField.d.ts.map +1 -0
- package/dist/fields/ResponsiveField.js +275 -0
- package/dist/fields/ResponsiveField.js.map +1 -0
- package/dist/fields/ResponsiveVisibilityField.d.ts +34 -0
- package/dist/fields/ResponsiveVisibilityField.d.ts.map +1 -0
- package/dist/fields/ResponsiveVisibilityField.js +145 -0
- package/dist/fields/ResponsiveVisibilityField.js.map +1 -0
- package/dist/fields/SizeField.d.ts +54 -0
- package/dist/fields/SizeField.d.ts.map +1 -0
- package/dist/fields/SizeField.js +255 -0
- package/dist/fields/SizeField.js.map +1 -0
- package/dist/fields/SlugPreviewField.d.ts +16 -0
- package/dist/fields/SlugPreviewField.d.ts.map +1 -0
- package/dist/fields/SlugPreviewField.js +49 -0
- package/dist/fields/SlugPreviewField.js.map +1 -0
- package/dist/fields/TemplateField.d.ts +31 -0
- package/dist/fields/TemplateField.d.ts.map +1 -0
- package/dist/fields/TemplateField.js +428 -0
- package/dist/fields/TemplateField.js.map +1 -0
- package/dist/fields/TiptapField.d.ts +40 -0
- package/dist/fields/TiptapField.d.ts.map +1 -0
- package/dist/fields/TiptapField.js +857 -0
- package/dist/fields/TiptapField.js.map +1 -0
- package/dist/fields/TiptapModal.d.ts +10 -0
- package/dist/fields/TiptapModal.d.ts.map +1 -0
- package/dist/fields/TiptapModal.js +114 -0
- package/dist/fields/TiptapModal.js.map +1 -0
- package/dist/fields/TiptapModalField.d.ts +23 -0
- package/dist/fields/TiptapModalField.d.ts.map +1 -0
- package/dist/fields/TiptapModalField.js +55 -0
- package/dist/fields/TiptapModalField.js.map +1 -0
- package/dist/fields/TransformField.d.ts +31 -0
- package/dist/fields/TransformField.d.ts.map +1 -0
- package/dist/fields/TransformField.js +384 -0
- package/dist/fields/TransformField.js.map +1 -0
- package/dist/fields/VerticalAlignmentField.d.ts +35 -0
- package/dist/fields/VerticalAlignmentField.d.ts.map +1 -0
- package/dist/fields/VerticalAlignmentField.js +120 -0
- package/dist/fields/VerticalAlignmentField.js.map +1 -0
- package/dist/fields/WidthField.d.ts +28 -0
- package/dist/fields/WidthField.d.ts.map +1 -0
- package/dist/fields/WidthField.js +339 -0
- package/dist/fields/WidthField.js.map +1 -0
- package/dist/fields/index.d.ts +44 -559
- package/dist/fields/index.d.ts.map +1 -0
- package/dist/fields/index.js +91 -7704
- package/dist/fields/index.js.map +1 -0
- package/dist/fields/richtext-output.css +219 -0
- package/dist/{shared-X9UpCJKW.d.mts → fields/shared.d.ts} +111 -132
- package/dist/fields/shared.d.ts.map +1 -0
- package/dist/fields/shared.js +1542 -0
- package/dist/fields/shared.js.map +1 -0
- package/dist/fields/{index.css → tiptap-styles.css} +75 -166
- package/dist/hooks/index.d.ts +8 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/index.js +8 -0
- package/dist/hooks/index.js.map +1 -0
- package/dist/hooks/useResponsiveStyles.d.ts +51 -0
- package/dist/hooks/useResponsiveStyles.d.ts.map +1 -0
- package/dist/hooks/useResponsiveStyles.js +149 -0
- package/dist/hooks/useResponsiveStyles.js.map +1 -0
- package/dist/hooks/useScrollAnimation.d.ts +56 -0
- package/dist/hooks/useScrollAnimation.d.ts.map +1 -0
- package/dist/hooks/useScrollAnimation.js +116 -0
- package/dist/hooks/useScrollAnimation.js.map +1 -0
- package/dist/index.d.ts +66 -6
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +67 -568
- package/dist/index.js.map +1 -0
- package/dist/layouts/LayoutWrapper.d.ts +33 -0
- package/dist/layouts/LayoutWrapper.d.ts.map +1 -0
- package/dist/layouts/LayoutWrapper.js +112 -0
- package/dist/layouts/LayoutWrapper.js.map +1 -0
- package/dist/layouts/defaults.d.ts +40 -0
- package/dist/layouts/defaults.d.ts.map +1 -0
- package/dist/layouts/defaults.js +106 -0
- package/dist/layouts/defaults.js.map +1 -0
- package/dist/layouts/index.d.ts +27 -94
- package/dist/layouts/index.d.ts.map +1 -0
- package/dist/layouts/index.js +30 -393
- package/dist/layouts/index.js.map +1 -0
- package/dist/{types-D7D3rZ1J.d.ts → layouts/types.d.ts} +8 -11
- package/dist/layouts/types.d.ts.map +1 -0
- package/dist/layouts/types.js +7 -0
- package/dist/layouts/types.js.map +1 -0
- package/dist/layouts/utils.d.ts +42 -0
- package/dist/layouts/utils.d.ts.map +1 -0
- package/dist/layouts/utils.js +83 -0
- package/dist/layouts/utils.js.map +1 -0
- package/dist/plugin/collections/Pages.d.ts +8 -0
- package/dist/plugin/collections/Pages.d.ts.map +1 -0
- package/dist/plugin/collections/Pages.js +117 -0
- package/dist/plugin/collections/Pages.js.map +1 -0
- package/dist/plugin/fields/index.d.ts +153 -0
- package/dist/plugin/fields/index.d.ts.map +1 -0
- package/dist/plugin/fields/index.js +364 -0
- package/dist/plugin/fields/index.js.map +1 -0
- package/dist/plugin/fields/types.d.ts +108 -0
- package/dist/plugin/fields/types.d.ts.map +1 -0
- package/dist/plugin/fields/types.js +7 -0
- package/dist/plugin/fields/types.js.map +1 -0
- package/dist/plugin/index.d.ts +13 -255
- package/dist/plugin/index.d.ts.map +1 -0
- package/dist/plugin/index.js +276 -553
- package/dist/plugin/index.js.map +1 -0
- package/dist/render/HybridPageRenderer.d.ts +85 -0
- package/dist/render/HybridPageRenderer.d.ts.map +1 -0
- package/dist/render/HybridPageRenderer.js +29 -0
- package/dist/render/HybridPageRenderer.js.map +1 -0
- package/dist/render/PageRenderer.d.ts +51 -0
- package/dist/render/PageRenderer.d.ts.map +1 -0
- package/dist/render/PageRenderer.js +61 -0
- package/dist/render/PageRenderer.js.map +1 -0
- package/dist/render/PuckEditor.client.d.ts +66 -0
- package/dist/render/PuckEditor.client.d.ts.map +1 -0
- package/dist/render/PuckEditor.client.js +66 -0
- package/dist/render/PuckEditor.client.js.map +1 -0
- package/dist/render/index.d.ts +8 -106
- package/dist/render/index.d.ts.map +1 -0
- package/dist/render/index.js +10 -2253
- package/dist/render/index.js.map +1 -0
- package/dist/theme/context.d.ts +59 -0
- package/dist/theme/context.d.ts.map +1 -0
- package/dist/theme/context.js +73 -0
- package/dist/theme/context.js.map +1 -0
- package/dist/theme/defaults.d.ts +39 -0
- package/dist/theme/defaults.d.ts.map +1 -0
- package/dist/theme/defaults.js +72 -0
- package/dist/theme/defaults.js.map +1 -0
- package/dist/theme/example.d.ts +30 -0
- package/dist/theme/example.d.ts.map +1 -0
- package/dist/theme/example.js +89 -0
- package/dist/theme/example.js.map +1 -0
- package/dist/theme/index.d.ts +17 -140
- package/dist/theme/index.d.ts.map +1 -0
- package/dist/theme/index.js +34 -200
- package/dist/theme/index.js.map +1 -0
- package/dist/{types-_6MvjyKv.d.ts → theme/types.d.ts} +8 -9
- package/dist/theme/types.d.ts.map +1 -0
- package/dist/theme/types.js +9 -0
- package/dist/theme/types.js.map +1 -0
- package/dist/theme/utils.d.ts +30 -0
- package/dist/theme/utils.d.ts.map +1 -0
- package/dist/theme/utils.js +84 -0
- package/dist/theme/utils.js.map +1 -0
- package/dist/{index-CQu6SzDg.d.mts → types/index.d.ts} +120 -115
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +2 -0
- package/dist/types/index.js.map +1 -0
- package/dist/utils/index.d.ts +23 -257
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +56 -425
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/{index.d.mts → migration.d.ts} +16 -112
- package/dist/utils/migration.d.ts.map +1 -0
- package/dist/utils/migration.js +309 -0
- package/dist/utils/migration.js.map +1 -0
- package/dist/utils/validation.d.ts +89 -0
- package/dist/utils/validation.d.ts.map +1 -0
- package/dist/utils/validation.js +247 -0
- package/dist/utils/validation.js.map +1 -0
- package/dist/views/PuckConfigContext.d.ts +71 -0
- package/dist/views/PuckConfigContext.d.ts.map +1 -0
- package/dist/views/PuckConfigContext.js +45 -0
- package/dist/views/PuckConfigContext.js.map +1 -0
- package/dist/views/PuckEditorClient.d.ts +73 -0
- package/dist/views/PuckEditorClient.d.ts.map +1 -0
- package/dist/views/PuckEditorClient.js +130 -0
- package/dist/views/PuckEditorClient.js.map +1 -0
- package/dist/views/PuckEditorView.d.ts +19 -0
- package/dist/views/PuckEditorView.d.ts.map +1 -0
- package/dist/views/PuckEditorView.js +106 -0
- package/dist/views/PuckEditorView.js.map +1 -0
- package/dist/views/index.d.ts +10 -0
- package/dist/views/index.d.ts.map +1 -0
- package/dist/views/index.js +10 -0
- package/dist/views/index.js.map +1 -0
- package/package.json +51 -74
- package/dist/AccordionClient.d.mts +0 -24
- package/dist/AccordionClient.d.ts +0 -24
- package/dist/AccordionClient.js +0 -786
- package/dist/AccordionClient.mjs +0 -784
- package/dist/AnimatedWrapper.d.mts +0 -30
- package/dist/AnimatedWrapper.d.ts +0 -30
- package/dist/AnimatedWrapper.js +0 -379
- package/dist/AnimatedWrapper.mjs +0 -377
- package/dist/admin/client.d.mts +0 -108
- package/dist/admin/client.mjs +0 -173
- package/dist/admin/index.d.mts +0 -157
- package/dist/admin/index.mjs +0 -29
- package/dist/api/index.d.mts +0 -460
- package/dist/api/index.mjs +0 -578
- package/dist/components/index.css +0 -339
- package/dist/components/index.d.mts +0 -219
- package/dist/components/index.mjs +0 -9216
- package/dist/config/config.editor.css +0 -339
- package/dist/config/config.editor.d.mts +0 -153
- package/dist/config/config.editor.mjs +0 -9445
- package/dist/config/index.d.mts +0 -68
- package/dist/config/index.mjs +0 -2099
- package/dist/editor/index.d.mts +0 -784
- package/dist/editor/index.mjs +0 -4592
- package/dist/fields/index.d.mts +0 -600
- package/dist/fields/index.mjs +0 -7588
- package/dist/index-CoUQnyC3.d.ts +0 -327
- package/dist/index.d.mts +0 -6
- package/dist/index.mjs +0 -555
- package/dist/layouts/index.d.mts +0 -96
- package/dist/layouts/index.mjs +0 -378
- package/dist/plugin/index.d.mts +0 -289
- package/dist/plugin/index.mjs +0 -555
- package/dist/render/index.d.mts +0 -109
- package/dist/render/index.mjs +0 -2231
- package/dist/shared-X9UpCJKW.d.ts +0 -548
- package/dist/theme/index.d.mts +0 -155
- package/dist/theme/index.mjs +0 -186
- package/dist/types-D7D3rZ1J.d.mts +0 -116
- package/dist/types-_6MvjyKv.d.mts +0 -104
- package/dist/utils/index.mjs +0 -412
- package/dist/utils-DaRs9t0J.d.mts +0 -85
- package/dist/utils-gAvt0Vhw.d.ts +0 -85
- package/examples/README.md +0 -247
- package/examples/api/puck/pages/[id]/route.ts +0 -64
- package/examples/api/puck/pages/[id]/versions/route.ts +0 -47
- package/examples/api/puck/pages/route.ts +0 -45
- package/examples/app/(frontend)/page.tsx +0 -94
- package/examples/app/(manage)/layout.tsx +0 -31
- package/examples/app/[...slug]/page.tsx +0 -101
- package/examples/app/pages/[id]/edit/page.tsx +0 -148
- package/examples/components/CustomBanner.tsx +0 -368
- package/examples/config/custom-config.ts +0 -223
- package/examples/config/payload.config.example.ts +0 -64
- package/examples/lib/puck-layouts.ts +0 -258
- package/examples/lib/puck-theme.ts +0 -94
- 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
|
-
- [
|
|
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
|
-
|
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
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
|
-
|
|
72
|
+
### Step 2: Provide Puck Configuration
|
|
152
73
|
|
|
153
|
-
|
|
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/(
|
|
176
|
-
'
|
|
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
|
|
81
|
+
export default function RootLayout({ children }: { children: React.ReactNode }) {
|
|
182
82
|
return (
|
|
183
|
-
<
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
232
|
-
|
|
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:
|
|
117
|
+
where: slugPath
|
|
118
|
+
? { slug: { equals: slugPath } }
|
|
119
|
+
: { isHomepage: { equals: true } },
|
|
238
120
|
limit: 1,
|
|
239
121
|
})
|
|
240
122
|
|
|
241
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
162
|
+
### That's It!
|
|
267
163
|
|
|
268
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
286
|
-
|
|
181
|
+
**Tailwind v4:**
|
|
287
182
|
```css
|
|
288
183
|
@import "tailwindcss";
|
|
289
184
|
@plugin "@tailwindcss/typography";
|
|
290
185
|
```
|
|
291
186
|
|
|
292
|
-
**Tailwind v3
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
-
//
|
|
259
|
+
// PuckConfigProvider - use editorConfig
|
|
471
260
|
import { editorConfig } from '@delmaredigital/payload-puck/config/editor'
|
|
472
|
-
<
|
|
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
|
-
|
|
495
|
-
<summary><strong>Components</strong> — Layout, Typography, Media, Interactive</summary>
|
|
279
|
+
## Components
|
|
496
280
|
|
|
497
281
|
### Layout
|
|
498
282
|
|
|
499
|
-
| Component | Description |
|
|
500
|
-
|
|
501
|
-
| **Container** | Content wrapper with max-width and background
|
|
502
|
-
| **Flex** | Flexible box layout with direction and alignment |
|
|
503
|
-
| **Grid** | CSS Grid layout with responsive columns |
|
|
504
|
-
| **Section** |
|
|
505
|
-
| **Spacer** | Vertical/horizontal spacing element |
|
|
506
|
-
| **Template** |
|
|
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 |
|
|
511
|
-
|
|
512
|
-
| **Heading** | H1-H6 headings with size and alignment
|
|
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
|
-
|
|
521
|
-
|-----------|-------------|---------------------|
|
|
522
|
-
| **Image** | Responsive image with alt text and sizing | Visibility |
|
|
300
|
+
### Media & Interactive
|
|
523
301
|
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
|
527
|
-
|
|
528
|
-
| **
|
|
529
|
-
| **
|
|
530
|
-
| **
|
|
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
|
-
|
|
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
|
-
|
|
538
|
-
- **Padding** - Inner spacing per breakpoint
|
|
539
|
-
- **Margin** - Outer spacing per breakpoint
|
|
540
|
-
- **Visibility** - Show/hide components at specific breakpoints
|
|
317
|
+
---
|
|
541
318
|
|
|
542
|
-
|
|
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
|
-
|
|
321
|
+
All fields are imported from `@delmaredigital/payload-puck/fields`.
|
|
552
322
|
|
|
553
|
-
|
|
323
|
+
### Field Reference
|
|
554
324
|
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
570
|
-
<summary><strong>Configuration</strong> — Merging configs, Custom components</summary>
|
|
372
|
+
## Theming
|
|
571
373
|
|
|
572
|
-
|
|
374
|
+
Customize button styles, color presets, and focus rings:
|
|
573
375
|
|
|
574
376
|
```typescript
|
|
575
|
-
import {
|
|
576
|
-
import {
|
|
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
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
613
|
-
|
|
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
|
-
|
|
616
|
-
|
|
617
|
-
|
|
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
|
-
|
|
620
|
-
items: { title: string; content: string }[]
|
|
621
|
-
defaultTab: number
|
|
622
|
-
}
|
|
426
|
+
Pass layouts to the `PuckConfigProvider`:
|
|
623
427
|
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
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
|
-
|
|
648
|
-
// components/Tabs.tsx - Editor version with interactivity
|
|
649
|
-
'use client'
|
|
434
|
+
And use them with `PageRenderer`:
|
|
650
435
|
|
|
651
|
-
|
|
652
|
-
import {
|
|
436
|
+
```typescript
|
|
437
|
+
import { LayoutWrapper } from '@delmaredigital/payload-puck/layouts'
|
|
653
438
|
|
|
654
|
-
|
|
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
|
-
|
|
660
|
-
|
|
661
|
-
|
|
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
|
-
|
|
700
|
-
```tsx
|
|
701
|
-
// In your custom baseConfig
|
|
702
|
-
import { TabsConfig } from './components/Tabs.server'
|
|
446
|
+
---
|
|
703
447
|
|
|
704
|
-
|
|
705
|
-
import { TabsConfig } from './components/Tabs'
|
|
706
|
-
```
|
|
707
|
-
</details>
|
|
448
|
+
## Page-Tree Integration
|
|
708
449
|
|
|
709
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
722
|
-
|
|
723
|
-
|
|
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
|
-
|
|
741
|
-
// components/Card.tsx - Editor version with all fields
|
|
742
|
-
import type { ComponentConfig } from '@measured/puck'
|
|
460
|
+
### Configuration
|
|
743
461
|
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
462
|
+
```typescript
|
|
463
|
+
createPuckPlugin({
|
|
464
|
+
// Auto-detect (default)
|
|
465
|
+
pageTreeIntegration: undefined,
|
|
748
466
|
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
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
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
</div>
|
|
764
|
-
),
|
|
765
|
-
}
|
|
472
|
+
|
|
473
|
+
// Explicitly disable
|
|
474
|
+
pageTreeIntegration: false,
|
|
475
|
+
})
|
|
766
476
|
```
|
|
767
477
|
|
|
768
|
-
|
|
769
|
-
</details>
|
|
478
|
+
### Performance
|
|
770
479
|
|
|
771
|
-
|
|
480
|
+
Detection is instant - it reads the in-memory collection config, no database queries.
|
|
772
481
|
|
|
773
482
|
---
|
|
774
483
|
|
|
775
|
-
|
|
776
|
-
<summary><strong>Custom Fields</strong> — 19 field types with usage examples</summary>
|
|
484
|
+
## Hybrid Integration
|
|
777
485
|
|
|
778
|
-
|
|
486
|
+
Add Puck to existing collections with legacy blocks.
|
|
779
487
|
|
|
780
|
-
###
|
|
488
|
+
### Automatic (Recommended)
|
|
781
489
|
|
|
782
|
-
|
|
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
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
fields:
|
|
934
|
-
|
|
935
|
-
|
|
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
|
-
|
|
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
|
-
###
|
|
512
|
+
### Manual with `getPuckFields()`
|
|
1129
513
|
|
|
1130
514
|
```typescript
|
|
1131
|
-
import {
|
|
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
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
{
|
|
1163
|
-
{
|
|
1164
|
-
{
|
|
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
|
-
|
|
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
|
-
|
|
1210
|
-
import
|
|
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
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
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
|
-
|
|
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
|
-
|
|
548
|
+
### Plugin Options
|
|
1406
549
|
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
|
|
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
|
-
|
|
1554
|
-
autoGenerateCollection: false,
|
|
593
|
+
enableEndpoints: false, // Disable built-in endpoints
|
|
1555
594
|
})
|
|
1556
595
|
```
|
|
1557
596
|
|
|
1558
|
-
|
|
597
|
+
Then create custom routes using the provided factories:
|
|
1559
598
|
|
|
1560
599
|
```typescript
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|