@delmaredigital/payload-puck 0.2.0 → 0.3.1
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 +389 -1261
- 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,15 @@ 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)
|
|
15
|
+
- [Building Custom Components](#building-custom-components)
|
|
17
16
|
- [Theming](#theming)
|
|
18
17
|
- [Layouts](#layouts)
|
|
19
|
-
- [
|
|
20
|
-
- [SEO Fields](#seo-fields)
|
|
21
|
-
- [Plugin Options](#plugin-options)
|
|
18
|
+
- [Page-Tree Integration](#page-tree-integration)
|
|
22
19
|
- [Hybrid Integration](#hybrid-integration)
|
|
20
|
+
- [Advanced Configuration](#advanced-configuration)
|
|
23
21
|
- [License](#license)
|
|
24
22
|
|
|
25
23
|
---
|
|
@@ -32,65 +30,24 @@ A PayloadCMS plugin for integrating [Puck](https://puckeditor.com) visual page b
|
|
|
32
30
|
|------------|---------|---------|
|
|
33
31
|
| `@measured/puck` | >= 0.20.0 | Visual editor core |
|
|
34
32
|
| `payload` | >= 3.0.0 | CMS backend |
|
|
35
|
-
|
|
|
33
|
+
| `@payloadcms/next` | >= 3.0.0 | Payload Next.js integration |
|
|
34
|
+
| `next` | >= 14.0.0 | React framework |
|
|
36
35
|
| `react` | >= 18.0.0 | UI library |
|
|
37
36
|
| `@tailwindcss/typography` | >= 0.5.0 | RichText component styling |
|
|
38
37
|
|
|
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
38
|
### Install
|
|
42
39
|
|
|
43
40
|
```bash
|
|
44
41
|
pnpm add @delmaredigital/payload-puck @measured/puck
|
|
45
42
|
```
|
|
46
43
|
|
|
47
|
-
Or install from GitHub:
|
|
48
|
-
|
|
49
|
-
```bash
|
|
50
|
-
pnpm add github:delmaredigital/payload-puck#main @measured/puck
|
|
51
|
-
```
|
|
52
|
-
|
|
53
44
|
---
|
|
54
45
|
|
|
55
46
|
## Quick Start
|
|
56
47
|
|
|
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>
|
|
48
|
+
The plugin integrates directly into Payload's admin UI with minimal configuration. API endpoints and admin views are registered automatically.
|
|
92
49
|
|
|
93
|
-
|
|
50
|
+
### Step 1: Add the Plugin
|
|
94
51
|
|
|
95
52
|
```typescript
|
|
96
53
|
// payload.config.ts
|
|
@@ -107,254 +64,150 @@ export default buildConfig({
|
|
|
107
64
|
})
|
|
108
65
|
```
|
|
109
66
|
|
|
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'
|
|
67
|
+
This automatically:
|
|
68
|
+
- Creates a `pages` collection with Puck fields (or adds fields to your existing collection)
|
|
69
|
+
- Registers API endpoints at `/api/puck/:collection`
|
|
70
|
+
- Adds the Puck editor view at `/admin/puck-editor/:collection/:id`
|
|
71
|
+
- Adds "Edit with Puck" buttons to the admin UI
|
|
137
72
|
|
|
138
|
-
|
|
139
|
-
collection: 'pages',
|
|
140
|
-
payloadConfig: config,
|
|
141
|
-
auth: {
|
|
142
|
-
authenticate: async (request) => {
|
|
143
|
-
// Same auth logic as above
|
|
144
|
-
},
|
|
145
|
-
},
|
|
146
|
-
})
|
|
147
|
-
```
|
|
73
|
+
### Step 2: Provide Puck Configuration
|
|
148
74
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
First, create a layout that imports your Tailwind CSS:
|
|
152
|
-
|
|
153
|
-
```typescript
|
|
154
|
-
// app/(manage)/layout.tsx
|
|
155
|
-
import '@/app/(frontend)/globals.css' // Adjust path to your CSS
|
|
156
|
-
|
|
157
|
-
export const metadata = {
|
|
158
|
-
title: 'Puck Editor',
|
|
159
|
-
description: 'Visual page editor',
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
export default function ManageLayout({ children }: { children: React.ReactNode }) {
|
|
163
|
-
return (
|
|
164
|
-
// data-theme may be required if your CSS hides content until theme is set
|
|
165
|
-
<html lang="en" data-theme="light">
|
|
166
|
-
<body>{children}</body>
|
|
167
|
-
</html>
|
|
168
|
-
)
|
|
169
|
-
}
|
|
170
|
-
```
|
|
171
|
-
|
|
172
|
-
Then create the editor page:
|
|
75
|
+
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
76
|
|
|
174
77
|
```typescript
|
|
175
|
-
// app/(
|
|
176
|
-
'
|
|
177
|
-
|
|
178
|
-
import { PuckEditorView } from '@delmaredigital/payload-puck/editor'
|
|
78
|
+
// app/(app)/layout.tsx (covers both admin and frontend)
|
|
79
|
+
import { PuckConfigProvider } from '@delmaredigital/payload-puck/client'
|
|
179
80
|
import { editorConfig } from '@delmaredigital/payload-puck/config/editor'
|
|
180
81
|
|
|
181
|
-
export default function
|
|
82
|
+
export default function RootLayout({ children }: { children: React.ReactNode }) {
|
|
182
83
|
return (
|
|
183
|
-
<
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
84
|
+
<html lang="en">
|
|
85
|
+
<body>
|
|
86
|
+
<PuckConfigProvider config={editorConfig}>
|
|
87
|
+
{children}
|
|
88
|
+
</PuckConfigProvider>
|
|
89
|
+
</body>
|
|
90
|
+
</html>
|
|
190
91
|
)
|
|
191
92
|
}
|
|
192
93
|
```
|
|
193
94
|
|
|
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**
|
|
95
|
+
### Step 3: Create a Frontend Route
|
|
202
96
|
|
|
203
|
-
The
|
|
97
|
+
The plugin can't auto-create frontend routes (Next.js App Router is file-based), but here's copy-paste ready code:
|
|
204
98
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
```typescript
|
|
208
|
-
// Add additional plugins (headingAnalyzer is still included)
|
|
209
|
-
<PuckEditorView
|
|
210
|
-
plugins={[myCustomPlugin]}
|
|
211
|
-
// ...
|
|
212
|
-
/>
|
|
213
|
-
|
|
214
|
-
// Disable all default plugins
|
|
215
|
-
<PuckEditorView
|
|
216
|
-
plugins={false}
|
|
217
|
-
// ...
|
|
218
|
-
/>
|
|
219
|
-
```
|
|
220
|
-
|
|
221
|
-
#### Step 4: Create a Frontend Route
|
|
99
|
+
<details>
|
|
100
|
+
<summary><strong>📄 app/(frontend)/[[...slug]]/page.tsx</strong> (click to expand)</summary>
|
|
222
101
|
|
|
223
102
|
```typescript
|
|
224
|
-
// app/(frontend)/[...slug]/page.tsx
|
|
225
103
|
import { getPayload } from 'payload'
|
|
226
104
|
import config from '@payload-config'
|
|
227
105
|
import { PageRenderer } from '@delmaredigital/payload-puck/render'
|
|
228
106
|
import { baseConfig } from '@delmaredigital/payload-puck/config'
|
|
229
107
|
import { notFound } from 'next/navigation'
|
|
108
|
+
import type { Metadata } from 'next'
|
|
230
109
|
|
|
231
|
-
|
|
232
|
-
|
|
110
|
+
// Fetch page by slug (or homepage if no slug)
|
|
111
|
+
async function getPage(slug?: string[]) {
|
|
233
112
|
const payload = await getPayload({ config })
|
|
113
|
+
const slugPath = slug?.join('/') || ''
|
|
234
114
|
|
|
115
|
+
// Try to find by slug, or find homepage
|
|
235
116
|
const { docs } = await payload.find({
|
|
236
117
|
collection: 'pages',
|
|
237
|
-
where:
|
|
118
|
+
where: slugPath
|
|
119
|
+
? { slug: { equals: slugPath } }
|
|
120
|
+
: { isHomepage: { equals: true } },
|
|
238
121
|
limit: 1,
|
|
239
122
|
})
|
|
240
123
|
|
|
241
|
-
|
|
124
|
+
return docs[0] || null
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Generate metadata from page SEO fields
|
|
128
|
+
export async function generateMetadata({
|
|
129
|
+
params
|
|
130
|
+
}: {
|
|
131
|
+
params: Promise<{ slug?: string[] }>
|
|
132
|
+
}): Promise<Metadata> {
|
|
133
|
+
const { slug } = await params
|
|
134
|
+
const page = await getPage(slug)
|
|
135
|
+
|
|
136
|
+
if (!page) return {}
|
|
137
|
+
|
|
138
|
+
return {
|
|
139
|
+
title: page.meta?.title || page.title,
|
|
140
|
+
description: page.meta?.description,
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Render the page
|
|
145
|
+
export default async function Page({
|
|
146
|
+
params
|
|
147
|
+
}: {
|
|
148
|
+
params: Promise<{ slug?: string[] }>
|
|
149
|
+
}) {
|
|
150
|
+
const { slug } = await params
|
|
151
|
+
const page = await getPage(slug)
|
|
152
|
+
|
|
242
153
|
if (!page) notFound()
|
|
243
154
|
|
|
244
155
|
return <PageRenderer config={baseConfig} data={page.puckData} />
|
|
245
156
|
}
|
|
246
157
|
```
|
|
247
158
|
|
|
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'
|
|
159
|
+
</details>
|
|
254
160
|
|
|
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
|
-
```
|
|
161
|
+
> **Note:** The `[[...slug]]` pattern with double brackets makes the slug optional, so this handles both `/` (homepage) and `/any/path`.
|
|
265
162
|
|
|
266
|
-
|
|
163
|
+
### That's It!
|
|
267
164
|
|
|
268
|
-
|
|
165
|
+
- The plugin registers the editor view at `/admin/puck-editor/:collection/:id`
|
|
166
|
+
- "Edit with Puck" buttons appear in the collection list view
|
|
167
|
+
- The editor runs inside Payload's admin UI with full navigation
|
|
168
|
+
- API endpoints are handled automatically via Payload's endpoint system
|
|
269
169
|
|
|
270
170
|
---
|
|
271
171
|
|
|
272
172
|
## Styling Setup
|
|
273
173
|
|
|
274
|
-
|
|
174
|
+
### Tailwind Typography (Required)
|
|
275
175
|
|
|
276
|
-
|
|
277
|
-
<summary><strong>⚠️ Tailwind Typography</strong> — Required for RichText component</summary>
|
|
176
|
+
> Required only if using the RichText component.
|
|
278
177
|
|
|
279
|
-
The RichText component uses
|
|
178
|
+
The RichText component uses `@tailwindcss/typography`:
|
|
280
179
|
|
|
281
180
|
```bash
|
|
282
181
|
pnpm add @tailwindcss/typography
|
|
283
182
|
```
|
|
284
183
|
|
|
285
|
-
**Tailwind v4
|
|
286
|
-
|
|
184
|
+
**Tailwind v4:**
|
|
287
185
|
```css
|
|
288
186
|
@import "tailwindcss";
|
|
289
187
|
@plugin "@tailwindcss/typography";
|
|
290
188
|
```
|
|
291
189
|
|
|
292
|
-
**Tailwind v3
|
|
293
|
-
|
|
190
|
+
**Tailwind v3:**
|
|
294
191
|
```javascript
|
|
295
192
|
// tailwind.config.js
|
|
296
193
|
module.exports = {
|
|
297
|
-
plugins: [
|
|
298
|
-
require('@tailwindcss/typography'),
|
|
299
|
-
],
|
|
194
|
+
plugins: [require('@tailwindcss/typography')],
|
|
300
195
|
}
|
|
301
196
|
```
|
|
302
197
|
|
|
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.
|
|
309
|
-
|
|
310
|
-
The `@source` directive (v4) or `content` path (v3) tells Tailwind to scan the package for class names.
|
|
198
|
+
### Package Scanning (Required)
|
|
311
199
|
|
|
312
|
-
|
|
200
|
+
> Required if your project uses Tailwind CSS. Ensures component classes are included in your build.
|
|
313
201
|
|
|
314
|
-
|
|
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` |
|
|
202
|
+
Tell Tailwind to scan the plugin's components:
|
|
321
203
|
|
|
204
|
+
**Tailwind v4:**
|
|
322
205
|
```css
|
|
323
|
-
|
|
324
|
-
@plugin "@tailwindcss/typography";
|
|
325
|
-
|
|
326
|
-
/* Adjust path based on your CSS file location */
|
|
206
|
+
/* Adjust path relative to your CSS file */
|
|
327
207
|
@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
208
|
```
|
|
355
209
|
|
|
356
|
-
**Tailwind v3
|
|
357
|
-
|
|
210
|
+
**Tailwind v3:**
|
|
358
211
|
```javascript
|
|
359
212
|
// tailwind.config.js
|
|
360
213
|
module.exports = {
|
|
@@ -365,118 +218,59 @@ module.exports = {
|
|
|
365
218
|
}
|
|
366
219
|
```
|
|
367
220
|
|
|
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.
|
|
221
|
+
### Theme CSS Variables (Optional)
|
|
376
222
|
|
|
377
|
-
|
|
223
|
+
> Optional - the plugin includes sensible defaults. Define these only to customize colors in rendered content (links, borders, etc).
|
|
378
224
|
|
|
379
|
-
|
|
380
|
-
cp node_modules/@delmaredigital/payload-puck/examples/styles/puck-theme.css src/styles/
|
|
381
|
-
```
|
|
382
|
-
|
|
383
|
-
Then import it:
|
|
225
|
+
The plugin uses [shadcn/ui](https://ui.shadcn.com)-style CSS variables. If you don't use shadcn/ui and want to customize colors, define these in your CSS:
|
|
384
226
|
|
|
385
227
|
```css
|
|
386
|
-
|
|
228
|
+
:root {
|
|
229
|
+
--background: 0 0% 100%;
|
|
230
|
+
--foreground: 222.2 84% 4.9%;
|
|
231
|
+
--primary: 222.2 47.4% 11.2%;
|
|
232
|
+
--primary-foreground: 210 40% 98%;
|
|
233
|
+
--secondary: 210 40% 96%;
|
|
234
|
+
--secondary-foreground: 222.2 47.4% 11.2%;
|
|
235
|
+
--muted: 210 40% 96%;
|
|
236
|
+
--muted-foreground: 215.4 16.3% 46.9%;
|
|
237
|
+
--accent: 210 40% 96%;
|
|
238
|
+
--accent-foreground: 222.2 47.4% 11.2%;
|
|
239
|
+
--destructive: 0 84.2% 60.2%;
|
|
240
|
+
--destructive-foreground: 210 40% 98%;
|
|
241
|
+
--border: 214.3 31.8% 91.4%;
|
|
242
|
+
--input: 214.3 31.8% 91.4%;
|
|
243
|
+
--ring: 222.2 84% 4.9%;
|
|
244
|
+
--radius: 0.5rem;
|
|
245
|
+
}
|
|
387
246
|
```
|
|
388
247
|
|
|
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
248
|
---
|
|
420
249
|
|
|
421
|
-
##
|
|
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
|
-
---
|
|
452
|
-
|
|
453
|
-
<details>
|
|
454
|
-
<summary><strong>Core Concepts</strong> — Server vs Client configs, Draft system</summary>
|
|
250
|
+
## Core Concepts
|
|
455
251
|
|
|
456
252
|
### Server vs Client Configuration
|
|
457
253
|
|
|
458
|
-
The plugin provides two configurations
|
|
254
|
+
The plugin provides two configurations for React Server Components:
|
|
459
255
|
|
|
460
256
|
| Config | Import | Use Case |
|
|
461
257
|
|--------|--------|----------|
|
|
462
258
|
| `baseConfig` | `@delmaredigital/payload-puck/config` | Server-safe rendering with `PageRenderer` |
|
|
463
|
-
| `editorConfig` | `@delmaredigital/payload-puck/config/editor` | Client-side editing with full
|
|
259
|
+
| `editorConfig` | `@delmaredigital/payload-puck/config/editor` | Client-side editing with full interactivity |
|
|
464
260
|
|
|
465
261
|
```typescript
|
|
466
262
|
// Server component - use baseConfig
|
|
467
263
|
import { baseConfig } from '@delmaredigital/payload-puck/config'
|
|
468
264
|
<PageRenderer config={baseConfig} data={page.puckData} />
|
|
469
265
|
|
|
470
|
-
//
|
|
266
|
+
// PuckConfigProvider - use editorConfig
|
|
471
267
|
import { editorConfig } from '@delmaredigital/payload-puck/config/editor'
|
|
472
|
-
<
|
|
268
|
+
<PuckConfigProvider config={editorConfig}>
|
|
473
269
|
```
|
|
474
270
|
|
|
475
271
|
### Draft System
|
|
476
272
|
|
|
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.
|
|
273
|
+
The editor uses Payload's native draft system. The plugin automatically enables drafts on the pages collection. You can also enable it manually:
|
|
480
274
|
|
|
481
275
|
```typescript
|
|
482
276
|
{
|
|
@@ -487,293 +281,49 @@ The editor uses Payload's native draft system.
|
|
|
487
281
|
}
|
|
488
282
|
```
|
|
489
283
|
|
|
490
|
-
</details>
|
|
491
|
-
|
|
492
284
|
---
|
|
493
285
|
|
|
494
|
-
|
|
495
|
-
<summary><strong>Components</strong> — Layout, Typography, Media, Interactive</summary>
|
|
286
|
+
## Components
|
|
496
287
|
|
|
497
288
|
### Layout
|
|
498
289
|
|
|
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** |
|
|
290
|
+
| Component | Description |
|
|
291
|
+
|-----------|-------------|
|
|
292
|
+
| **Container** | Content wrapper with max-width and background |
|
|
293
|
+
| **Flex** | Flexible box layout with direction and alignment |
|
|
294
|
+
| **Grid** | CSS Grid layout with responsive columns |
|
|
295
|
+
| **Section** | Two-layer: full-bleed section + constrained content area |
|
|
296
|
+
| **Spacer** | Vertical/horizontal spacing element |
|
|
297
|
+
| **Template** | Save/load reusable component arrangements |
|
|
507
298
|
|
|
508
299
|
### Typography
|
|
509
300
|
|
|
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 |
|
|
301
|
+
| Component | Description |
|
|
302
|
+
|-----------|-------------|
|
|
303
|
+
| **Heading** | H1-H6 headings with size and alignment |
|
|
304
|
+
| **Text** | Paragraph text with styling options |
|
|
305
|
+
| **RichText** | TipTap-powered WYSIWYG editor |
|
|
515
306
|
|
|
516
|
-
|
|
307
|
+
### Media & Interactive
|
|
517
308
|
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
|
521
|
-
|
|
522
|
-
| **
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
| Component | Description | Responsive Controls |
|
|
527
|
-
|-----------|-------------|---------------------|
|
|
528
|
-
| **Button** | Styled button/link with variants | — |
|
|
529
|
-
| **Card** | Content card with optional image header | — |
|
|
530
|
-
| **Divider** | Horizontal rule with style options | — |
|
|
531
|
-
| **Accordion** | Expandable content sections | — |
|
|
309
|
+
| Component | Description |
|
|
310
|
+
|-----------|-------------|
|
|
311
|
+
| **Image** | Responsive image with alt text |
|
|
312
|
+
| **Button** | Styled button/link with variants |
|
|
313
|
+
| **Card** | Content card with optional image |
|
|
314
|
+
| **Divider** | Horizontal rule with styles |
|
|
315
|
+
| **Accordion** | Expandable content sections |
|
|
532
316
|
|
|
533
317
|
### Responsive Controls
|
|
534
318
|
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
- **
|
|
538
|
-
- **
|
|
539
|
-
- **Margin** - Outer spacing per breakpoint
|
|
540
|
-
- **Visibility** - Show/hide components at specific breakpoints
|
|
541
|
-
|
|
542
|
-
Breakpoints follow Tailwind CSS conventions:
|
|
543
|
-
| Breakpoint | Min Width | Description |
|
|
544
|
-
|------------|-----------|-------------|
|
|
545
|
-
| base | 0px | Mobile (default) |
|
|
546
|
-
| sm | 640px | Small tablets |
|
|
547
|
-
| md | 768px | Tablets |
|
|
548
|
-
| lg | 1024px | Laptops |
|
|
549
|
-
| xl | 1280px | Desktops |
|
|
550
|
-
|
|
551
|
-
### Template Component
|
|
552
|
-
|
|
553
|
-
The Template component allows saving groups of components as reusable templates. The plugin automatically creates a `puck-templates` collection in Payload.
|
|
554
|
-
|
|
555
|
-
**Saving a template:**
|
|
556
|
-
1. Add a Template component to your page
|
|
557
|
-
2. Add child components inside the Template slot
|
|
558
|
-
3. Click "Save as Template" and give it a name/category
|
|
559
|
-
|
|
560
|
-
**Loading a template:**
|
|
561
|
-
1. Add a Template component to your page
|
|
562
|
-
2. Select a saved template from the dropdown
|
|
563
|
-
3. The template's components are loaded into the slot
|
|
564
|
-
|
|
565
|
-
</details>
|
|
566
|
-
|
|
567
|
-
---
|
|
568
|
-
|
|
569
|
-
<details>
|
|
570
|
-
<summary><strong>Configuration</strong> — Merging configs, Custom components</summary>
|
|
571
|
-
|
|
572
|
-
### Merging Custom Components
|
|
573
|
-
|
|
574
|
-
```typescript
|
|
575
|
-
import { mergeConfigs } from '@delmaredigital/payload-puck/config'
|
|
576
|
-
import { baseConfig } from '@delmaredigital/payload-puck/config'
|
|
577
|
-
import { MyCustomComponent } from './components/MyCustomComponent'
|
|
578
|
-
|
|
579
|
-
const customConfig = mergeConfigs({
|
|
580
|
-
base: baseConfig,
|
|
581
|
-
components: {
|
|
582
|
-
MyCustomComponent,
|
|
583
|
-
},
|
|
584
|
-
categories: {
|
|
585
|
-
custom: { title: 'Custom', components: ['MyCustomComponent'] },
|
|
586
|
-
},
|
|
587
|
-
exclude: ['Spacer'], // Optionally remove components
|
|
588
|
-
})
|
|
589
|
-
```
|
|
590
|
-
|
|
591
|
-
### Creating Custom Components
|
|
592
|
-
|
|
593
|
-
Components need two variants to work across server rendering and the editor:
|
|
594
|
-
|
|
595
|
-
| File | Purpose | Used By |
|
|
596
|
-
|------|---------|---------|
|
|
597
|
-
| `MyComponent.server.tsx` | Server-safe render (no hooks/interactivity) | `baseConfig` → `PageRenderer` |
|
|
598
|
-
| `MyComponent.tsx` or `.editor.tsx` | Full interactivity + field definitions | `editorConfig` → `PuckEditor` |
|
|
599
|
-
|
|
600
|
-
**Server variant** (`MyComponent.server.tsx`):
|
|
601
|
-
- No `'use client'` directive
|
|
602
|
-
- No React hooks (`useState`, `useEffect`, etc.)
|
|
603
|
-
- No event handlers that require client JS
|
|
604
|
-
- **If component has slots**: Must include `fields: { content: { type: 'slot' } }` (Puck needs this to transform slot data into a renderable component)
|
|
605
|
-
- Other fields can be omitted (not used in rendering)
|
|
606
|
-
|
|
607
|
-
**Editor variant** (`MyComponent.tsx`):
|
|
608
|
-
- Can use `'use client'` if needed
|
|
609
|
-
- Full interactivity with hooks
|
|
610
|
-
- Includes all `fields` for the Puck sidebar
|
|
611
|
-
|
|
612
|
-
<details>
|
|
613
|
-
<summary><strong>Example: Interactive Component</strong></summary>
|
|
614
|
-
|
|
615
|
-
```tsx
|
|
616
|
-
// components/Tabs.server.tsx - Server-safe version
|
|
617
|
-
import type { ComponentConfig } from '@measured/puck'
|
|
618
|
-
|
|
619
|
-
export interface TabsProps {
|
|
620
|
-
items: { title: string; content: string }[]
|
|
621
|
-
defaultTab: number
|
|
622
|
-
}
|
|
623
|
-
|
|
624
|
-
export const TabsConfig: ComponentConfig<TabsProps> = {
|
|
625
|
-
label: 'Tabs',
|
|
626
|
-
defaultProps: {
|
|
627
|
-
items: [{ title: 'Tab 1', content: 'Content 1' }],
|
|
628
|
-
defaultTab: 0,
|
|
629
|
-
},
|
|
630
|
-
// No fields - server version only renders
|
|
631
|
-
render: ({ items, defaultTab }) => (
|
|
632
|
-
<div>
|
|
633
|
-
{/* Render only the default tab statically */}
|
|
634
|
-
<div className="flex border-b">
|
|
635
|
-
{items.map((item, i) => (
|
|
636
|
-
<div key={i} className={i === defaultTab ? 'border-b-2 border-primary' : ''}>
|
|
637
|
-
{item.title}
|
|
638
|
-
</div>
|
|
639
|
-
))}
|
|
640
|
-
</div>
|
|
641
|
-
<div>{items[defaultTab]?.content}</div>
|
|
642
|
-
</div>
|
|
643
|
-
),
|
|
644
|
-
}
|
|
645
|
-
```
|
|
646
|
-
|
|
647
|
-
```tsx
|
|
648
|
-
// components/Tabs.tsx - Editor version with interactivity
|
|
649
|
-
'use client'
|
|
650
|
-
|
|
651
|
-
import type { ComponentConfig } from '@measured/puck'
|
|
652
|
-
import { useState } from 'react'
|
|
653
|
-
|
|
654
|
-
export interface TabsProps {
|
|
655
|
-
items: { title: string; content: string }[]
|
|
656
|
-
defaultTab: number
|
|
657
|
-
}
|
|
658
|
-
|
|
659
|
-
export const TabsConfig: ComponentConfig<TabsProps> = {
|
|
660
|
-
label: 'Tabs',
|
|
661
|
-
fields: {
|
|
662
|
-
items: {
|
|
663
|
-
type: 'array',
|
|
664
|
-
label: 'Tabs',
|
|
665
|
-
arrayFields: {
|
|
666
|
-
title: { type: 'text', label: 'Title' },
|
|
667
|
-
content: { type: 'textarea', label: 'Content' },
|
|
668
|
-
},
|
|
669
|
-
},
|
|
670
|
-
defaultTab: { type: 'number', label: 'Default Tab' },
|
|
671
|
-
},
|
|
672
|
-
defaultProps: {
|
|
673
|
-
items: [{ title: 'Tab 1', content: 'Content 1' }],
|
|
674
|
-
defaultTab: 0,
|
|
675
|
-
},
|
|
676
|
-
render: ({ items, defaultTab }) => {
|
|
677
|
-
const [activeTab, setActiveTab] = useState(defaultTab)
|
|
678
|
-
|
|
679
|
-
return (
|
|
680
|
-
<div>
|
|
681
|
-
<div className="flex border-b">
|
|
682
|
-
{items.map((item, i) => (
|
|
683
|
-
<button
|
|
684
|
-
key={i}
|
|
685
|
-
onClick={() => setActiveTab(i)}
|
|
686
|
-
className={i === activeTab ? 'border-b-2 border-primary' : ''}
|
|
687
|
-
>
|
|
688
|
-
{item.title}
|
|
689
|
-
</button>
|
|
690
|
-
))}
|
|
691
|
-
</div>
|
|
692
|
-
<div>{items[activeTab]?.content}</div>
|
|
693
|
-
</div>
|
|
694
|
-
)
|
|
695
|
-
},
|
|
696
|
-
}
|
|
697
|
-
```
|
|
698
|
-
|
|
699
|
-
Then register both:
|
|
700
|
-
```tsx
|
|
701
|
-
// In your custom baseConfig
|
|
702
|
-
import { TabsConfig } from './components/Tabs.server'
|
|
703
|
-
|
|
704
|
-
// In your custom editorConfig
|
|
705
|
-
import { TabsConfig } from './components/Tabs'
|
|
706
|
-
```
|
|
707
|
-
</details>
|
|
708
|
-
|
|
709
|
-
<details>
|
|
710
|
-
<summary><strong>Example: Component with Slot (nested components)</strong></summary>
|
|
711
|
-
|
|
712
|
-
```tsx
|
|
713
|
-
// components/Card.server.tsx - Server-safe version WITH slot field
|
|
714
|
-
import type { ComponentConfig } from '@measured/puck'
|
|
715
|
-
|
|
716
|
-
export interface CardProps {
|
|
717
|
-
content: unknown // Slot for nested components
|
|
718
|
-
title: string
|
|
719
|
-
}
|
|
720
|
-
|
|
721
|
-
export const CardConfig: ComponentConfig<CardProps> = {
|
|
722
|
-
label: 'Card',
|
|
723
|
-
// CRITICAL: Slot field MUST be defined for Puck to transform data into component
|
|
724
|
-
fields: {
|
|
725
|
-
content: { type: 'slot' },
|
|
726
|
-
},
|
|
727
|
-
defaultProps: {
|
|
728
|
-
content: [],
|
|
729
|
-
title: 'Card Title',
|
|
730
|
-
},
|
|
731
|
-
render: ({ content: Content, title }) => (
|
|
732
|
-
<div className="border rounded-lg p-4">
|
|
733
|
-
<h3 className="font-bold mb-2">{title}</h3>
|
|
734
|
-
<Content /> {/* Renders nested components */}
|
|
735
|
-
</div>
|
|
736
|
-
),
|
|
737
|
-
}
|
|
738
|
-
```
|
|
739
|
-
|
|
740
|
-
```tsx
|
|
741
|
-
// components/Card.tsx - Editor version with all fields
|
|
742
|
-
import type { ComponentConfig } from '@measured/puck'
|
|
743
|
-
|
|
744
|
-
export interface CardProps {
|
|
745
|
-
content: unknown
|
|
746
|
-
title: string
|
|
747
|
-
}
|
|
748
|
-
|
|
749
|
-
export const CardConfig: ComponentConfig<CardProps> = {
|
|
750
|
-
label: 'Card',
|
|
751
|
-
fields: {
|
|
752
|
-
title: { type: 'text', label: 'Title' },
|
|
753
|
-
content: { type: 'slot' },
|
|
754
|
-
},
|
|
755
|
-
defaultProps: {
|
|
756
|
-
content: [],
|
|
757
|
-
title: 'Card Title',
|
|
758
|
-
},
|
|
759
|
-
render: ({ content: Content, title }) => (
|
|
760
|
-
<div className="border rounded-lg p-4">
|
|
761
|
-
<h3 className="font-bold mb-2">{title}</h3>
|
|
762
|
-
<Content />
|
|
763
|
-
</div>
|
|
764
|
-
),
|
|
765
|
-
}
|
|
766
|
-
```
|
|
767
|
-
|
|
768
|
-
**Why slots need the field definition:** Puck stores slot content as an array of component data. The `fields: { content: { type: 'slot' } }` tells Puck to transform this array into a renderable `<Content />` component before passing it to `render()`. Without this, you'll get "Element type is invalid: got array" errors.
|
|
769
|
-
</details>
|
|
770
|
-
|
|
771
|
-
</details>
|
|
319
|
+
Layout components support per-breakpoint customization:
|
|
320
|
+
- **Dimensions** - Width, max-width, height constraints
|
|
321
|
+
- **Padding/Margin** - Spacing per breakpoint
|
|
322
|
+
- **Visibility** - Show/hide at specific breakpoints
|
|
772
323
|
|
|
773
324
|
---
|
|
774
325
|
|
|
775
|
-
|
|
776
|
-
<summary><strong>Custom Fields</strong> — 19 field types with usage examples</summary>
|
|
326
|
+
## Custom Fields
|
|
777
327
|
|
|
778
328
|
All fields are imported from `@delmaredigital/payload-puck/fields`.
|
|
779
329
|
|
|
@@ -781,276 +331,176 @@ All fields are imported from `@delmaredigital/payload-puck/fields`.
|
|
|
781
331
|
|
|
782
332
|
| Field | Description |
|
|
783
333
|
|-------|-------------|
|
|
784
|
-
| **MediaField** | Payload media library integration
|
|
785
|
-
| **TiptapField** | Rich text editor with formatting
|
|
786
|
-
| **ColorPickerField** | Color picker with
|
|
787
|
-
| **BackgroundField** |
|
|
788
|
-
| **PaddingField** | Visual
|
|
789
|
-
| **
|
|
790
|
-
| **
|
|
791
|
-
| **
|
|
792
|
-
| **
|
|
793
|
-
| **
|
|
794
|
-
| **
|
|
795
|
-
| **
|
|
796
|
-
| **
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
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
|
-
},
|
|
334
|
+
| **MediaField** | Payload media library integration |
|
|
335
|
+
| **TiptapField** | Rich text editor with formatting |
|
|
336
|
+
| **ColorPickerField** | Color picker with opacity and presets |
|
|
337
|
+
| **BackgroundField** | Solid colors, gradients, images |
|
|
338
|
+
| **PaddingField / MarginField** | Visual spacing editors |
|
|
339
|
+
| **BorderField** | Border width, style, color, radius |
|
|
340
|
+
| **DimensionsField** | Width/height with constraints |
|
|
341
|
+
| **AlignmentField** | Text alignment options |
|
|
342
|
+
| **AnimationField** | Entrance animations |
|
|
343
|
+
| **ResponsiveVisibilityField** | Show/hide per breakpoint |
|
|
344
|
+
| **FolderPickerField** | Hierarchical folder selection (page-tree) |
|
|
345
|
+
| **PageSegmentField** | URL segment with slugification (page-tree) |
|
|
346
|
+
| **SlugPreviewField** | Read-only computed slug (page-tree) |
|
|
347
|
+
|
|
348
|
+
### Usage Example
|
|
349
|
+
|
|
350
|
+
```typescript
|
|
351
|
+
import { createMediaField, createBackgroundField, backgroundValueToCSS } from '@delmaredigital/payload-puck/fields'
|
|
352
|
+
|
|
353
|
+
const HeroConfig = {
|
|
354
|
+
fields: {
|
|
355
|
+
image: createMediaField({ label: 'Background Image' }),
|
|
356
|
+
background: createBackgroundField({ label: 'Overlay' }),
|
|
845
357
|
},
|
|
358
|
+
render: ({ image, background }) => (
|
|
359
|
+
<section style={{ background: backgroundValueToCSS(background) }}>
|
|
360
|
+
{/* content */}
|
|
361
|
+
</section>
|
|
362
|
+
),
|
|
846
363
|
}
|
|
847
364
|
```
|
|
848
|
-
</details>
|
|
849
365
|
|
|
850
|
-
|
|
851
|
-
<summary><strong>ColorPickerField</strong></summary>
|
|
852
|
-
|
|
853
|
-
Color picker with presets and alpha channel:
|
|
366
|
+
### CSS Helper Functions
|
|
854
367
|
|
|
855
368
|
```typescript
|
|
856
|
-
import {
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
backgroundColor: createColorPickerField({
|
|
863
|
-
label: 'Background Color',
|
|
864
|
-
}),
|
|
865
|
-
},
|
|
866
|
-
},
|
|
867
|
-
},
|
|
868
|
-
}
|
|
369
|
+
import {
|
|
370
|
+
backgroundValueToCSS,
|
|
371
|
+
dimensionsValueToCSS,
|
|
372
|
+
animationValueToCSS,
|
|
373
|
+
visibilityValueToCSS,
|
|
374
|
+
} from '@delmaredigital/payload-puck/fields'
|
|
869
375
|
```
|
|
870
|
-
</details>
|
|
871
376
|
|
|
872
|
-
|
|
873
|
-
<summary><strong>BackgroundField</strong></summary>
|
|
874
|
-
|
|
875
|
-
Full background editor with solid colors, gradients, and images:
|
|
377
|
+
---
|
|
876
378
|
|
|
877
|
-
|
|
878
|
-
import { createBackgroundField, backgroundValueToCSS } from '@delmaredigital/payload-puck/fields'
|
|
379
|
+
## Building Custom Components
|
|
879
380
|
|
|
880
|
-
|
|
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>
|
|
381
|
+
The plugin exports individual component configs and field factories for building custom Puck configurations.
|
|
896
382
|
|
|
897
|
-
|
|
898
|
-
<summary><strong>DimensionsField</strong></summary>
|
|
383
|
+
### Cherry-Picking Components
|
|
899
384
|
|
|
900
|
-
|
|
385
|
+
Import only the components you need:
|
|
901
386
|
|
|
902
387
|
```typescript
|
|
903
|
-
import {
|
|
904
|
-
|
|
905
|
-
|
|
388
|
+
import {
|
|
389
|
+
SectionConfig,
|
|
390
|
+
HeadingConfig,
|
|
391
|
+
TextConfig,
|
|
392
|
+
ImageConfig,
|
|
393
|
+
ButtonConfig,
|
|
394
|
+
} from '@delmaredigital/payload-puck/components'
|
|
395
|
+
|
|
396
|
+
export const puckConfig: Config = {
|
|
906
397
|
components: {
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
<div style={dimensionsValueToCSS(dimensions)}>
|
|
913
|
-
{children}
|
|
914
|
-
</div>
|
|
915
|
-
),
|
|
916
|
-
},
|
|
398
|
+
Section: SectionConfig,
|
|
399
|
+
Heading: HeadingConfig,
|
|
400
|
+
Text: TextConfig,
|
|
401
|
+
Image: ImageConfig,
|
|
402
|
+
Button: ButtonConfig,
|
|
917
403
|
},
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
<details>
|
|
923
|
-
<summary><strong>PaddingField & MarginField</strong></summary>
|
|
924
|
-
|
|
925
|
-
Visual spacing editors:
|
|
926
|
-
|
|
927
|
-
```typescript
|
|
928
|
-
import { createPaddingField, createMarginField } from '@delmaredigital/payload-puck/fields'
|
|
929
|
-
|
|
930
|
-
const config = {
|
|
931
|
-
components: {
|
|
932
|
-
Box: {
|
|
933
|
-
fields: {
|
|
934
|
-
padding: createPaddingField({ label: 'Padding' }),
|
|
935
|
-
margin: createMarginField({ label: 'Margin' }),
|
|
936
|
-
},
|
|
937
|
-
},
|
|
404
|
+
categories: {
|
|
405
|
+
layout: { components: ['Section'] },
|
|
406
|
+
content: { components: ['Heading', 'Text', 'Image', 'Button'] },
|
|
938
407
|
},
|
|
939
408
|
}
|
|
940
409
|
```
|
|
941
|
-
</details>
|
|
942
410
|
|
|
943
|
-
|
|
944
|
-
<summary><strong>LockedTextField & LockedRadioField</strong></summary>
|
|
411
|
+
### Using Field Factories
|
|
945
412
|
|
|
946
|
-
|
|
413
|
+
Build custom components with pre-built fields:
|
|
947
414
|
|
|
948
415
|
```typescript
|
|
416
|
+
import type { ComponentConfig } from '@measured/puck'
|
|
949
417
|
import {
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
418
|
+
createMediaField,
|
|
419
|
+
createBackgroundField,
|
|
420
|
+
createPaddingField,
|
|
421
|
+
backgroundValueToCSS,
|
|
422
|
+
paddingValueToCSS,
|
|
954
423
|
} from '@delmaredigital/payload-puck/fields'
|
|
955
424
|
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
425
|
+
export const HeroConfig: ComponentConfig = {
|
|
426
|
+
label: 'Hero',
|
|
427
|
+
fields: {
|
|
428
|
+
image: createMediaField({ label: 'Background Image' }),
|
|
429
|
+
overlay: createBackgroundField({ label: 'Overlay' }),
|
|
430
|
+
padding: createPaddingField({ label: 'Padding' }),
|
|
431
|
+
},
|
|
432
|
+
defaultProps: {
|
|
433
|
+
image: null,
|
|
434
|
+
overlay: null,
|
|
435
|
+
padding: { top: 80, bottom: 80, left: 24, right: 24, unit: 'px', linked: false },
|
|
963
436
|
},
|
|
437
|
+
render: ({ image, overlay, padding }) => (
|
|
438
|
+
<section
|
|
439
|
+
style={{
|
|
440
|
+
background: backgroundValueToCSS(overlay),
|
|
441
|
+
padding: paddingValueToCSS(padding),
|
|
442
|
+
}}
|
|
443
|
+
>
|
|
444
|
+
{/* Hero content */}
|
|
445
|
+
</section>
|
|
446
|
+
),
|
|
964
447
|
}
|
|
965
|
-
|
|
966
|
-
// Or create custom locked fields
|
|
967
|
-
const customLockedField = createLockedTextField({
|
|
968
|
-
label: 'API Key',
|
|
969
|
-
placeholder: 'Enter API key',
|
|
970
|
-
warningMessage: 'Changing this will break integrations.',
|
|
971
|
-
})
|
|
972
448
|
```
|
|
973
|
-
</details>
|
|
974
449
|
|
|
975
|
-
|
|
976
|
-
<summary><strong>AnimationField</strong></summary>
|
|
450
|
+
### Server vs Editor Variants
|
|
977
451
|
|
|
978
|
-
|
|
452
|
+
For `PageRenderer` (frontend), components need server-safe configs without React hooks:
|
|
979
453
|
|
|
980
454
|
```typescript
|
|
981
|
-
|
|
455
|
+
// Import server variants for PageRenderer
|
|
456
|
+
import {
|
|
457
|
+
SectionServerConfig,
|
|
458
|
+
HeadingServerConfig,
|
|
459
|
+
TextServerConfig,
|
|
460
|
+
} from '@delmaredigital/payload-puck/components'
|
|
982
461
|
|
|
983
|
-
|
|
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
|
-
}
|
|
462
|
+
<PageRenderer config={{ components: { Section: SectionServerConfig, ... } }} data={page.puckData} />
|
|
997
463
|
```
|
|
998
|
-
</details>
|
|
999
464
|
|
|
1000
|
-
|
|
1001
|
-
|
|
465
|
+
For custom components, create two files:
|
|
466
|
+
- `MyComponent.tsx` - Full editor version with fields and interactivity
|
|
467
|
+
- `MyComponent.server.tsx` - Server-safe version (no hooks, no 'use client')
|
|
1002
468
|
|
|
1003
|
-
|
|
469
|
+
### Extending Built-in Configs
|
|
470
|
+
|
|
471
|
+
Use `extendConfig()` to add custom components:
|
|
1004
472
|
|
|
1005
473
|
```typescript
|
|
1006
|
-
import {
|
|
474
|
+
import { extendConfig, fullConfig } from '@delmaredigital/payload-puck/config/editor'
|
|
475
|
+
import { HeroConfig } from './components/Hero'
|
|
1007
476
|
|
|
1008
|
-
const
|
|
477
|
+
export const puckConfig = extendConfig({
|
|
478
|
+
base: fullConfig,
|
|
1009
479
|
components: {
|
|
1010
|
-
|
|
1011
|
-
fields: {
|
|
1012
|
-
columns: createResponsiveField({
|
|
1013
|
-
label: 'Columns',
|
|
1014
|
-
field: { type: 'number' },
|
|
1015
|
-
defaultValue: { sm: 1, md: 2, lg: 3 },
|
|
1016
|
-
}),
|
|
1017
|
-
},
|
|
1018
|
-
},
|
|
480
|
+
Hero: HeroConfig,
|
|
1019
481
|
},
|
|
1020
|
-
|
|
482
|
+
categories: {
|
|
483
|
+
custom: { title: 'Custom', components: ['Hero'] },
|
|
484
|
+
},
|
|
485
|
+
})
|
|
1021
486
|
```
|
|
1022
|
-
</details>
|
|
1023
487
|
|
|
1024
|
-
|
|
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'
|
|
488
|
+
> **Note:** Use `fullConfig` from `/config/editor` for extending the editor. For server-side rendering, use `baseConfig` from `/config`.
|
|
1031
489
|
|
|
1032
|
-
|
|
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
|
-
```
|
|
490
|
+
### Available Field Factories
|
|
1051
491
|
|
|
1052
|
-
|
|
1053
|
-
|
|
492
|
+
| Factory | Description |
|
|
493
|
+
|---------|-------------|
|
|
494
|
+
| `createMediaField()` | Payload media library picker |
|
|
495
|
+
| `createBackgroundField()` | Solid, gradient, or image backgrounds |
|
|
496
|
+
| `createColorPickerField()` | Color picker with opacity |
|
|
497
|
+
| `createPaddingField()` | Visual padding editor |
|
|
498
|
+
| `createMarginField()` | Visual margin editor |
|
|
499
|
+
| `createBorderField()` | Border styling |
|
|
500
|
+
| `createDimensionsField()` | Width/height constraints |
|
|
501
|
+
| `createAnimationField()` | Entrance animations |
|
|
502
|
+
| `createAlignmentField()` | Text alignment |
|
|
503
|
+
| `createTiptapField()` | Inline rich text editor |
|
|
1054
504
|
|
|
1055
505
|
### CSS Helper Functions
|
|
1056
506
|
|
|
@@ -1059,56 +509,25 @@ Convert field values to CSS:
|
|
|
1059
509
|
```typescript
|
|
1060
510
|
import {
|
|
1061
511
|
backgroundValueToCSS,
|
|
512
|
+
paddingValueToCSS,
|
|
513
|
+
marginValueToCSS,
|
|
514
|
+
borderValueToCSS,
|
|
1062
515
|
dimensionsValueToCSS,
|
|
1063
|
-
|
|
1064
|
-
transformValueToCSS,
|
|
1065
|
-
gradientValueToCSS,
|
|
1066
|
-
sizeValueToCSS,
|
|
1067
|
-
// Responsive helpers
|
|
1068
|
-
responsiveValueToCSS,
|
|
1069
|
-
visibilityValueToCSS,
|
|
516
|
+
colorValueToCSS,
|
|
1070
517
|
} from '@delmaredigital/payload-puck/fields'
|
|
1071
518
|
|
|
1072
|
-
const
|
|
1073
|
-
background: backgroundValueToCSS(background),
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
transform: transformValueToCSS(transform),
|
|
519
|
+
const style = {
|
|
520
|
+
background: backgroundValueToCSS(props.background),
|
|
521
|
+
padding: paddingValueToCSS(props.padding),
|
|
522
|
+
...dimensionsValueToCSS(props.dimensions),
|
|
1077
523
|
}
|
|
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
524
|
```
|
|
1099
525
|
|
|
1100
|
-
</details>
|
|
1101
|
-
|
|
1102
526
|
---
|
|
1103
527
|
|
|
1104
|
-
|
|
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
|
|
528
|
+
## Theming
|
|
1110
529
|
|
|
1111
|
-
|
|
530
|
+
Customize button styles, color presets, and focus rings:
|
|
1112
531
|
|
|
1113
532
|
```typescript
|
|
1114
533
|
import { PageRenderer } from '@delmaredigital/payload-puck/render'
|
|
@@ -1116,94 +535,36 @@ import { ThemeProvider } from '@delmaredigital/payload-puck/theme'
|
|
|
1116
535
|
|
|
1117
536
|
<ThemeProvider theme={{
|
|
1118
537
|
buttonVariants: {
|
|
1119
|
-
default: { classes: 'bg-primary text-
|
|
1120
|
-
secondary: { classes: 'bg-secondary text-
|
|
538
|
+
default: { classes: 'bg-primary text-white hover:bg-primary/90' },
|
|
539
|
+
secondary: { classes: 'bg-secondary text-foreground hover:bg-secondary/90' },
|
|
1121
540
|
},
|
|
1122
541
|
focusRingColor: 'focus:ring-primary',
|
|
1123
|
-
}}>
|
|
1124
|
-
<PageRenderer config={baseConfig} data={page.puckData} />
|
|
1125
|
-
</ThemeProvider>
|
|
1126
|
-
```
|
|
1127
|
-
|
|
1128
|
-
### Using the Example Theme
|
|
1129
|
-
|
|
1130
|
-
```typescript
|
|
1131
|
-
import { ThemeProvider, exampleTheme } from '@delmaredigital/payload-puck/theme'
|
|
1132
|
-
|
|
1133
|
-
<ThemeProvider theme={exampleTheme}>
|
|
1134
|
-
<PageRenderer data={page.puckData} />
|
|
1135
|
-
</ThemeProvider>
|
|
1136
|
-
|
|
1137
|
-
// Or customize specific values
|
|
1138
|
-
<ThemeProvider theme={{
|
|
1139
|
-
...exampleTheme,
|
|
1140
|
-
focusRingColor: 'focus:ring-brand',
|
|
1141
|
-
}}>
|
|
1142
|
-
<PageRenderer data={page.puckData} />
|
|
1143
|
-
</ThemeProvider>
|
|
1144
|
-
```
|
|
1145
|
-
|
|
1146
|
-
### Theme Options
|
|
1147
|
-
|
|
1148
|
-
| Option | Description |
|
|
1149
|
-
|--------|-------------|
|
|
1150
|
-
| `buttonVariants` | Button component variant styles (default, secondary, outline, ghost) |
|
|
1151
|
-
| `ctaButtonVariants` | CallToAction button styles (primary, secondary, outline) |
|
|
1152
|
-
| `ctaBackgroundStyles` | CallToAction background styles (default, dark, light) |
|
|
1153
|
-
| `colorPresets` | Color picker preset swatches |
|
|
1154
|
-
| `extendColorPresets` | If true, adds to defaults instead of replacing |
|
|
1155
|
-
| `focusRingColor` | Focus ring class (e.g., `focus:ring-primary`) |
|
|
1156
|
-
|
|
1157
|
-
### Custom Color Presets
|
|
1158
|
-
|
|
1159
|
-
```typescript
|
|
1160
|
-
<ThemeProvider theme={{
|
|
1161
542
|
colorPresets: [
|
|
1162
543
|
{ hex: '#3b82f6', label: 'Brand Blue' },
|
|
1163
544
|
{ hex: '#10b981', label: 'Success' },
|
|
1164
|
-
{ hex: '#ef4444', label: 'Danger' },
|
|
1165
545
|
],
|
|
1166
|
-
extendColorPresets: false, // Replace defaults
|
|
1167
546
|
}}>
|
|
1168
|
-
<PageRenderer data={page.puckData} />
|
|
547
|
+
<PageRenderer config={baseConfig} data={page.puckData} />
|
|
1169
548
|
</ThemeProvider>
|
|
1170
549
|
```
|
|
1171
550
|
|
|
1172
|
-
|
|
551
|
+
Access theme values in custom components with `useTheme()`:
|
|
1173
552
|
|
|
1174
553
|
```typescript
|
|
1175
|
-
import {
|
|
1176
|
-
ThemeProvider,
|
|
1177
|
-
useTheme,
|
|
1178
|
-
getVariantClasses,
|
|
1179
|
-
DEFAULT_THEME,
|
|
1180
|
-
} from '@delmaredigital/payload-puck/theme'
|
|
554
|
+
import { useTheme } from '@delmaredigital/payload-puck/theme'
|
|
1181
555
|
|
|
1182
|
-
function
|
|
556
|
+
function CustomButton({ variant }) {
|
|
1183
557
|
const theme = useTheme()
|
|
1184
|
-
const classes =
|
|
1185
|
-
return <button className={classes}
|
|
558
|
+
const classes = theme.buttonVariants[variant]?.classes
|
|
559
|
+
return <button className={classes}>...</button>
|
|
1186
560
|
}
|
|
1187
561
|
```
|
|
1188
562
|
|
|
1189
|
-
</details>
|
|
1190
|
-
|
|
1191
563
|
---
|
|
1192
564
|
|
|
1193
|
-
|
|
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.
|
|
565
|
+
## Layouts
|
|
1197
566
|
|
|
1198
|
-
|
|
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
|
|
567
|
+
Define page layouts with headers, footers, and styling:
|
|
1207
568
|
|
|
1208
569
|
```typescript
|
|
1209
570
|
// lib/puck-layouts.ts
|
|
@@ -1219,280 +580,91 @@ export const siteLayouts: LayoutDefinition[] = [
|
|
|
1219
580
|
maxWidth: '1200px',
|
|
1220
581
|
header: SiteHeader,
|
|
1221
582
|
footer: SiteFooter,
|
|
1222
|
-
editorBackground: '#ffffff',
|
|
1223
|
-
editorDarkMode: false,
|
|
1224
583
|
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
584
|
},
|
|
1233
585
|
{
|
|
1234
586
|
value: 'landing',
|
|
1235
587
|
label: 'Landing',
|
|
1236
588
|
description: 'Full-width landing page',
|
|
1237
589
|
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
590
|
},
|
|
1251
591
|
]
|
|
1252
592
|
```
|
|
1253
593
|
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
### Using Layouts in the Editor
|
|
594
|
+
Pass layouts to the `PuckConfigProvider`:
|
|
1257
595
|
|
|
1258
596
|
```typescript
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
<PuckEditor
|
|
1263
|
-
config={editorConfig}
|
|
1264
|
-
pageId={page.id}
|
|
1265
|
-
initialData={page.puckData}
|
|
1266
|
-
layouts={siteLayouts}
|
|
1267
|
-
/>
|
|
1268
|
-
```
|
|
1269
|
-
|
|
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
|
-
}
|
|
597
|
+
<PuckConfigProvider config={editorConfig} layouts={siteLayouts}>
|
|
598
|
+
{children}
|
|
599
|
+
</PuckConfigProvider>
|
|
1286
600
|
```
|
|
1287
601
|
|
|
1288
|
-
|
|
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:
|
|
602
|
+
And use them with `PageRenderer`:
|
|
1329
603
|
|
|
1330
604
|
```typescript
|
|
1331
|
-
|
|
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
|
-
```
|
|
605
|
+
import { LayoutWrapper } from '@delmaredigital/payload-puck/layouts'
|
|
1347
606
|
|
|
1348
|
-
|
|
607
|
+
const layout = siteLayouts.find(l => l.value === page.puckData?.root?.props?.pageLayout)
|
|
1349
608
|
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
createPuckApiRoutesWithId({
|
|
1354
|
-
// ...
|
|
1355
|
-
rootPropsMapping: [
|
|
1356
|
-
{ from: 'title', to: 'meta.title' },
|
|
1357
|
-
{ from: 'description', to: 'meta.description' },
|
|
1358
|
-
{ from: 'pageLayout', to: 'pageLayout' },
|
|
1359
|
-
],
|
|
1360
|
-
})
|
|
609
|
+
<LayoutWrapper layout={layout}>
|
|
610
|
+
<PageRenderer config={baseConfig} data={page.puckData} />
|
|
611
|
+
</LayoutWrapper>
|
|
1361
612
|
```
|
|
1362
613
|
|
|
1363
|
-
</details>
|
|
1364
|
-
|
|
1365
614
|
---
|
|
1366
615
|
|
|
1367
|
-
|
|
1368
|
-
<summary><strong>SEO Fields</strong> — Robots meta, sitemap integration</summary>
|
|
616
|
+
## Page-Tree Integration
|
|
1369
617
|
|
|
1370
|
-
|
|
618
|
+
When `@delmaredigital/payload-page-tree` is detected, the plugin automatically adds folder management to the Puck sidebar.
|
|
1371
619
|
|
|
1372
|
-
|
|
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 |
|
|
620
|
+
### How It Works
|
|
1380
621
|
|
|
1381
|
-
|
|
622
|
+
The plugin checks if your collection has a `pageSegment` field (page-tree's signature). When detected:
|
|
1382
623
|
|
|
1383
|
-
|
|
624
|
+
1. **Folder Picker** - Select a folder from the hierarchy
|
|
625
|
+
2. **Page Segment** - Edit the page's URL segment
|
|
626
|
+
3. **Slug Preview** - See the computed slug (folder path + segment)
|
|
1384
627
|
|
|
1385
|
-
|
|
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
|
|
1404
|
-
|
|
1405
|
-
Filter out pages marked as excluded in your `sitemap.ts`:
|
|
1406
|
-
|
|
1407
|
-
```typescript
|
|
1408
|
-
// app/sitemap.ts
|
|
1409
|
-
import type { MetadataRoute } from 'next'
|
|
1410
|
-
import { getPayload } from 'payload'
|
|
1411
|
-
import config from '@payload-config'
|
|
1412
|
-
|
|
1413
|
-
export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
|
|
1414
|
-
const baseUrl = 'https://yoursite.com'
|
|
1415
|
-
const payload = await getPayload({ config })
|
|
1416
|
-
|
|
1417
|
-
const { docs: pages } = await payload.find({
|
|
1418
|
-
collection: 'pages',
|
|
1419
|
-
limit: 1000,
|
|
1420
|
-
where: {
|
|
1421
|
-
or: [
|
|
1422
|
-
{ 'meta.excludeFromSitemap': { equals: false } },
|
|
1423
|
-
{ 'meta.excludeFromSitemap': { exists: false } },
|
|
1424
|
-
],
|
|
1425
|
-
},
|
|
1426
|
-
select: {
|
|
1427
|
-
slug: true,
|
|
1428
|
-
updatedAt: true,
|
|
1429
|
-
},
|
|
1430
|
-
})
|
|
1431
|
-
|
|
1432
|
-
return pages.map((page) => ({
|
|
1433
|
-
url: `${baseUrl}/${page.slug}`,
|
|
1434
|
-
lastModified: new Date(page.updatedAt),
|
|
1435
|
-
}))
|
|
1436
|
-
}
|
|
1437
|
-
```
|
|
1438
|
-
|
|
1439
|
-
</details>
|
|
1440
|
-
|
|
1441
|
-
---
|
|
1442
|
-
|
|
1443
|
-
<details>
|
|
1444
|
-
<summary><strong>Plugin Options</strong> — Collection config, access control</summary>
|
|
628
|
+
### Configuration
|
|
1445
629
|
|
|
1446
630
|
```typescript
|
|
1447
631
|
createPuckPlugin({
|
|
1448
|
-
//
|
|
1449
|
-
|
|
632
|
+
// Auto-detect (default)
|
|
633
|
+
pageTreeIntegration: undefined,
|
|
1450
634
|
|
|
1451
|
-
//
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
collectionOverrides: {
|
|
1456
|
-
admin: {
|
|
1457
|
-
defaultColumns: ['title', 'slug', 'updatedAt'],
|
|
1458
|
-
},
|
|
635
|
+
// Explicitly enable with custom config
|
|
636
|
+
pageTreeIntegration: {
|
|
637
|
+
folderSlug: 'payload-folders',
|
|
638
|
+
pageSegmentFieldName: 'pageSegment',
|
|
1459
639
|
},
|
|
1460
640
|
|
|
1461
|
-
//
|
|
1462
|
-
|
|
1463
|
-
read: () => true,
|
|
1464
|
-
create: ({ req }) => !!req.user,
|
|
1465
|
-
update: ({ req }) => !!req.user,
|
|
1466
|
-
delete: ({ req }) => !!req.user,
|
|
1467
|
-
},
|
|
641
|
+
// Explicitly disable
|
|
642
|
+
pageTreeIntegration: false,
|
|
1468
643
|
})
|
|
1469
644
|
```
|
|
1470
645
|
|
|
1471
|
-
|
|
646
|
+
### Performance
|
|
647
|
+
|
|
648
|
+
Detection is instant - it reads the in-memory collection config, no database queries.
|
|
1472
649
|
|
|
1473
650
|
---
|
|
1474
651
|
|
|
1475
|
-
|
|
1476
|
-
<summary><strong>Hybrid Integration</strong> — Add Puck to existing collections with legacy blocks</summary>
|
|
652
|
+
## Hybrid Integration
|
|
1477
653
|
|
|
1478
|
-
|
|
654
|
+
Add Puck to existing collections with legacy blocks.
|
|
1479
655
|
|
|
1480
656
|
### Automatic (Recommended)
|
|
1481
657
|
|
|
1482
|
-
If you already have a `pages` collection
|
|
658
|
+
If you already have a `pages` collection, the plugin adds only the Puck-specific fields:
|
|
1483
659
|
|
|
1484
660
|
```typescript
|
|
1485
661
|
// payload.config.ts
|
|
1486
|
-
import { buildConfig } from 'payload'
|
|
1487
|
-
import { createPuckPlugin } from '@delmaredigital/payload-puck/plugin'
|
|
1488
|
-
|
|
1489
662
|
export default buildConfig({
|
|
1490
663
|
collections: [
|
|
1491
664
|
{
|
|
1492
665
|
slug: 'pages',
|
|
1493
666
|
fields: [
|
|
1494
667
|
{ name: 'title', type: 'text', required: true },
|
|
1495
|
-
{ name: 'slug', type: 'text', required: true },
|
|
1496
668
|
{ name: 'layout', type: 'blocks', blocks: [HeroBlock, CTABlock] },
|
|
1497
669
|
],
|
|
1498
670
|
},
|
|
@@ -1503,162 +675,118 @@ export default buildConfig({
|
|
|
1503
675
|
})
|
|
1504
676
|
```
|
|
1505
677
|
|
|
1506
|
-
The
|
|
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.
|
|
678
|
+
The `editorVersion` field auto-detects whether pages use legacy blocks or Puck.
|
|
1509
679
|
|
|
1510
680
|
### Manual with `getPuckFields()`
|
|
1511
681
|
|
|
1512
|
-
For full control, disable auto-generation and use `getPuckFields()`:
|
|
1513
|
-
|
|
1514
682
|
```typescript
|
|
1515
|
-
// collections/Pages.ts
|
|
1516
|
-
import type { CollectionConfig } from 'payload'
|
|
1517
683
|
import { getPuckFields } from '@delmaredigital/payload-puck'
|
|
1518
684
|
|
|
1519
685
|
export const Pages: CollectionConfig = {
|
|
1520
686
|
slug: 'pages',
|
|
1521
|
-
versions: { drafts: true },
|
|
1522
687
|
fields: [
|
|
1523
|
-
{ name: 'title', type: 'text'
|
|
1524
|
-
{ name: '
|
|
1525
|
-
{ name: 'layout', type: 'blocks', blocks: [HeroBlock, CTABlock] },
|
|
1526
|
-
|
|
688
|
+
{ name: 'title', type: 'text' },
|
|
689
|
+
{ name: 'layout', type: 'blocks', blocks: [...] },
|
|
1527
690
|
...getPuckFields({
|
|
1528
|
-
includeSEO:
|
|
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
|
-
],
|
|
691
|
+
includeSEO: true,
|
|
1537
692
|
includeEditorVersion: true,
|
|
1538
693
|
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
694
|
}),
|
|
1546
695
|
],
|
|
1547
696
|
}
|
|
1548
697
|
```
|
|
1549
698
|
|
|
1550
|
-
|
|
1551
|
-
// payload.config.ts
|
|
1552
|
-
createPuckPlugin({
|
|
1553
|
-
pagesCollection: 'pages',
|
|
1554
|
-
autoGenerateCollection: false,
|
|
1555
|
-
})
|
|
1556
|
-
```
|
|
1557
|
-
|
|
1558
|
-
### Individual Field Imports
|
|
699
|
+
### Rendering Hybrid Pages
|
|
1559
700
|
|
|
1560
701
|
```typescript
|
|
1561
|
-
import {
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
}
|
|
1568
|
-
|
|
1569
|
-
const Pages: CollectionConfig = {
|
|
1570
|
-
slug: 'pages',
|
|
1571
|
-
fields: [
|
|
1572
|
-
puckDataField,
|
|
1573
|
-
editorVersionField,
|
|
1574
|
-
createPageLayoutField(myCustomLayouts),
|
|
1575
|
-
],
|
|
1576
|
-
}
|
|
702
|
+
import { HybridPageRenderer } from '@delmaredigital/payload-puck/render'
|
|
703
|
+
import { LegacyBlockRenderer } from '@/components/LegacyBlockRenderer'
|
|
704
|
+
|
|
705
|
+
<HybridPageRenderer
|
|
706
|
+
page={page}
|
|
707
|
+
config={puckConfig}
|
|
708
|
+
legacyRenderer={(blocks) => <LegacyBlockRenderer blocks={blocks} />}
|
|
709
|
+
/>
|
|
1577
710
|
```
|
|
1578
711
|
|
|
1579
|
-
|
|
712
|
+
---
|
|
1580
713
|
|
|
1581
|
-
|
|
714
|
+
## Advanced Configuration
|
|
1582
715
|
|
|
1583
|
-
|
|
716
|
+
### Plugin Options
|
|
717
|
+
|
|
718
|
+
| Option | Default | Description |
|
|
719
|
+
|--------|---------|-------------|
|
|
720
|
+
| `pagesCollection` | `'pages'` | Collection slug to use for pages |
|
|
721
|
+
| `autoGenerateCollection` | `true` | Create the collection if it doesn't exist, or add Puck fields to existing |
|
|
722
|
+
| `enableEndpoints` | `true` | Register API endpoints at `/api/puck/:collection` for the editor |
|
|
723
|
+
| `enableAdminView` | `true` | Register the Puck editor view in Payload admin |
|
|
724
|
+
| `adminViewPath` | `'/puck-editor'` | Path for the editor (full path: `/admin/puck-editor/:collection/:id`) |
|
|
725
|
+
| `pageTreeIntegration` | auto-detect | Integration with `@delmaredigital/payload-page-tree` |
|
|
726
|
+
| `layouts` | `undefined` | Layout definitions for page templates |
|
|
1584
727
|
|
|
1585
728
|
```typescript
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
729
|
+
createPuckPlugin({
|
|
730
|
+
pagesCollection: 'pages',
|
|
731
|
+
autoGenerateCollection: true,
|
|
732
|
+
enableEndpoints: true,
|
|
733
|
+
enableAdminView: true,
|
|
734
|
+
adminViewPath: '/puck-editor',
|
|
735
|
+
pageTreeIntegration: undefined, // auto-detects
|
|
1591
736
|
|
|
1592
|
-
|
|
1593
|
-
|
|
737
|
+
// Collection overrides (merged with generated collection)
|
|
738
|
+
collectionOverrides: {
|
|
739
|
+
admin: {
|
|
740
|
+
defaultColumns: ['title', 'slug', 'updatedAt'],
|
|
741
|
+
},
|
|
742
|
+
},
|
|
1594
743
|
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
}
|
|
744
|
+
// Access control
|
|
745
|
+
access: {
|
|
746
|
+
read: () => true,
|
|
747
|
+
create: ({ req }) => !!req.user,
|
|
748
|
+
update: ({ req }) => !!req.user,
|
|
749
|
+
delete: ({ req }) => !!req.user,
|
|
750
|
+
},
|
|
751
|
+
})
|
|
1604
752
|
```
|
|
1605
753
|
|
|
1606
|
-
|
|
754
|
+
### Custom API Routes (Advanced)
|
|
1607
755
|
|
|
1608
|
-
|
|
756
|
+
The built-in endpoints handle most use cases. Only disable them if you need custom authentication or middleware.
|
|
1609
757
|
|
|
1610
|
-
|
|
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'
|
|
758
|
+
If needed, three route factories are available:
|
|
1616
759
|
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
<PageRenderer
|
|
1623
|
-
config={puckConfig}
|
|
1624
|
-
data={page.puckData}
|
|
1625
|
-
layouts={siteLayouts}
|
|
1626
|
-
/>
|
|
1627
|
-
)
|
|
1628
|
-
}
|
|
760
|
+
| Factory | Route Pattern | Methods |
|
|
761
|
+
|---------|---------------|---------|
|
|
762
|
+
| `createPuckApiRoutes` | `/api/puck/[collection]` | GET (list), POST (create) |
|
|
763
|
+
| `createPuckApiRoutesWithId` | `/api/puck/[collection]/[id]` | GET, PATCH, DELETE |
|
|
764
|
+
| `createPuckApiRoutesVersions` | `/api/puck/[collection]/[id]/versions` | GET, POST (restore) |
|
|
1629
765
|
|
|
1630
|
-
|
|
1631
|
-
}
|
|
1632
|
-
```
|
|
766
|
+
See the JSDoc in `@delmaredigital/payload-puck/api` for usage examples.
|
|
1633
767
|
|
|
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` |
|
|
768
|
+
---
|
|
1657
769
|
|
|
1658
|
-
|
|
770
|
+
## Export Reference
|
|
771
|
+
|
|
772
|
+
| Export Path | Description |
|
|
773
|
+
|-------------|-------------|
|
|
774
|
+
| `@delmaredigital/payload-puck` | Plugin creation, field utilities |
|
|
775
|
+
| `@delmaredigital/payload-puck/plugin` | `createPuckPlugin` |
|
|
776
|
+
| `@delmaredigital/payload-puck/config` | `baseConfig`, `createConfig()`, `extendConfig()` |
|
|
777
|
+
| `@delmaredigital/payload-puck/config/editor` | `editorConfig` for editing |
|
|
778
|
+
| `@delmaredigital/payload-puck/client` | `PuckConfigProvider`, `usePuckConfig`, client components |
|
|
779
|
+
| `@delmaredigital/payload-puck/rsc` | `PuckEditorView` for Payload admin views |
|
|
780
|
+
| `@delmaredigital/payload-puck/render` | `PageRenderer`, `HybridPageRenderer` |
|
|
781
|
+
| `@delmaredigital/payload-puck/fields` | Custom Puck fields and CSS helpers |
|
|
782
|
+
| `@delmaredigital/payload-puck/components` | Component configs for custom configurations |
|
|
783
|
+
| `@delmaredigital/payload-puck/theme` | `ThemeProvider`, theme utilities |
|
|
784
|
+
| `@delmaredigital/payload-puck/layouts` | Layout definitions, `LayoutWrapper` |
|
|
785
|
+
| `@delmaredigital/payload-puck/api` | API route factories (for custom implementations) |
|
|
786
|
+
| `@delmaredigital/payload-puck/admin/client` | `EditWithPuckButton`, `EditWithPuckCell` |
|
|
1659
787
|
|
|
1660
788
|
---
|
|
1661
789
|
|
|
1662
790
|
## License
|
|
1663
791
|
|
|
1664
|
-
MIT
|
|
792
|
+
MIT
|