@delmaredigital/payload-puck 0.1.1 → 0.1.3
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/LICENSE +21 -73
- package/README.md +1 -22
- package/package.json +3 -2
- package/dist/AccordionClient.js.map +0 -1
- package/dist/AccordionClient.mjs.map +0 -1
- package/dist/AnimatedWrapper.js.map +0 -1
- package/dist/AnimatedWrapper.mjs.map +0 -1
- package/dist/admin/client.js.map +0 -1
- package/dist/admin/client.mjs.map +0 -1
- package/dist/admin/index.js.map +0 -1
- package/dist/admin/index.mjs.map +0 -1
- package/dist/api/index.js.map +0 -1
- package/dist/api/index.mjs.map +0 -1
- package/dist/components/index.css.map +0 -1
- package/dist/components/index.js.map +0 -1
- package/dist/components/index.mjs.map +0 -1
- package/dist/config/config.editor.css.map +0 -1
- package/dist/config/config.editor.js.map +0 -1
- package/dist/config/config.editor.mjs.map +0 -1
- package/dist/config/index.js.map +0 -1
- package/dist/config/index.mjs.map +0 -1
- package/dist/editor/index.js.map +0 -1
- package/dist/editor/index.mjs.map +0 -1
- package/dist/fields/index.css.map +0 -1
- package/dist/fields/index.js.map +0 -1
- package/dist/fields/index.mjs.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/index.mjs.map +0 -1
- package/dist/layouts/index.js.map +0 -1
- package/dist/layouts/index.mjs.map +0 -1
- package/dist/plugin/index.js.map +0 -1
- package/dist/plugin/index.mjs.map +0 -1
- package/dist/render/index.js.map +0 -1
- package/dist/render/index.mjs.map +0 -1
- package/dist/theme/index.js.map +0 -1
- package/dist/theme/index.mjs.map +0 -1
- package/dist/utils/index.js.map +0 -1
- package/dist/utils/index.mjs.map +0 -1
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/hooks/useScrollAnimation.ts","../src/fields/shared.ts","../src/components/AnimatedWrapper.tsx"],"names":[],"mappings":"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","file":"AnimatedWrapper.mjs","sourcesContent":["'use client'\n\n/**\n * useScrollAnimation - Hook for scroll-triggered animations\n *\n * Uses IntersectionObserver to detect when an element enters the viewport.\n * Perfect for triggering entrance animations, lazy loading, or scroll-based effects.\n */\n\nimport { useRef, useState, useEffect, useCallback } from 'react'\n\n// =============================================================================\n// Types\n// =============================================================================\n\nexport interface UseScrollAnimationOptions {\n /**\n * Whether to trigger animation on scroll into view.\n * If false, isInView will always be true.\n * @default true\n */\n triggerOnScroll?: boolean\n\n /**\n * Threshold for intersection (0-1).\n * 0 = trigger as soon as any pixel is visible.\n * 1 = trigger only when fully visible.\n * @default 0.1\n */\n threshold?: number\n\n /**\n * Whether to only trigger once.\n * If true, hasAnimated will stay true after first trigger.\n * @default true\n */\n once?: boolean\n\n /**\n * Root margin for intersection observer.\n * Allows triggering before/after the element enters the viewport.\n * @example \"-50px\" // Trigger 50px before entering viewport\n * @example \"100px 0px\" // 100px top/bottom, 0px left/right\n * @default \"0px\"\n */\n rootMargin?: string\n\n /**\n * Delay in milliseconds before setting isInView to true.\n * Useful for staggering animations.\n * @default 0\n */\n delay?: number\n}\n\nexport interface UseScrollAnimationResult<T extends HTMLElement = HTMLElement> {\n /**\n * Ref to attach to the element you want to observe\n */\n ref: React.RefObject<T | null>\n\n /**\n * Whether the element is currently in view\n */\n isInView: boolean\n\n /**\n * Whether the element has ever been in view\n * (useful for once-only animations)\n */\n hasAnimated: boolean\n\n /**\n * Manually reset the animation state\n */\n reset: () => void\n}\n\n// =============================================================================\n// Hook Implementation\n// =============================================================================\n\nexport function useScrollAnimation<T extends HTMLElement = HTMLElement>(\n options: UseScrollAnimationOptions = {}\n): UseScrollAnimationResult<T> {\n const {\n triggerOnScroll = true,\n threshold = 0.1,\n once = true,\n rootMargin = '0px',\n delay = 0,\n } = options\n\n const ref = useRef<T | null>(null)\n // Always start with isInView: false to allow initial → animate transition\n const [isInView, setIsInView] = useState(false)\n const [hasAnimated, setHasAnimated] = useState(false)\n const timeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null)\n const hasMountedRef = useRef(false)\n\n // Reset function\n const reset = useCallback(() => {\n setIsInView(false)\n setHasAnimated(false)\n hasMountedRef.current = false\n if (timeoutRef.current) {\n clearTimeout(timeoutRef.current)\n timeoutRef.current = null\n }\n }, [])\n\n useEffect(() => {\n // If not triggering on scroll, animate immediately after mount\n // Use requestAnimationFrame to ensure the initial state is rendered first\n if (!triggerOnScroll) {\n // Skip if already mounted (prevents re-triggering on re-renders)\n if (hasMountedRef.current) return\n hasMountedRef.current = true\n\n // Use double RAF to ensure browser has painted initial state\n requestAnimationFrame(() => {\n requestAnimationFrame(() => {\n if (delay > 0) {\n timeoutRef.current = setTimeout(() => {\n setIsInView(true)\n setHasAnimated(true)\n }, delay)\n } else {\n setIsInView(true)\n setHasAnimated(true)\n }\n })\n })\n return\n }\n\n // If once mode and already animated, skip observer setup\n if (once && hasAnimated) {\n return\n }\n\n const element = ref.current\n if (!element) return\n\n // Check if IntersectionObserver is available (SSR safety)\n if (typeof IntersectionObserver === 'undefined') {\n setIsInView(true)\n setHasAnimated(true)\n return\n }\n\n const observer = new IntersectionObserver(\n (entries) => {\n const [entry] = entries\n const inView = entry.isIntersecting\n\n if (inView) {\n if (delay > 0) {\n // Apply delay before setting isInView\n timeoutRef.current = setTimeout(() => {\n setIsInView(true)\n setHasAnimated(true)\n }, delay)\n } else {\n setIsInView(true)\n setHasAnimated(true)\n }\n\n // If once mode, disconnect observer after triggering\n if (once) {\n observer.disconnect()\n }\n } else if (!once) {\n // Only update isInView to false if not in once mode\n if (timeoutRef.current) {\n clearTimeout(timeoutRef.current)\n timeoutRef.current = null\n }\n setIsInView(false)\n }\n },\n {\n threshold,\n rootMargin,\n }\n )\n\n observer.observe(element)\n\n return () => {\n observer.disconnect()\n if (timeoutRef.current) {\n clearTimeout(timeoutRef.current)\n timeoutRef.current = null\n }\n }\n }, [triggerOnScroll, threshold, once, rootMargin, delay, hasAnimated])\n\n return {\n ref,\n isInView,\n hasAnimated,\n reset,\n }\n}\n","/**\n * Shared Puck Field Definitions\n *\n * Reusable field configurations and CSS utility maps for Puck components.\n * These ensure consistency across all components.\n */\n\nimport type { Field } from '@measured/puck'\nimport type React from 'react'\n\n// =============================================================================\n// Utility Functions\n// =============================================================================\n\n/**\n * Combines class names, filtering out falsy values\n * A simple alternative to clsx/classnames for bundling purposes\n */\nexport function cn(...classes: (string | boolean | undefined | null)[]): string {\n return classes.filter(Boolean).join(' ')\n}\n\n// =============================================================================\n// Custom Style Types\n// =============================================================================\n\nexport interface ColorValue {\n hex: string\n opacity?: number\n}\n\nexport interface PaddingValue {\n top: number\n right: number\n bottom: number\n left: number\n unit: 'px' | 'rem' | 'em' | '%'\n /** Whether all sides are linked (sync together). Defaults to true if not set. */\n linked?: boolean\n}\n\nexport interface BorderValue {\n style: 'none' | 'solid' | 'dashed' | 'dotted'\n width: number\n color: ColorValue | null\n radius: number\n sides: {\n top: boolean\n right: boolean\n bottom: boolean\n left: boolean\n }\n}\n\nexport interface WidthValue {\n mode: 'full' | 'contained' | 'custom'\n maxWidth: number\n unit: 'px' | 'rem' | '%' | 'vw'\n alignment: 'left' | 'center' | 'right'\n}\n\n// =============================================================================\n// Dimensions Types (Enhanced Width + Height)\n// =============================================================================\n\nexport type DimensionsUnit = 'px' | 'rem' | '%' | 'vw' | 'vh'\nexport type DimensionsMode = 'full' | 'contained' | 'custom'\nexport type ContentAlignment = 'left' | 'center' | 'right'\n\n/**\n * Represents a single dimension constraint (min or max for width or height)\n */\nexport interface DimensionConstraint {\n value: number\n unit: DimensionsUnit\n enabled: boolean\n}\n\n/**\n * Full dimensions configuration value - replaces/extends WidthValue\n * Supports min/max constraints for both width and height\n */\nexport interface DimensionsValue {\n /** Width mode: full (100%), contained (centered max-width), or custom */\n mode: DimensionsMode\n /** Content alignment within the container */\n alignment: ContentAlignment\n /** Minimum width constraint (optional) */\n minWidth?: DimensionConstraint | null\n /** Maximum width constraint (required for backward compat) */\n maxWidth: DimensionConstraint\n /** Minimum height constraint (optional) */\n minHeight?: DimensionConstraint | null\n /** Maximum height constraint (optional) */\n maxHeight?: DimensionConstraint | null\n /** UI state: whether advanced mode is expanded */\n advancedMode?: boolean\n}\n\n/**\n * Type guard to detect legacy WidthValue format\n */\nexport function isLegacyWidthValue(value: unknown): value is WidthValue {\n if (!value || typeof value !== 'object') return false\n const v = value as Record<string, unknown>\n return (\n typeof v.maxWidth === 'number' &&\n typeof v.unit === 'string' &&\n typeof v.mode === 'string' &&\n !('minWidth' in v) &&\n !('minHeight' in v) &&\n !('maxHeight' in v)\n )\n}\n\n/**\n * Migrate legacy WidthValue to new DimensionsValue format\n */\nexport function migrateWidthValue(legacy: WidthValue): DimensionsValue {\n return {\n mode: legacy.mode,\n alignment: legacy.alignment,\n maxWidth: {\n value: legacy.maxWidth,\n unit: legacy.unit,\n enabled: true,\n },\n advancedMode: false,\n }\n}\n\n// =============================================================================\n// Background Types\n// =============================================================================\n\nexport interface GradientStop {\n color: ColorValue\n position: number // 0-100%\n}\n\nexport interface GradientValue {\n type: 'linear' | 'radial'\n angle: number // 0-360 for linear\n stops: GradientStop[]\n radialShape?: 'circle' | 'ellipse'\n radialPosition?: 'center' | 'top' | 'bottom' | 'left' | 'right'\n}\n\n/**\n * Gradient mask for fading images to transparent\n */\nexport interface GradientMask {\n enabled: boolean\n direction:\n | 'to-top'\n | 'to-bottom'\n | 'to-left'\n | 'to-right'\n | 'to-top-left'\n | 'to-top-right'\n | 'to-bottom-left'\n | 'to-bottom-right'\n | 'from-center' // Radial gradient from center outward\n startOpacity: number // 0-100, typically 100 (fully visible)\n endOpacity: number // 0-100, typically 0 (fully transparent)\n startPosition: number // 0-100%, where fade begins\n endPosition: number // 0-100%, where fade ends\n}\n\nexport interface BackgroundImageValue {\n media: import('./MediaField').MediaReference | null\n size: 'cover' | 'contain' | 'auto'\n position:\n | 'center'\n | 'top'\n | 'bottom'\n | 'left'\n | 'right'\n | 'top-left'\n | 'top-right'\n | 'bottom-left'\n | 'bottom-right'\n repeat: 'no-repeat' | 'repeat' | 'repeat-x' | 'repeat-y'\n attachment: 'scroll' | 'fixed'\n /** Overall image opacity 0-100 (default 100) */\n opacity?: number\n /** Gradient mask for fade to transparent effect */\n mask?: GradientMask\n}\n\n/**\n * Overlay layer for images (Divi-style)\n * Renders a color or gradient on top of the background image\n */\nexport interface BackgroundOverlay {\n enabled: boolean\n type: 'solid' | 'gradient'\n solid?: ColorValue | null\n gradient?: GradientValue | null\n}\n\nexport interface BackgroundValue {\n type: 'none' | 'solid' | 'gradient' | 'image'\n solid?: ColorValue | null\n gradient?: GradientValue | null\n image?: BackgroundImageValue | null\n /** Overlay layer, only used when type === 'image' */\n overlay?: BackgroundOverlay | null\n}\n\n// =============================================================================\n// Visibility Field\n// =============================================================================\n\nexport const visibilityField: Field = {\n type: 'select',\n label: 'Visibility',\n options: [\n { label: 'Always Visible', value: 'always' },\n { label: 'Authenticated Users Only', value: 'authenticatedOnly' },\n { label: 'Guests Only', value: 'guestOnly' },\n ],\n}\n\n// =============================================================================\n// Button Style Field\n// =============================================================================\n\nexport const buttonStyleField: Field = {\n type: 'select',\n label: 'Button Style',\n options: [\n { label: 'Primary', value: 'primary' },\n { label: 'Secondary', value: 'secondary' },\n { label: 'Outline', value: 'outline' },\n { label: 'Ghost', value: 'ghost' },\n { label: 'Link', value: 'link' },\n ],\n}\n\n// =============================================================================\n// Button Variant Field\n// =============================================================================\n\nexport const buttonVariantField: Field = {\n type: 'select',\n label: 'Button Variant',\n options: [\n { label: 'Default', value: 'default' },\n { label: 'Destructive', value: 'destructive' },\n { label: 'Outline', value: 'outline' },\n { label: 'Secondary', value: 'secondary' },\n { label: 'Ghost', value: 'ghost' },\n { label: 'Link', value: 'link' },\n ],\n}\n\n// =============================================================================\n// Button Size Field\n// =============================================================================\n\nexport const buttonSizeField: Field = {\n type: 'select',\n label: 'Size',\n options: [\n { label: 'Small', value: 'sm' },\n { label: 'Default', value: 'default' },\n { label: 'Large', value: 'lg' },\n { label: 'Icon', value: 'icon' },\n ],\n}\n\n// =============================================================================\n// Background Color Field (Preset Palette)\n// =============================================================================\n\nexport const backgroundColorField: Field = {\n type: 'select',\n label: 'Background Color',\n options: [\n { label: 'None', value: 'none' },\n { label: 'Background', value: 'background' },\n { label: 'Card', value: 'card' },\n { label: 'Muted', value: 'muted' },\n { label: 'Primary', value: 'primary' },\n { label: 'Secondary', value: 'secondary' },\n { label: 'Accent', value: 'accent' },\n ],\n}\n\n// =============================================================================\n// Text Color Field (Preset Palette)\n// =============================================================================\n\nexport const textColorField: Field = {\n type: 'select',\n label: 'Text Color',\n options: [\n { label: 'Theme (Auto)', value: 'default' },\n { label: 'Foreground', value: 'foreground' },\n { label: 'Muted', value: 'muted-foreground' },\n { label: 'Primary', value: 'primary' },\n { label: 'Secondary', value: 'secondary-foreground' },\n ],\n}\n\n// =============================================================================\n// Gap/Spacing Field\n// =============================================================================\n\nexport const gapField: Field = {\n type: 'select',\n label: 'Gap',\n options: [\n { label: 'None', value: 'none' },\n { label: 'Extra Small', value: 'xs' },\n { label: 'Small', value: 'sm' },\n { label: 'Medium', value: 'md' },\n { label: 'Large', value: 'lg' },\n { label: 'Extra Large', value: 'xl' },\n { label: '2XL', value: '2xl' },\n ],\n}\n\n// =============================================================================\n// Shadow Field\n// =============================================================================\n\nexport const shadowField: Field = {\n type: 'select',\n label: 'Shadow',\n options: [\n { label: 'None', value: 'none' },\n { label: 'Small', value: 'sm' },\n { label: 'Medium', value: 'md' },\n { label: 'Large', value: 'lg' },\n { label: 'Extra Large', value: 'xl' },\n { label: '2XL', value: '2xl' },\n ],\n}\n\n// =============================================================================\n// Spacer Height Field\n// =============================================================================\n\nexport const spacerHeightField: Field = {\n type: 'select',\n label: 'Height',\n options: [\n { label: 'Extra Small (8px)', value: 'xs' },\n { label: 'Small (16px)', value: 'sm' },\n { label: 'Medium (32px)', value: 'md' },\n { label: 'Large (48px)', value: 'lg' },\n { label: 'Extra Large (64px)', value: 'xl' },\n { label: '2XL (96px)', value: '2xl' },\n { label: '3XL (128px)', value: '3xl' },\n ],\n}\n\n// =============================================================================\n// Heading Level Field\n// =============================================================================\n\nexport const headingLevelField: Field = {\n type: 'select',\n label: 'Heading Level',\n options: [\n { label: 'H1', value: 'h1' },\n { label: 'H2', value: 'h2' },\n { label: 'H3', value: 'h3' },\n { label: 'H4', value: 'h4' },\n { label: 'H5', value: 'h5' },\n { label: 'H6', value: 'h6' },\n ],\n}\n\n// =============================================================================\n// Text Size Field\n// =============================================================================\n\nexport const textSizeField: Field = {\n type: 'select',\n label: 'Text Size',\n options: [\n { label: 'Extra Small', value: 'xs' },\n { label: 'Small', value: 'sm' },\n { label: 'Base', value: 'base' },\n { label: 'Large', value: 'lg' },\n { label: 'Extra Large', value: 'xl' },\n { label: '2XL', value: '2xl' },\n ],\n}\n\n// =============================================================================\n// Aspect Ratio Field\n// =============================================================================\n\nexport const aspectRatioField: Field = {\n type: 'select',\n label: 'Aspect Ratio',\n options: [\n { label: 'Auto', value: 'auto' },\n { label: 'Square (1:1)', value: 'square' },\n { label: 'Video (16:9)', value: 'video' },\n { label: 'Portrait (3:4)', value: 'portrait' },\n { label: 'Landscape (4:3)', value: 'landscape' },\n { label: 'Wide (21:9)', value: 'wide' },\n ],\n}\n\n// =============================================================================\n// Divider Style Field\n// =============================================================================\n\nexport const dividerStyleField: Field = {\n type: 'select',\n label: 'Style',\n options: [\n { label: 'Solid', value: 'solid' },\n { label: 'Dashed', value: 'dashed' },\n { label: 'Dotted', value: 'dotted' },\n ],\n}\n\n// =============================================================================\n// Border Radius Field\n// =============================================================================\n\nexport const borderRadiusField: Field = {\n type: 'select',\n label: 'Border Radius',\n options: [\n { label: 'None', value: 'none' },\n { label: 'Small', value: 'sm' },\n { label: 'Medium', value: 'md' },\n { label: 'Large', value: 'lg' },\n { label: 'Extra Large', value: 'xl' },\n { label: '2XL', value: '2xl' },\n { label: 'Full', value: 'full' },\n ],\n}\n\n// =============================================================================\n// Columns Count Field\n// =============================================================================\n\nexport const columnsCountField: Field = {\n type: 'select',\n label: 'Columns',\n options: [\n { label: '1 Column', value: '1' },\n { label: '2 Columns', value: '2' },\n { label: '3 Columns', value: '3' },\n { label: '4 Columns', value: '4' },\n { label: '5 Columns', value: '5' },\n { label: '6 Columns', value: '6' },\n ],\n}\n\n// =============================================================================\n// Flex Direction Field\n// =============================================================================\n\nexport const flexDirectionField: Field = {\n type: 'select',\n label: 'Direction',\n options: [\n { label: 'Row (Horizontal)', value: 'row' },\n { label: 'Column (Vertical)', value: 'column' },\n { label: 'Row Reverse', value: 'row-reverse' },\n { label: 'Column Reverse', value: 'column-reverse' },\n ],\n}\n\n// =============================================================================\n// Flex Wrap Field\n// =============================================================================\n\nexport const flexWrapField: Field = {\n type: 'select',\n label: 'Wrap',\n options: [\n { label: 'No Wrap', value: 'nowrap' },\n { label: 'Wrap', value: 'wrap' },\n { label: 'Wrap Reverse', value: 'wrap-reverse' },\n ],\n}\n\n// =============================================================================\n// CSS Class Mappings\n// =============================================================================\n\n/**\n * Maps alignment values to Tailwind classes\n */\nexport const alignmentMap: Record<string, string> = {\n left: 'text-left',\n center: 'text-center',\n right: 'text-right',\n}\n\n/**\n * Maps background color values to Tailwind classes\n */\nexport const bgColorMap: Record<string, string> = {\n none: '',\n background: 'bg-background',\n card: 'bg-card',\n muted: 'bg-muted',\n primary: 'bg-primary',\n secondary: 'bg-secondary',\n accent: 'bg-accent',\n}\n\n/**\n * Maps text color values to Tailwind classes\n */\nexport const textColorMap: Record<string, string> = {\n default: 'text-inherit',\n foreground: 'text-foreground',\n 'muted-foreground': 'text-muted-foreground',\n primary: 'text-primary',\n 'secondary-foreground': 'text-secondary-foreground',\n}\n\n/**\n * Maps gap values to Tailwind classes\n */\nexport const gapMap: Record<string, string> = {\n none: 'gap-0',\n xs: 'gap-1',\n sm: 'gap-2',\n md: 'gap-4',\n lg: 'gap-6',\n xl: 'gap-8',\n '2xl': 'gap-12',\n}\n\n/**\n * Maps shadow values to Tailwind classes\n */\nexport const shadowMap: Record<string, string> = {\n none: '',\n sm: 'shadow-sm',\n md: 'shadow-md',\n lg: 'shadow-lg',\n xl: 'shadow-xl',\n '2xl': 'shadow-2xl',\n}\n\n/**\n * Maps spacer height values to Tailwind classes\n */\nexport const spacerHeightMap: Record<string, string> = {\n xs: 'h-2',\n sm: 'h-4',\n md: 'h-8',\n lg: 'h-12',\n xl: 'h-16',\n '2xl': 'h-24',\n '3xl': 'h-32',\n}\n\n/**\n * Maps heading level to Tailwind classes\n */\nexport const headingLevelMap: Record<string, string> = {\n h1: 'text-4xl md:text-5xl lg:text-6xl font-bold tracking-tight',\n h2: 'text-3xl md:text-4xl font-bold tracking-tight',\n h3: 'text-2xl md:text-3xl font-semibold',\n h4: 'text-xl md:text-2xl font-semibold',\n h5: 'text-lg md:text-xl font-medium',\n h6: 'text-base md:text-lg font-medium',\n}\n\n/**\n * Maps text size to Tailwind classes\n */\nexport const textSizeMap: Record<string, string> = {\n xs: 'text-xs',\n sm: 'text-sm',\n base: 'text-base',\n lg: 'text-lg',\n xl: 'text-xl',\n '2xl': 'text-2xl',\n}\n\n/**\n * Maps aspect ratio to Tailwind classes\n */\nexport const aspectRatioMap: Record<string, string> = {\n auto: '',\n square: 'aspect-square',\n video: 'aspect-video',\n portrait: 'aspect-[3/4]',\n landscape: 'aspect-[4/3]',\n wide: 'aspect-[21/9]',\n}\n\n/**\n * Maps divider style to Tailwind classes\n */\nexport const dividerStyleMap: Record<string, string> = {\n solid: 'border-solid',\n dashed: 'border-dashed',\n dotted: 'border-dotted',\n}\n\n/**\n * Maps border radius to Tailwind classes\n */\nexport const borderRadiusMap: Record<string, string> = {\n none: 'rounded-none',\n sm: 'rounded-sm',\n md: 'rounded-md',\n lg: 'rounded-lg',\n xl: 'rounded-xl',\n '2xl': 'rounded-2xl',\n full: 'rounded-full',\n}\n\n/**\n * Maps columns count to Tailwind grid classes (responsive)\n */\nexport const columnsCountMap: Record<string, string> = {\n '1': 'grid-cols-1',\n '2': 'grid-cols-1 md:grid-cols-2',\n '3': 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3',\n '4': 'grid-cols-1 md:grid-cols-2 lg:grid-cols-4',\n '5': 'grid-cols-2 md:grid-cols-3 lg:grid-cols-5',\n '6': 'grid-cols-2 md:grid-cols-3 lg:grid-cols-6',\n}\n\n/**\n * Maps flex direction to Tailwind classes\n */\nexport const flexDirectionMap: Record<string, string> = {\n row: 'flex-row',\n column: 'flex-col',\n 'row-reverse': 'flex-row-reverse',\n 'column-reverse': 'flex-col-reverse',\n}\n\n/**\n * Maps justify content to Tailwind classes\n * Supports both short (start) and full (flex-start) values\n */\nexport const justifyContentMap: Record<string, string> = {\n start: 'justify-start',\n 'flex-start': 'justify-start',\n center: 'justify-center',\n end: 'justify-end',\n 'flex-end': 'justify-end',\n between: 'justify-between',\n 'space-between': 'justify-between',\n around: 'justify-around',\n 'space-around': 'justify-around',\n evenly: 'justify-evenly',\n 'space-evenly': 'justify-evenly',\n}\n\n/**\n * Maps align items to Tailwind classes\n * Supports both short (start) and full (flex-start) values\n */\nexport const alignItemsMap: Record<string, string> = {\n start: 'items-start',\n 'flex-start': 'items-start',\n center: 'items-center',\n end: 'items-end',\n 'flex-end': 'items-end',\n stretch: 'items-stretch',\n baseline: 'items-baseline',\n}\n\n/**\n * Maps self-alignment to Tailwind classes (for grid/flex item alignment)\n * Used by components like TextImageSplit for vertical self-alignment\n */\nexport const selfAlignmentMap: Record<string, string> = {\n start: 'self-start',\n 'flex-start': 'self-start',\n center: 'self-center',\n end: 'self-end',\n 'flex-end': 'self-end',\n stretch: 'self-stretch',\n auto: 'self-auto',\n}\n\n/**\n * Maps flex wrap to Tailwind classes\n */\nexport const flexWrapMap: Record<string, string> = {\n nowrap: 'flex-nowrap',\n wrap: 'flex-wrap',\n 'wrap-reverse': 'flex-wrap-reverse',\n}\n\n// =============================================================================\n// Custom Style Value Utilities\n// =============================================================================\n\n/**\n * Convert hex color to RGB components\n */\nfunction hexToRgb(hex: string): { r: number; g: number; b: number } | null {\n const clean = hex.replace(/^#/, '')\n if (clean.length !== 6) return null\n\n const r = parseInt(clean.substring(0, 2), 16)\n const g = parseInt(clean.substring(2, 4), 16)\n const b = parseInt(clean.substring(4, 6), 16)\n\n if (isNaN(r) || isNaN(g) || isNaN(b)) return null\n\n return { r, g, b }\n}\n\n/**\n * Convert ColorValue to CSS rgba string\n */\nexport function colorValueToCSS(color: ColorValue | null | undefined): string | undefined {\n if (!color?.hex) return undefined\n\n const rgb = hexToRgb(color.hex)\n if (!rgb) return color.hex\n\n const opacity = (color.opacity ?? 100) / 100\n\n if (opacity === 1) {\n return color.hex\n }\n\n return `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${opacity})`\n}\n\n/**\n * Convert PaddingValue to CSS padding string\n */\nexport function paddingValueToCSS(padding: PaddingValue | null | undefined): string | undefined {\n if (!padding) return undefined\n\n const { top, right, bottom, left, unit } = padding\n\n if (top === right && right === bottom && bottom === left) {\n return `${top}${unit}`\n }\n\n if (top === bottom && left === right) {\n return `${top}${unit} ${right}${unit}`\n }\n\n if (left === right) {\n return `${top}${unit} ${right}${unit} ${bottom}${unit}`\n }\n\n return `${top}${unit} ${right}${unit} ${bottom}${unit} ${left}${unit}`\n}\n\n/**\n * Convert PaddingValue to CSS margin string (same structure, different property)\n */\nexport function marginValueToCSS(margin: PaddingValue | null | undefined): string | undefined {\n if (!margin) return undefined\n\n const { top, right, bottom, left, unit } = margin\n\n if (top === right && right === bottom && bottom === left) {\n return `${top}${unit}`\n }\n\n if (top === bottom && left === right) {\n return `${top}${unit} ${right}${unit}`\n }\n\n if (left === right) {\n return `${top}${unit} ${right}${unit} ${bottom}${unit}`\n }\n\n return `${top}${unit} ${right}${unit} ${bottom}${unit} ${left}${unit}`\n}\n\n/**\n * Convert BorderValue to CSS properties object\n */\nexport function borderValueToCSS(border: BorderValue | null | undefined): React.CSSProperties | undefined {\n if (!border || border.style === 'none') return undefined\n\n const color = colorValueToCSS(border.color) || '#000000'\n const style: React.CSSProperties = {}\n\n if (border.sides.top) {\n style.borderTopWidth = `${border.width}px`\n style.borderTopStyle = border.style\n style.borderTopColor = color\n }\n\n if (border.sides.right) {\n style.borderRightWidth = `${border.width}px`\n style.borderRightStyle = border.style\n style.borderRightColor = color\n }\n\n if (border.sides.bottom) {\n style.borderBottomWidth = `${border.width}px`\n style.borderBottomStyle = border.style\n style.borderBottomColor = color\n }\n\n if (border.sides.left) {\n style.borderLeftWidth = `${border.width}px`\n style.borderLeftStyle = border.style\n style.borderLeftColor = color\n }\n\n if (border.radius > 0) {\n style.borderRadius = `${border.radius}px`\n }\n\n return Object.keys(style).length > 0 ? style : undefined\n}\n\n/**\n * Convert WidthValue to CSS properties object\n */\nexport function widthValueToCSS(width: WidthValue | null | undefined): React.CSSProperties | undefined {\n if (!width) return undefined\n\n const style: React.CSSProperties = {}\n\n if (width.mode === 'full') {\n style.width = '100%'\n style.maxWidth = '100%'\n } else {\n style.maxWidth = `${width.maxWidth}${width.unit}`\n style.width = '100%'\n }\n\n switch (width.alignment) {\n case 'left':\n style.marginLeft = '0'\n style.marginRight = 'auto'\n break\n case 'center':\n style.marginLeft = 'auto'\n style.marginRight = 'auto'\n break\n case 'right':\n style.marginLeft = 'auto'\n style.marginRight = '0'\n break\n }\n\n return style\n}\n\n/**\n * Convert DimensionsValue to CSS properties object\n * Handles both legacy WidthValue and new DimensionsValue formats\n */\nexport function dimensionsValueToCSS(\n dimensions: DimensionsValue | WidthValue | null | undefined\n): React.CSSProperties | undefined {\n if (!dimensions) return undefined\n\n // Handle legacy WidthValue format\n if (isLegacyWidthValue(dimensions)) {\n return widthValueToCSS(dimensions)\n }\n\n const dim = dimensions as DimensionsValue\n const style: React.CSSProperties = {}\n\n // Width handling based on mode\n if (dim.mode === 'full') {\n style.width = '100%'\n style.maxWidth = '100%'\n } else {\n style.width = '100%'\n\n // Max Width (required)\n if (dim.maxWidth?.enabled !== false && dim.maxWidth?.value > 0) {\n style.maxWidth = `${dim.maxWidth.value}${dim.maxWidth.unit}`\n }\n\n // Min Width (optional)\n if (dim.minWidth?.enabled && dim.minWidth.value > 0) {\n style.minWidth = `${dim.minWidth.value}${dim.minWidth.unit}`\n }\n }\n\n // Height handling (applies to all modes)\n if (dim.minHeight?.enabled && dim.minHeight.value > 0) {\n style.minHeight = `${dim.minHeight.value}${dim.minHeight.unit}`\n }\n\n if (dim.maxHeight?.enabled && dim.maxHeight.value > 0) {\n style.maxHeight = `${dim.maxHeight.value}${dim.maxHeight.unit}`\n }\n\n // Alignment (via margin)\n switch (dim.alignment) {\n case 'left':\n style.marginLeft = '0'\n style.marginRight = 'auto'\n break\n case 'center':\n style.marginLeft = 'auto'\n style.marginRight = 'auto'\n break\n case 'right':\n style.marginLeft = 'auto'\n style.marginRight = '0'\n break\n }\n\n return style\n}\n\n/**\n * Get human-readable summary of dimensions\n */\nexport function getDimensionsSummary(dim: DimensionsValue | null | undefined): string {\n if (!dim) return 'auto'\n\n if (dim.mode === 'full') return '100%'\n\n const parts: string[] = []\n\n if (dim.maxWidth?.enabled && dim.maxWidth.value > 0) {\n parts.push(`max: ${dim.maxWidth.value}${dim.maxWidth.unit}`)\n }\n\n if (dim.minWidth?.enabled && dim.minWidth.value > 0) {\n parts.push(`min: ${dim.minWidth.value}${dim.minWidth.unit}`)\n }\n\n if (dim.maxHeight?.enabled && dim.maxHeight.value > 0) {\n parts.push(`h-max: ${dim.maxHeight.value}${dim.maxHeight.unit}`)\n }\n\n if (dim.minHeight?.enabled && dim.minHeight.value > 0) {\n parts.push(`h-min: ${dim.minHeight.value}${dim.minHeight.unit}`)\n }\n\n return parts.length > 0 ? parts.join(' | ') : 'auto'\n}\n\n/**\n * Combined style generator for layout components\n */\nexport function getCustomStyleObject(options: {\n backgroundColor?: ColorValue | null\n textColor?: ColorValue | null\n padding?: PaddingValue | null\n margin?: PaddingValue | null\n border?: BorderValue | null\n width?: WidthValue | null\n}): React.CSSProperties {\n const style: React.CSSProperties = {}\n\n const bgColor = colorValueToCSS(options.backgroundColor)\n if (bgColor) {\n style.backgroundColor = bgColor\n }\n\n const txtColor = colorValueToCSS(options.textColor)\n if (txtColor) {\n style.color = txtColor\n }\n\n const paddingCSS = paddingValueToCSS(options.padding)\n if (paddingCSS) {\n style.padding = paddingCSS\n }\n\n const marginCSS = marginValueToCSS(options.margin)\n if (marginCSS) {\n style.margin = marginCSS\n }\n\n const borderCSS = borderValueToCSS(options.border)\n if (borderCSS) {\n Object.assign(style, borderCSS)\n }\n\n const widthCSS = widthValueToCSS(options.width)\n if (widthCSS) {\n Object.assign(style, widthCSS)\n }\n\n return style\n}\n\n/**\n * Convert GradientValue to CSS gradient string\n */\nexport function gradientValueToCSS(gradient: GradientValue | null | undefined): string {\n if (!gradient?.stops || gradient.stops.length === 0) {\n return 'transparent'\n }\n\n // Sort stops by position\n const sortedStops = [...gradient.stops].sort((a, b) => a.position - b.position)\n\n // Convert stops to CSS format\n const stopsCSS = sortedStops\n .map((stop) => {\n const color = colorValueToCSS(stop.color) || 'transparent'\n return `${color} ${stop.position}%`\n })\n .join(', ')\n\n if (gradient.type === 'radial') {\n const shape = gradient.radialShape || 'circle'\n const position = gradient.radialPosition || 'center'\n return `radial-gradient(${shape} at ${position}, ${stopsCSS})`\n }\n\n // Linear gradient\n return `linear-gradient(${gradient.angle}deg, ${stopsCSS})`\n}\n\n/**\n * Convert position value to CSS background-position\n */\nfunction positionToCSS(\n position: BackgroundImageValue['position'] | undefined\n): string {\n const positionMap: Record<NonNullable<BackgroundImageValue['position']>, string> = {\n center: 'center',\n top: 'top',\n bottom: 'bottom',\n left: 'left',\n right: 'right',\n 'top-left': 'top left',\n 'top-right': 'top right',\n 'bottom-left': 'bottom left',\n 'bottom-right': 'bottom right',\n }\n return position ? positionMap[position] || 'center' : 'center'\n}\n\n/**\n * Convert GradientMask direction to CSS gradient direction\n */\nfunction maskDirectionToCSS(direction: GradientMask['direction']): string {\n const directionMap: Record<GradientMask['direction'], string> = {\n 'to-top': 'to top',\n 'to-bottom': 'to bottom',\n 'to-left': 'to left',\n 'to-right': 'to right',\n 'to-top-left': 'to top left',\n 'to-top-right': 'to top right',\n 'to-bottom-left': 'to bottom left',\n 'to-bottom-right': 'to bottom right',\n 'from-center': 'radial', // Not used for linear, handled separately in maskToCSS\n }\n return directionMap[direction] || 'to bottom'\n}\n\n/**\n * Convert GradientMask to CSS mask-image string\n */\nfunction maskToCSS(mask: GradientMask): string {\n const startAlpha = (mask.startOpacity ?? 100) / 100\n const endAlpha = (mask.endOpacity ?? 0) / 100\n\n // Handle radial gradient for \"from-center\"\n if (mask.direction === 'from-center') {\n return `radial-gradient(circle at center, rgba(0,0,0,${startAlpha}) ${mask.startPosition}%, rgba(0,0,0,${endAlpha}) ${mask.endPosition}%)`\n }\n\n // Linear gradient for directional fades\n const direction = maskDirectionToCSS(mask.direction)\n return `linear-gradient(${direction}, rgba(0,0,0,${startAlpha}) ${mask.startPosition}%, rgba(0,0,0,${endAlpha}) ${mask.endPosition}%)`\n}\n\n/**\n * Result of background CSS conversion\n * Includes both styles and metadata for consumer components\n */\nexport interface BackgroundCSSResult {\n /** CSS properties to apply directly */\n styles: React.CSSProperties\n /** Image opacity (0-1) - consumer should apply via wrapper if needed */\n imageOpacity?: number\n}\n\n/**\n * Convert BackgroundValue to CSS properties object\n * Returns both styles and metadata for advanced features like image opacity\n */\nexport function backgroundValueToCSS(\n bg: BackgroundValue | null | undefined\n): React.CSSProperties {\n if (!bg || bg.type === 'none') {\n return {}\n }\n\n const style: React.CSSProperties = {}\n\n switch (bg.type) {\n case 'solid':\n if (bg.solid?.hex) {\n style.backgroundColor = colorValueToCSS(bg.solid)\n }\n break\n\n case 'gradient':\n if (bg.gradient && bg.gradient.stops && bg.gradient.stops.length > 0) {\n style.background = gradientValueToCSS(bg.gradient)\n }\n break\n\n case 'image':\n if (bg.image?.media?.url) {\n const imageUrl = bg.image.media.url\n const size = bg.image.size || 'cover'\n const position = positionToCSS(bg.image.position)\n const repeat = bg.image.repeat || 'no-repeat'\n const attachment = bg.image.attachment || 'scroll'\n\n // Check if overlay is enabled\n if (bg.overlay?.enabled) {\n // Layer overlay on top of image using CSS multiple backgrounds\n // Use only backgroundImage to avoid shorthand/longhand conflicts\n const overlayCSS =\n bg.overlay.type === 'solid'\n ? colorValueToCSS(bg.overlay.solid)\n : gradientValueToCSS(bg.overlay.gradient)\n\n // CSS background layering: first layer is on top\n // For solid color overlay, we need to use a gradient to make it a proper layer\n if (bg.overlay.type === 'solid' && overlayCSS) {\n style.backgroundImage = `linear-gradient(${overlayCSS}, ${overlayCSS}), url(${imageUrl})`\n } else {\n style.backgroundImage = `${overlayCSS}, url(${imageUrl})`\n }\n // Use comma-separated values for each layer\n style.backgroundSize = `auto, ${size}`\n style.backgroundPosition = `center, ${position}`\n style.backgroundRepeat = `no-repeat, ${repeat}`\n style.backgroundAttachment = `scroll, ${attachment}`\n } else {\n // No overlay, just the image\n style.backgroundImage = `url(${imageUrl})`\n style.backgroundSize = size\n style.backgroundPosition = position\n style.backgroundRepeat = repeat\n style.backgroundAttachment = attachment\n }\n\n // Apply gradient mask if enabled\n if (bg.image.mask?.enabled) {\n const maskCSS = maskToCSS(bg.image.mask)\n style.maskImage = maskCSS\n // Webkit prefix for Safari support\n ;(style as Record<string, string>).WebkitMaskImage = maskCSS\n }\n }\n break\n }\n\n return style\n}\n\n/**\n * Get image opacity from BackgroundValue (for consumer wrapper components)\n * Returns undefined if no image or opacity is 100%\n */\nexport function getBackgroundImageOpacity(\n bg: BackgroundValue | null | undefined\n): number | undefined {\n if (!bg || bg.type !== 'image' || !bg.image) return undefined\n const opacity = bg.image.opacity ?? 100\n return opacity < 100 ? opacity / 100 : undefined\n}\n\n/**\n * Check if any custom style values are set\n */\nexport function hasCustomStyles(options: {\n backgroundColor?: ColorValue | null\n textColor?: ColorValue | null\n padding?: PaddingValue | null\n margin?: PaddingValue | null\n border?: BorderValue | null\n width?: WidthValue | null\n}): boolean {\n return !!(\n options.backgroundColor?.hex ||\n options.textColor?.hex ||\n options.padding ||\n options.margin ||\n (options.border && options.border.style !== 'none') ||\n options.width\n )\n}\n\n// =============================================================================\n// Transform Types\n// =============================================================================\n\nexport type TransformOrigin =\n | 'center'\n | 'top'\n | 'bottom'\n | 'left'\n | 'right'\n | 'top-left'\n | 'top-right'\n | 'bottom-left'\n | 'bottom-right'\n\nexport interface TransformValue {\n rotate: number // -360 to 360\n scaleX: number // 0.1 to 3\n scaleY: number // 0.1 to 3\n scaleLocked: boolean // When true, X and Y sync\n skewX: number // -45 to 45\n skewY: number // -45 to 45\n translateX: number\n translateY: number\n translateUnit: 'px' | 'rem' | '%'\n origin: TransformOrigin\n\n // Optional 3D\n enable3D: boolean\n perspective?: number // 100-2000px\n rotateX?: number // -180 to 180\n rotateY?: number // -180 to 180\n}\n\n/**\n * Default transform value\n */\nexport const DEFAULT_TRANSFORM: TransformValue = {\n rotate: 0,\n scaleX: 1,\n scaleY: 1,\n scaleLocked: true,\n skewX: 0,\n skewY: 0,\n translateX: 0,\n translateY: 0,\n translateUnit: 'px',\n origin: 'center',\n enable3D: false,\n perspective: 1000,\n rotateX: 0,\n rotateY: 0,\n}\n\n/**\n * Convert TransformOrigin to CSS transform-origin value\n */\nfunction transformOriginToCSS(origin: TransformOrigin): string {\n const originMap: Record<TransformOrigin, string> = {\n center: 'center',\n top: 'top',\n bottom: 'bottom',\n left: 'left',\n right: 'right',\n 'top-left': 'top left',\n 'top-right': 'top right',\n 'bottom-left': 'bottom left',\n 'bottom-right': 'bottom right',\n }\n return originMap[origin] || 'center'\n}\n\n/**\n * Convert TransformValue to CSS properties object\n */\nexport function transformValueToCSS(\n transform: TransformValue | null | undefined\n): React.CSSProperties | undefined {\n if (!transform) return undefined\n\n const style: React.CSSProperties = {}\n const transforms: string[] = []\n\n // Handle 3D perspective\n if (transform.enable3D && transform.perspective) {\n style.perspective = `${transform.perspective}px`\n }\n\n // Build transform string\n // Translate\n if (transform.translateX !== 0 || transform.translateY !== 0) {\n transforms.push(\n `translate(${transform.translateX}${transform.translateUnit}, ${transform.translateY}${transform.translateUnit})`\n )\n }\n\n // Rotate (2D)\n if (transform.rotate !== 0) {\n transforms.push(`rotate(${transform.rotate}deg)`)\n }\n\n // 3D rotations\n if (transform.enable3D) {\n if (transform.rotateX && transform.rotateX !== 0) {\n transforms.push(`rotateX(${transform.rotateX}deg)`)\n }\n if (transform.rotateY && transform.rotateY !== 0) {\n transforms.push(`rotateY(${transform.rotateY}deg)`)\n }\n }\n\n // Scale\n if (transform.scaleX !== 1 || transform.scaleY !== 1) {\n if (transform.scaleX === transform.scaleY) {\n transforms.push(`scale(${transform.scaleX})`)\n } else {\n transforms.push(`scale(${transform.scaleX}, ${transform.scaleY})`)\n }\n }\n\n // Skew\n if (transform.skewX !== 0 || transform.skewY !== 0) {\n if (transform.skewX !== 0 && transform.skewY !== 0) {\n transforms.push(`skew(${transform.skewX}deg, ${transform.skewY}deg)`)\n } else if (transform.skewX !== 0) {\n transforms.push(`skewX(${transform.skewX}deg)`)\n } else {\n transforms.push(`skewY(${transform.skewY}deg)`)\n }\n }\n\n // Apply transform if we have any\n if (transforms.length > 0) {\n style.transform = transforms.join(' ')\n }\n\n // Transform origin\n if (transform.origin !== 'center') {\n style.transformOrigin = transformOriginToCSS(transform.origin)\n }\n\n // Add transform-style for 3D\n if (transform.enable3D) {\n style.transformStyle = 'preserve-3d'\n }\n\n return Object.keys(style).length > 0 ? style : undefined\n}\n\n// =============================================================================\n// Responsive Field Types\n// =============================================================================\n\nexport type Breakpoint = 'xs' | 'sm' | 'md' | 'lg' | 'xl'\n\n/**\n * Responsive value that can have different values at different breakpoints.\n * XS (extra small) is required, other breakpoints are optional overrides.\n */\nexport interface ResponsiveValue<T> {\n xs: T\n sm?: T\n md?: T\n lg?: T\n xl?: T\n}\n\n/**\n * Breakpoint configuration with labels and pixel values\n */\nexport const BREAKPOINTS: Array<{\n key: Breakpoint\n label: string\n minWidth: number | null\n}> = [\n { key: 'xs', label: 'XS', minWidth: null },\n { key: 'sm', label: 'SM', minWidth: 640 },\n { key: 'md', label: 'MD', minWidth: 768 },\n { key: 'lg', label: 'LG', minWidth: 1024 },\n { key: 'xl', label: 'XL', minWidth: 1280 },\n]\n\n// =============================================================================\n// Responsive CSS Helpers\n// =============================================================================\n\n/**\n * Type guard to check if a value is a ResponsiveValue (has breakpoint structure)\n */\nexport function isResponsiveValue<T>(value: unknown): value is ResponsiveValue<T> {\n if (!value || typeof value !== 'object') return false\n return 'xs' in value\n}\n\n/**\n * Converts a camelCase property name to kebab-case CSS property\n */\nfunction camelToKebab(str: string): string {\n return str.replace(/[A-Z]/g, (letter) => `-${letter.toLowerCase()}`)\n}\n\n/**\n * Converts React.CSSProperties to a CSS string for use in style tags\n */\nexport function cssPropertiesToString(styles: React.CSSProperties): string {\n return Object.entries(styles)\n .filter(([, value]) => value !== undefined && value !== null && value !== '')\n .map(([key, value]) => `${camelToKebab(key)}: ${value}`)\n .join('; ')\n}\n\n/**\n * Result of converting a responsive value to CSS\n */\nexport interface ResponsiveCSSResult {\n /** Base styles to apply as inline styles */\n baseStyles: React.CSSProperties\n /** CSS media queries to render in a <style> tag */\n mediaQueryCSS: string\n}\n\n/**\n * Converts a ResponsiveValue to CSS with media queries.\n * Works with any value type that has a CSS converter function.\n *\n * @param value - The responsive or non-responsive value\n * @param converter - Function to convert the value type to CSSProperties\n * @param uniqueId - Unique class name for targeting in media queries\n * @returns Object with baseStyles (inline) and mediaQueryCSS (for <style> tag)\n *\n * @example\n * ```tsx\n * const { baseStyles, mediaQueryCSS } = responsiveValueToCSS(\n * dimensions,\n * dimensionsValueToCSS,\n * 'container-abc123'\n * )\n *\n * return (\n * <>\n * {mediaQueryCSS && <style>{mediaQueryCSS}</style>}\n * <div className=\"container-abc123\" style={baseStyles}>...</div>\n * </>\n * )\n * ```\n */\nexport function responsiveValueToCSS<T>(\n value: ResponsiveValue<T> | T | null | undefined,\n converter: (v: T) => React.CSSProperties | undefined,\n uniqueId: string\n): ResponsiveCSSResult {\n // Handle null/undefined\n if (value === null || value === undefined) {\n return { baseStyles: {}, mediaQueryCSS: '' }\n }\n\n // If not responsive (single value), return as base styles only\n if (!isResponsiveValue<T>(value)) {\n const styles = converter(value as T)\n return {\n baseStyles: styles || {},\n mediaQueryCSS: '',\n }\n }\n\n // Generate media queries for each breakpoint\n const mediaQueries: string[] = []\n let baseStyles: React.CSSProperties = {}\n\n BREAKPOINTS.forEach((bp) => {\n const bpValue = value[bp.key]\n if (bpValue === undefined) return\n\n const cssProps = converter(bpValue)\n if (!cssProps) return\n\n if (bp.key === 'xs') {\n baseStyles = cssProps\n } else {\n const styleString = cssPropertiesToString(cssProps)\n if (styleString) {\n mediaQueries.push(\n `@media (min-width: ${bp.minWidth}px) { .${uniqueId} { ${styleString} } }`\n )\n }\n }\n })\n\n return { baseStyles, mediaQueryCSS: mediaQueries.join('\\n') }\n}\n\n/**\n * Visibility value for show/hide per breakpoint\n */\nexport interface VisibilityValue {\n /** XS (extra small) visibility - true = visible, false = hidden (default: true) */\n xs: boolean\n /** Small screens (640px+) */\n sm?: boolean\n /** Override for medium screens (768px+) */\n md?: boolean\n /** Override for large screens (1024px+) */\n lg?: boolean\n /** Override for extra large screens (1280px+) */\n xl?: boolean\n}\n\n/**\n * Default visibility value (visible at all breakpoints)\n */\nexport const DEFAULT_VISIBILITY: VisibilityValue = {\n xs: true,\n sm: true,\n md: true,\n lg: true,\n xl: true,\n}\n\n/**\n * Converts a VisibilityValue to CSS with display: none media queries.\n * Each breakpoint is independent - generates targeted media queries for hidden breakpoints.\n *\n * @param visibility - The visibility settings per breakpoint\n * @param uniqueId - Unique class name for targeting in media queries\n * @returns CSS media queries string for hiding at specific breakpoints\n */\nexport function visibilityValueToCSS(\n visibility: VisibilityValue | null | undefined,\n uniqueId: string\n): string {\n if (!visibility) return ''\n\n const mediaQueries: string[] = []\n\n // Breakpoint min-widths for range calculations\n const breakpointWidths: Record<Breakpoint, number | null> = {\n xs: null, // 0px\n sm: 640,\n md: 768,\n lg: 1024,\n xl: 1280,\n }\n\n // Get next breakpoint's min-width for max-width calculation\n const getNextBreakpointWidth = (bp: Breakpoint): number | null => {\n const order: Breakpoint[] = ['xs', 'sm', 'md', 'lg', 'xl']\n const index = order.indexOf(bp)\n if (index === -1 || index === order.length - 1) return null\n return breakpointWidths[order[index + 1]]\n }\n\n // XS (0 to 639px)\n if (visibility.xs === false) {\n const nextWidth = getNextBreakpointWidth('xs')\n if (nextWidth) {\n mediaQueries.push(`@media (max-width: ${nextWidth - 1}px) { .${uniqueId} { display: none; } }`)\n } else {\n mediaQueries.push(`.${uniqueId} { display: none; }`)\n }\n }\n\n // Other breakpoints (sm, md, lg, xl)\n BREAKPOINTS.slice(1).forEach((bp) => {\n if (visibility[bp.key] === false) {\n const minWidth = breakpointWidths[bp.key]\n const maxWidth = getNextBreakpointWidth(bp.key)\n\n if (minWidth && maxWidth) {\n // Range query (e.g., sm: 640-767px)\n mediaQueries.push(\n `@media (min-width: ${minWidth}px) and (max-width: ${maxWidth - 1}px) { .${uniqueId} { display: none; } }`\n )\n } else if (minWidth) {\n // Last breakpoint (xl: 1280px+)\n mediaQueries.push(\n `@media (min-width: ${minWidth}px) { .${uniqueId} { display: none; } }`\n )\n }\n }\n })\n\n return mediaQueries.join('\\n')\n}\n\n// =============================================================================\n// Animation Types\n// =============================================================================\n\n/** Standard CSS easing functions */\nexport type EasingFunction = 'linear' | 'ease' | 'ease-in' | 'ease-out' | 'ease-in-out'\n\n/** Advanced easing with spring/bounce effects via cubic-bezier approximations */\nexport type AdvancedEasingFunction =\n | EasingFunction\n | 'spring'\n | 'spring-gentle'\n | 'bounce'\n | 'bounce-in'\n | 'bounce-out'\n | 'back-in'\n | 'back-out'\n | 'back-in-out'\n | 'elastic'\n\n/** Map advanced easing to CSS cubic-bezier values */\nexport const EASING_CSS_MAP: Record<AdvancedEasingFunction, string> = {\n linear: 'linear',\n ease: 'ease',\n 'ease-in': 'ease-in',\n 'ease-out': 'ease-out',\n 'ease-in-out': 'ease-in-out',\n spring: 'cubic-bezier(0.175, 0.885, 0.32, 1.275)',\n 'spring-gentle': 'cubic-bezier(0.34, 1.56, 0.64, 1)',\n bounce: 'cubic-bezier(0.68, -0.55, 0.265, 1.55)',\n 'bounce-in': 'cubic-bezier(0.6, -0.28, 0.735, 0.045)',\n 'bounce-out': 'cubic-bezier(0.175, 0.885, 0.32, 1.275)',\n 'back-in': 'cubic-bezier(0.6, -0.28, 0.735, 0.045)',\n 'back-out': 'cubic-bezier(0.175, 0.885, 0.32, 1.275)',\n 'back-in-out': 'cubic-bezier(0.68, -0.55, 0.265, 1.55)',\n elastic: 'cubic-bezier(0.68, -0.6, 0.32, 1.6)',\n}\n\n/** Transform origin for animations (3x3 grid) */\nexport type AnimationOrigin =\n | 'center'\n | 'top'\n | 'bottom'\n | 'left'\n | 'right'\n | 'top-left'\n | 'top-right'\n | 'bottom-left'\n | 'bottom-right'\n\n/** Stagger direction for child animations */\nexport type StaggerDirection = 'forward' | 'reverse' | 'center' | 'edges'\n\n/** Configuration for staggered child animations */\nexport interface StaggerConfig {\n enabled: boolean\n /** Delay between each child element (ms) */\n delay: number\n /** Maximum total delay to prevent very long animations */\n maxDelay?: number\n /** Direction of stagger effect */\n direction: StaggerDirection\n}\n\n/** Animation categories for UI organization */\nexport type AnimationCategory =\n | 'fade'\n | 'scale'\n | 'slide'\n | 'blur'\n | 'rotate'\n | 'bounce'\n | 'flip'\n | 'zoom'\n\n/**\n * Extended entrance animation presets (27 total)\n * Organized by category for the UI dropdown\n */\nexport type EntranceAnimation =\n // None\n | 'none'\n // Fade (6)\n | 'fade-in'\n | 'fade-up'\n | 'fade-down'\n | 'fade-left'\n | 'fade-right'\n | 'fade-scale'\n // Scale (4)\n | 'scale-in'\n | 'scale-up'\n | 'scale-down'\n | 'scale-out'\n // Slide (4)\n | 'slide-up'\n | 'slide-down'\n | 'slide-left'\n | 'slide-right'\n // Blur (3)\n | 'blur-in'\n | 'blur-up'\n | 'blur-down'\n // Rotate (3)\n | 'rotate-in'\n | 'rotate-up'\n | 'rotate-down'\n // Bounce (3)\n | 'bounce-in'\n | 'bounce-up'\n | 'bounce-down'\n // Flip (2)\n | 'flip-x'\n | 'flip-y'\n // Zoom (2)\n | 'zoom-in'\n | 'zoom-out'\n\n/**\n * Animation presets organized by category for UI\n */\nexport const ANIMATION_CATEGORIES: Array<{\n category: AnimationCategory | 'none'\n label: string\n animations: EntranceAnimation[]\n}> = [\n { category: 'none', label: 'None', animations: ['none'] },\n { category: 'fade', label: 'Fade', animations: ['fade-in', 'fade-up', 'fade-down', 'fade-left', 'fade-right', 'fade-scale'] },\n { category: 'scale', label: 'Scale', animations: ['scale-in', 'scale-up', 'scale-down', 'scale-out'] },\n { category: 'slide', label: 'Slide', animations: ['slide-up', 'slide-down', 'slide-left', 'slide-right'] },\n { category: 'blur', label: 'Blur', animations: ['blur-in', 'blur-up', 'blur-down'] },\n { category: 'rotate', label: 'Rotate', animations: ['rotate-in', 'rotate-up', 'rotate-down'] },\n { category: 'bounce', label: 'Bounce', animations: ['bounce-in', 'bounce-up', 'bounce-down'] },\n { category: 'flip', label: 'Flip', animations: ['flip-x', 'flip-y'] },\n { category: 'zoom', label: 'Zoom', animations: ['zoom-in', 'zoom-out'] },\n]\n\nexport interface AnimationValue {\n mode: 'preset' | 'custom'\n\n // Preset mode\n entrance?: EntranceAnimation\n entranceDuration?: number // ms\n entranceDelay?: number // ms\n\n // Intensity controls (context-aware based on animation type)\n /** Distance for translate animations (8-200px) */\n distance?: number\n /** Starting scale for scale animations (0.1-2) */\n scaleFrom?: number\n /** Rotation angle for rotate animations (-180 to 180deg) */\n rotateAngle?: number\n /** Blur amount for blur animations (0-50px) */\n blurAmount?: number\n\n // Transform origin (affects scale/rotate)\n origin?: AnimationOrigin\n\n // Advanced easing\n easing?: AdvancedEasingFunction\n\n // Stagger for child elements\n stagger?: StaggerConfig\n\n // Custom transition mode\n duration?: number // 0-2000ms\n delay?: number // 0-2000ms\n\n // Scroll trigger\n triggerOnScroll?: boolean\n triggerThreshold?: number // 0-1\n triggerOnce?: boolean\n /** Margin around viewport for earlier/later triggering (e.g., \"0px 0px -100px 0px\") */\n triggerMargin?: string\n}\n\n// =============================================================================\n// Animation CSS Utilities\n// =============================================================================\n\n/**\n * Convert AnimationOrigin to CSS transform-origin value\n */\nfunction animationOriginToCSS(origin: AnimationOrigin | undefined): string {\n if (!origin) return 'center'\n const originMap: Record<AnimationOrigin, string> = {\n center: 'center',\n top: 'top',\n bottom: 'bottom',\n left: 'left',\n right: 'right',\n 'top-left': 'top left',\n 'top-right': 'top right',\n 'bottom-left': 'bottom left',\n 'bottom-right': 'bottom right',\n }\n return originMap[origin] || 'center'\n}\n\n/**\n * Convert AnimationValue to CSS transition property (for custom mode)\n * Returns undefined for preset mode - use getEntranceAnimationStyles instead\n */\nexport function animationValueToCSS(anim: AnimationValue | null): React.CSSProperties | undefined {\n if (!anim || anim.mode !== 'custom') return undefined\n\n const duration = anim.duration ?? 300\n const delay = anim.delay ?? 0\n const easing = anim.easing ?? 'ease'\n const easingCSS = EASING_CSS_MAP[easing] || 'ease'\n\n return {\n transition: `all ${duration}ms ${easingCSS} ${delay}ms`,\n transitionProperty: 'opacity, transform, filter, background-color, color, border-color, box-shadow',\n }\n}\n\n/**\n * Get initial and animate styles for entrance animations\n * Returns inline CSS style objects that work without Tailwind compilation\n * Supports all 27 animation presets with customizable intensity\n */\nexport function getEntranceAnimationStyles(anim: AnimationValue | null): {\n initial: React.CSSProperties\n animate: React.CSSProperties\n duration: number\n delay: number\n easing: string\n origin: string\n} {\n const defaultResult = {\n initial: {} as React.CSSProperties,\n animate: {} as React.CSSProperties,\n duration: 500,\n delay: 0,\n easing: 'ease',\n origin: 'center',\n }\n\n if (!anim || anim.mode !== 'preset' || anim.entrance === 'none') {\n return defaultResult\n }\n\n const duration = anim.entranceDuration ?? 500\n const delay = anim.entranceDelay ?? 0\n const easing = EASING_CSS_MAP[anim.easing ?? 'ease'] || 'ease'\n const origin = animationOriginToCSS(anim.origin)\n\n // Intensity values with defaults\n const distance = anim.distance ?? 24 // px\n const scaleFrom = anim.scaleFrom ?? 0.9\n const rotateAngle = anim.rotateAngle ?? 15 // degrees\n const blurAmount = anim.blurAmount ?? 8 // px\n\n // Build animation styles based on preset\n const entrance = anim.entrance ?? 'none'\n\n let initial: React.CSSProperties = {}\n let animate: React.CSSProperties = {}\n\n switch (entrance) {\n // ==================== FADE (6) ====================\n case 'fade-in':\n initial = { opacity: 0 }\n animate = { opacity: 1 }\n break\n\n case 'fade-up':\n initial = { opacity: 0, transform: `translateY(${distance}px)` }\n animate = { opacity: 1, transform: 'translateY(0)' }\n break\n\n case 'fade-down':\n initial = { opacity: 0, transform: `translateY(-${distance}px)` }\n animate = { opacity: 1, transform: 'translateY(0)' }\n break\n\n case 'fade-left':\n initial = { opacity: 0, transform: `translateX(${distance}px)` }\n animate = { opacity: 1, transform: 'translateX(0)' }\n break\n\n case 'fade-right':\n initial = { opacity: 0, transform: `translateX(-${distance}px)` }\n animate = { opacity: 1, transform: 'translateX(0)' }\n break\n\n case 'fade-scale':\n initial = { opacity: 0, transform: `scale(${scaleFrom})` }\n animate = { opacity: 1, transform: 'scale(1)' }\n break\n\n // ==================== SCALE (4) ====================\n case 'scale-in':\n initial = { opacity: 0, transform: `scale(${scaleFrom})` }\n animate = { opacity: 1, transform: 'scale(1)' }\n break\n\n case 'scale-up':\n initial = { opacity: 0, transform: `scale(${scaleFrom}) translateY(${distance}px)` }\n animate = { opacity: 1, transform: 'scale(1) translateY(0)' }\n break\n\n case 'scale-down':\n initial = { opacity: 0, transform: `scale(${scaleFrom}) translateY(-${distance}px)` }\n animate = { opacity: 1, transform: 'scale(1) translateY(0)' }\n break\n\n case 'scale-out':\n // Scales from larger to normal\n initial = { opacity: 0, transform: `scale(${2 - scaleFrom})` }\n animate = { opacity: 1, transform: 'scale(1)' }\n break\n\n // ==================== SLIDE (4) ====================\n case 'slide-up':\n initial = { transform: `translateY(${distance}px)` }\n animate = { transform: 'translateY(0)' }\n break\n\n case 'slide-down':\n initial = { transform: `translateY(-${distance}px)` }\n animate = { transform: 'translateY(0)' }\n break\n\n case 'slide-left':\n initial = { transform: `translateX(${distance}px)` }\n animate = { transform: 'translateX(0)' }\n break\n\n case 'slide-right':\n initial = { transform: `translateX(-${distance}px)` }\n animate = { transform: 'translateX(0)' }\n break\n\n // ==================== BLUR (3) ====================\n case 'blur-in':\n initial = { opacity: 0, filter: `blur(${blurAmount}px)` }\n animate = { opacity: 1, filter: 'blur(0)' }\n break\n\n case 'blur-up':\n initial = { opacity: 0, filter: `blur(${blurAmount}px)`, transform: `translateY(${distance}px)` }\n animate = { opacity: 1, filter: 'blur(0)', transform: 'translateY(0)' }\n break\n\n case 'blur-down':\n initial = { opacity: 0, filter: `blur(${blurAmount}px)`, transform: `translateY(-${distance}px)` }\n animate = { opacity: 1, filter: 'blur(0)', transform: 'translateY(0)' }\n break\n\n // ==================== ROTATE (3) ====================\n case 'rotate-in':\n initial = { opacity: 0, transform: `rotate(${rotateAngle}deg) scale(${scaleFrom})` }\n animate = { opacity: 1, transform: 'rotate(0) scale(1)' }\n break\n\n case 'rotate-up':\n initial = { opacity: 0, transform: `rotate(${rotateAngle}deg) translateY(${distance}px)` }\n animate = { opacity: 1, transform: 'rotate(0) translateY(0)' }\n break\n\n case 'rotate-down':\n initial = { opacity: 0, transform: `rotate(-${rotateAngle}deg) translateY(-${distance}px)` }\n animate = { opacity: 1, transform: 'rotate(0) translateY(0)' }\n break\n\n // ==================== BOUNCE (3) ====================\n // These use spring/bounce easing by default for the effect\n case 'bounce-in':\n initial = { opacity: 0, transform: `scale(${scaleFrom * 0.8})` }\n animate = { opacity: 1, transform: 'scale(1)' }\n break\n\n case 'bounce-up':\n initial = { opacity: 0, transform: `translateY(${distance * 1.5}px)` }\n animate = { opacity: 1, transform: 'translateY(0)' }\n break\n\n case 'bounce-down':\n initial = { opacity: 0, transform: `translateY(-${distance * 1.5}px)` }\n animate = { opacity: 1, transform: 'translateY(0)' }\n break\n\n // ==================== FLIP (2) ====================\n // Flip uses perspective in transform for proper 3D effect\n // Starts from -90deg (tilted back) so the flip motion is visible\n case 'flip-x':\n initial = {\n transform: 'perspective(1000px) rotateX(-90deg)',\n opacity: 0.2,\n backfaceVisibility: 'hidden',\n }\n animate = {\n transform: 'perspective(1000px) rotateX(0deg)',\n opacity: 1,\n backfaceVisibility: 'hidden',\n }\n break\n\n case 'flip-y':\n initial = {\n transform: 'perspective(1000px) rotateY(-90deg)',\n opacity: 0.2,\n backfaceVisibility: 'hidden',\n }\n animate = {\n transform: 'perspective(1000px) rotateY(0deg)',\n opacity: 1,\n backfaceVisibility: 'hidden',\n }\n break\n\n // ==================== ZOOM (2) ====================\n case 'zoom-in':\n // Starts small, zooms to full size\n initial = { opacity: 0, transform: `scale(${scaleFrom * 0.5})` }\n animate = { opacity: 1, transform: 'scale(1)' }\n break\n\n case 'zoom-out':\n // Starts large, zooms down to full size\n initial = { opacity: 0, transform: `scale(${2.5 - scaleFrom})` }\n animate = { opacity: 1, transform: 'scale(1)' }\n break\n\n default:\n break\n }\n\n return {\n initial,\n animate,\n duration,\n delay,\n easing,\n origin,\n }\n}\n\n/**\n * Get default easing for animation category\n * Bounce animations default to bounce easing, etc.\n */\nexport function getDefaultEasingForAnimation(entrance: EntranceAnimation): AdvancedEasingFunction {\n if (entrance.startsWith('bounce-')) return 'bounce'\n if (entrance.startsWith('flip-')) return 'back-out'\n if (entrance.startsWith('zoom-')) return 'ease-out'\n return 'ease'\n}\n\n/**\n * Get CSS custom properties for animation timing\n * Useful for CSS-only animations with custom properties\n */\nexport function getAnimationCSSVariables(anim: AnimationValue | null): Record<string, string> {\n if (!anim) return {}\n\n const isPreset = anim.mode === 'preset'\n const duration = isPreset ? (anim.entranceDuration ?? 500) : (anim.duration ?? 300)\n const delay = isPreset ? (anim.entranceDelay ?? 0) : (anim.delay ?? 0)\n const easing = anim.easing ?? 'ease'\n const easingCSS = EASING_CSS_MAP[easing] || 'ease'\n\n return {\n '--animation-duration': `${duration}ms`,\n '--animation-delay': `${delay}ms`,\n '--animation-easing': easingCSS,\n }\n}\n\n/**\n * Generate stagger delay for a specific child index\n * Accounts for direction (forward, reverse, center, edges)\n */\nexport function getStaggerDelay(config: StaggerConfig, index: number, totalChildren: number): number {\n if (!config.enabled || totalChildren <= 1) return 0\n\n let effectiveIndex: number\n\n switch (config.direction) {\n case 'forward':\n effectiveIndex = index\n break\n case 'reverse':\n effectiveIndex = totalChildren - 1 - index\n break\n case 'center': {\n // Center starts from middle, animates outward\n const center = (totalChildren - 1) / 2\n effectiveIndex = Math.abs(index - center)\n break\n }\n case 'edges': {\n // Edges starts from outside, animates inward\n const center = (totalChildren - 1) / 2\n effectiveIndex = center - Math.abs(index - center)\n break\n }\n default:\n effectiveIndex = index\n }\n\n const delay = effectiveIndex * config.delay\n\n // Cap at max delay if specified\n if (config.maxDelay && delay > config.maxDelay) {\n return config.maxDelay\n }\n\n return delay\n}\n\n/**\n * Generate CSS styles for staggered children\n * Returns an object with CSS custom properties for each child\n */\nexport function generateStaggerStyles(\n config: StaggerConfig | undefined,\n totalChildren: number\n): React.CSSProperties[] {\n if (!config?.enabled || totalChildren <= 1) {\n return Array(totalChildren).fill({})\n }\n\n return Array.from({ length: totalChildren }, (_, i) => {\n const delay = getStaggerDelay(config, i, totalChildren)\n return {\n '--stagger-delay': `${delay}ms`,\n transitionDelay: `${delay}ms`,\n } as React.CSSProperties\n })\n}\n\n/**\n * Check which intensity controls are relevant for an animation type\n */\nexport function getRelevantIntensityControls(entrance: EntranceAnimation): {\n showDistance: boolean\n showScale: boolean\n showRotate: boolean\n showBlur: boolean\n} {\n const hasTranslate = [\n 'fade-up', 'fade-down', 'fade-left', 'fade-right',\n 'scale-up', 'scale-down',\n 'slide-up', 'slide-down', 'slide-left', 'slide-right',\n 'blur-up', 'blur-down',\n 'rotate-up', 'rotate-down',\n 'bounce-up', 'bounce-down',\n ].includes(entrance)\n\n const hasScale = [\n 'fade-scale',\n 'scale-in', 'scale-up', 'scale-down', 'scale-out',\n 'rotate-in',\n 'bounce-in',\n 'zoom-in', 'zoom-out',\n ].includes(entrance)\n\n const hasRotate = [\n 'rotate-in', 'rotate-up', 'rotate-down',\n ].includes(entrance)\n\n const hasBlur = [\n 'blur-in', 'blur-up', 'blur-down',\n ].includes(entrance)\n\n return {\n showDistance: hasTranslate,\n showScale: hasScale,\n showRotate: hasRotate,\n showBlur: hasBlur,\n }\n}\n\n/**\n * Default animation value\n */\nexport const DEFAULT_ANIMATION: AnimationValue = {\n mode: 'preset',\n entrance: 'none',\n entranceDuration: 500,\n entranceDelay: 0,\n distance: 24,\n scaleFrom: 0.9,\n rotateAngle: 15,\n blurAmount: 8,\n origin: 'center',\n easing: 'ease',\n triggerOnScroll: true,\n triggerThreshold: 0.1,\n triggerOnce: true,\n}\n\n// =============================================================================\n// Layout Components Disallow List (prevent recursion in slots)\n// =============================================================================\n\nexport const layoutComponentsDisallow = [\n 'Container',\n 'Flex',\n 'Grid',\n 'Section',\n]\n\n","'use client'\n\n/**\n * AnimatedWrapper - Client component for scroll-triggered animations\n *\n * Wraps children with animation support using IntersectionObserver.\n * Handles both preset entrance animations and custom transitions.\n * Supports 27 animation presets with customizable intensity, easing, and origin.\n */\n\nimport type { ReactNode, CSSProperties, ElementType } from 'react'\nimport { useScrollAnimation } from '../hooks/useScrollAnimation'\nimport {\n getEntranceAnimationStyles,\n animationValueToCSS,\n type AnimationValue,\n} from '../fields/shared'\n\nexport interface AnimatedWrapperProps {\n /** Animation configuration from the component */\n animation: AnimationValue | null | undefined\n /** Child content to animate */\n children: ReactNode\n /** Additional CSS classes */\n className?: string\n /** Inline styles */\n style?: CSSProperties\n /** HTML element to render as (default: 'div') */\n as?: ElementType\n}\n\n/**\n * Wraps children with scroll-triggered animation support.\n *\n * For preset animations: Applies initial/animate inline styles\n * when element enters viewport.\n *\n * For custom animations: Applies CSS transition properties.\n *\n * If no animation is set, renders children without a wrapper div.\n */\nexport function AnimatedWrapper({\n animation,\n children,\n className,\n style,\n as: Component = 'div',\n}: AnimatedWrapperProps) {\n // Check if animation should be applied\n const hasAnimation = animation && (\n (animation.mode === 'preset' && animation.entrance && animation.entrance !== 'none') ||\n animation.mode === 'custom'\n )\n\n // If no animation, render children directly without wrapper\n if (!hasAnimation) {\n // If there's a className or style, we still need to wrap\n if (className || style) {\n return <Component className={className} style={style}>{children}</Component>\n }\n return <>{children}</>\n }\n\n // Use the scroll animation hook\n const { ref, isInView } = useScrollAnimation({\n triggerOnScroll: animation.triggerOnScroll ?? true,\n threshold: animation.triggerThreshold ?? 0.1,\n once: animation.triggerOnce ?? true,\n rootMargin: animation.triggerMargin,\n })\n\n // Handle preset entrance animations\n if (animation.mode === 'preset') {\n const { initial, animate, duration, delay, easing, origin } = getEntranceAnimationStyles(animation)\n\n // Apply initial or animate styles based on visibility\n const animationStyles = isInView ? animate : initial\n\n // Build transition string with all relevant properties\n const transitionProperties = [\n `opacity ${duration}ms ${easing} ${delay}ms`,\n `transform ${duration}ms ${easing} ${delay}ms`,\n `filter ${duration}ms ${easing} ${delay}ms`,\n ].join(', ')\n\n return (\n <Component\n ref={ref}\n className={className}\n style={{\n ...style,\n ...animationStyles,\n transition: transitionProperties,\n transformOrigin: origin,\n }}\n >\n {children}\n </Component>\n )\n }\n\n // Handle custom transition mode\n const customStyles = animationValueToCSS(animation)\n\n return (\n <Component\n ref={ref}\n className={className}\n style={{\n ...style,\n ...customStyles,\n // Apply opacity for visibility-based transitions\n opacity: isInView ? 1 : 0,\n }}\n >\n {children}\n </Component>\n )\n}\n"]}
|
package/dist/admin/client.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/admin/EditWithPuckButton.tsx","../../src/admin/EditWithPuckCell.tsx"],"names":["jsxs","jsx","useDocumentInfo","PuckIcon"],"mappings":"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","file":"client.js","sourcesContent":["'use client'\n\nimport type { UIFieldClientComponent } from 'payload'\nimport { useDocumentInfo } from '@payloadcms/ui'\n\n/**\n * Props for EditWithPuckButton when used standalone\n */\nexport interface EditWithPuckButtonProps {\n /**\n * Document ID to edit\n */\n id?: string\n /**\n * Collection slug\n * @default 'pages'\n */\n collectionSlug?: string\n /**\n * Custom path pattern for the Puck editor\n * Use {id} as placeholder for the document ID\n * @default '/pages/{id}/edit'\n */\n editorPathPattern?: string\n /**\n * Button label\n * @default 'Edit with Puck'\n */\n label?: string\n /**\n * Whether to show as icon only\n * @default false\n */\n iconOnly?: boolean\n}\n\n/**\n * Pencil/Edit icon component\n */\nfunction PuckIcon({ size = 18 }: { size?: number }) {\n return (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width={size}\n height={size}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <path d=\"M12 3H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7\" />\n <path d=\"M18.375 2.625a2.121 2.121 0 1 1 3 3L12 15l-4 1 1-4Z\" />\n </svg>\n )\n}\n\n/**\n * Edit with Puck button for use in Payload admin document edit views\n *\n * Links to a Puck editor page outside of Payload admin. Configure the\n * `editorPathPattern` to match your editor route.\n *\n * @example\n * ```tsx\n * // In your Payload collection config:\n * {\n * name: 'puckEdit',\n * type: 'ui',\n * admin: {\n * position: 'sidebar',\n * components: {\n * Field: '@delmaredigital/payload-puck/admin/client#EditWithPuckButton',\n * },\n * custom: {\n * editorPathPattern: '/pages/{id}/edit', // Your editor route\n * label: 'Visual Editor',\n * },\n * },\n * }\n * ```\n */\nexport const EditWithPuckButton: UIFieldClientComponent = (props) => {\n // Get document context from Payload\n const { id } = useDocumentInfo()\n\n // Extract custom props passed via field config\n const customProps = (props as any)?.field?.custom as EditWithPuckButtonProps | undefined\n const label = customProps?.label || 'Edit with Puck'\n const iconOnly = customProps?.iconOnly || false\n\n // Build editor URL from pattern (default: /pages/{id}/edit)\n const pattern = customProps?.editorPathPattern || '/pages/{id}/edit'\n const editorPath = pattern.replace('{id}', String(id))\n\n if (!id) {\n return null\n }\n\n return (\n <div style={{ marginBottom: '1rem' }}>\n <a\n href={editorPath}\n style={{\n display: 'inline-flex',\n alignItems: 'center',\n gap: '8px',\n padding: iconOnly ? '8px' : '10px 16px',\n backgroundColor: '#2563eb',\n color: '#fff',\n borderRadius: '6px',\n textDecoration: 'none',\n fontSize: '14px',\n fontWeight: 500,\n transition: 'background-color 0.2s',\n }}\n onMouseEnter={(e) => {\n e.currentTarget.style.backgroundColor = '#1d4ed8'\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.backgroundColor = '#2563eb'\n }}\n title={iconOnly ? label : undefined}\n >\n <PuckIcon size={iconOnly ? 20 : 18} />\n {!iconOnly && label}\n </a>\n </div>\n )\n}\n\n/**\n * Standalone version of the button that doesn't rely on Payload context\n */\nexport function EditWithPuckLink({\n id,\n editorPathPattern = '/pages/{id}/edit',\n label = 'Edit with Puck',\n iconOnly = false,\n}: EditWithPuckButtonProps & { id: string }) {\n const path = editorPathPattern.replace('{id}', id)\n\n return (\n <a\n href={path}\n style={{\n display: 'inline-flex',\n alignItems: 'center',\n gap: '8px',\n padding: iconOnly ? '8px' : '10px 16px',\n backgroundColor: '#2563eb',\n color: '#fff',\n borderRadius: '6px',\n textDecoration: 'none',\n fontSize: '14px',\n fontWeight: 500,\n transition: 'background-color 0.2s',\n }}\n onMouseEnter={(e) => {\n e.currentTarget.style.backgroundColor = '#1d4ed8'\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.backgroundColor = '#2563eb'\n }}\n title={iconOnly ? label : undefined}\n >\n <PuckIcon size={iconOnly ? 20 : 18} />\n {!iconOnly && label}\n </a>\n )\n}\n\nexport default EditWithPuckButton\n","'use client'\n\nimport type { DefaultCellComponentProps } from 'payload'\n\n/**\n * Props for configuring the EditWithPuckCell component\n */\nexport interface EditWithPuckCellConfig {\n /**\n * Collection slug for building the editor URL\n * @default 'pages'\n */\n collectionSlug?: string\n /**\n * Custom editor path pattern\n * Use {id} as placeholder for the document ID\n * @default '/admin/puck/{collectionSlug}/{id}/edit'\n */\n editorPathPattern?: string\n}\n\n/**\n * Pencil/Edit icon component\n */\nfunction PuckIcon({ size = 16 }: { size?: number }) {\n return (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width={size}\n height={size}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <path d=\"M12 3H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7\" />\n <path d=\"M18.375 2.625a2.121 2.121 0 1 1 3 3L12 15l-4 1 1-4Z\" />\n </svg>\n )\n}\n\n/**\n * Custom cell component that renders an \"Edit with Puck\" button in list views\n *\n * Add this to a UI field in your collection to show the visual editor button\n * in the list view table.\n *\n * @example\n * ```ts\n * // In your collection config:\n * {\n * name: 'puckEdit',\n * type: 'ui',\n * admin: {\n * components: {\n * Cell: '@delmaredigital/payload-puck/admin#EditWithPuckCell',\n * },\n * custom: {\n * collectionSlug: 'pages',\n * },\n * },\n * }\n * ```\n */\nexport const EditWithPuckCell: React.FC<DefaultCellComponentProps> = ({\n rowData,\n field,\n collectionSlug: contextCollectionSlug,\n}) => {\n // Get document ID from row data\n const id = rowData?.id as string | undefined\n\n // Get custom config from field\n const customConfig = (field as any)?.custom as EditWithPuckCellConfig | undefined\n const collectionSlug = customConfig?.collectionSlug || contextCollectionSlug || 'pages'\n\n if (!id) {\n return null\n }\n\n // Build editor URL\n const editorPath = customConfig?.editorPathPattern\n ? customConfig.editorPathPattern.replace('{id}', id).replace('{collectionSlug}', collectionSlug)\n : `/admin/puck/${collectionSlug}/${id}/edit`\n\n return (\n <a\n href={editorPath}\n onClick={(e) => e.stopPropagation()}\n style={{\n display: 'inline-flex',\n alignItems: 'center',\n justifyContent: 'center',\n padding: '6px 10px',\n backgroundColor: '#2563eb',\n color: '#fff',\n borderRadius: '4px',\n textDecoration: 'none',\n fontSize: '12px',\n fontWeight: 500,\n gap: '4px',\n transition: 'background-color 0.2s',\n whiteSpace: 'nowrap',\n }}\n onMouseEnter={(e) => {\n e.currentTarget.style.backgroundColor = '#1d4ed8'\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.backgroundColor = '#2563eb'\n }}\n title=\"Edit with Puck Visual Editor\"\n >\n <PuckIcon size={14} />\n <span>Visual Editor</span>\n </a>\n )\n}\n\nexport default EditWithPuckCell\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/admin/EditWithPuckButton.tsx","../../src/admin/EditWithPuckCell.tsx"],"names":["PuckIcon","jsxs","jsx"],"mappings":"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","file":"client.mjs","sourcesContent":["'use client'\n\nimport type { UIFieldClientComponent } from 'payload'\nimport { useDocumentInfo } from '@payloadcms/ui'\n\n/**\n * Props for EditWithPuckButton when used standalone\n */\nexport interface EditWithPuckButtonProps {\n /**\n * Document ID to edit\n */\n id?: string\n /**\n * Collection slug\n * @default 'pages'\n */\n collectionSlug?: string\n /**\n * Custom path pattern for the Puck editor\n * Use {id} as placeholder for the document ID\n * @default '/pages/{id}/edit'\n */\n editorPathPattern?: string\n /**\n * Button label\n * @default 'Edit with Puck'\n */\n label?: string\n /**\n * Whether to show as icon only\n * @default false\n */\n iconOnly?: boolean\n}\n\n/**\n * Pencil/Edit icon component\n */\nfunction PuckIcon({ size = 18 }: { size?: number }) {\n return (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width={size}\n height={size}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <path d=\"M12 3H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7\" />\n <path d=\"M18.375 2.625a2.121 2.121 0 1 1 3 3L12 15l-4 1 1-4Z\" />\n </svg>\n )\n}\n\n/**\n * Edit with Puck button for use in Payload admin document edit views\n *\n * Links to a Puck editor page outside of Payload admin. Configure the\n * `editorPathPattern` to match your editor route.\n *\n * @example\n * ```tsx\n * // In your Payload collection config:\n * {\n * name: 'puckEdit',\n * type: 'ui',\n * admin: {\n * position: 'sidebar',\n * components: {\n * Field: '@delmaredigital/payload-puck/admin/client#EditWithPuckButton',\n * },\n * custom: {\n * editorPathPattern: '/pages/{id}/edit', // Your editor route\n * label: 'Visual Editor',\n * },\n * },\n * }\n * ```\n */\nexport const EditWithPuckButton: UIFieldClientComponent = (props) => {\n // Get document context from Payload\n const { id } = useDocumentInfo()\n\n // Extract custom props passed via field config\n const customProps = (props as any)?.field?.custom as EditWithPuckButtonProps | undefined\n const label = customProps?.label || 'Edit with Puck'\n const iconOnly = customProps?.iconOnly || false\n\n // Build editor URL from pattern (default: /pages/{id}/edit)\n const pattern = customProps?.editorPathPattern || '/pages/{id}/edit'\n const editorPath = pattern.replace('{id}', String(id))\n\n if (!id) {\n return null\n }\n\n return (\n <div style={{ marginBottom: '1rem' }}>\n <a\n href={editorPath}\n style={{\n display: 'inline-flex',\n alignItems: 'center',\n gap: '8px',\n padding: iconOnly ? '8px' : '10px 16px',\n backgroundColor: '#2563eb',\n color: '#fff',\n borderRadius: '6px',\n textDecoration: 'none',\n fontSize: '14px',\n fontWeight: 500,\n transition: 'background-color 0.2s',\n }}\n onMouseEnter={(e) => {\n e.currentTarget.style.backgroundColor = '#1d4ed8'\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.backgroundColor = '#2563eb'\n }}\n title={iconOnly ? label : undefined}\n >\n <PuckIcon size={iconOnly ? 20 : 18} />\n {!iconOnly && label}\n </a>\n </div>\n )\n}\n\n/**\n * Standalone version of the button that doesn't rely on Payload context\n */\nexport function EditWithPuckLink({\n id,\n editorPathPattern = '/pages/{id}/edit',\n label = 'Edit with Puck',\n iconOnly = false,\n}: EditWithPuckButtonProps & { id: string }) {\n const path = editorPathPattern.replace('{id}', id)\n\n return (\n <a\n href={path}\n style={{\n display: 'inline-flex',\n alignItems: 'center',\n gap: '8px',\n padding: iconOnly ? '8px' : '10px 16px',\n backgroundColor: '#2563eb',\n color: '#fff',\n borderRadius: '6px',\n textDecoration: 'none',\n fontSize: '14px',\n fontWeight: 500,\n transition: 'background-color 0.2s',\n }}\n onMouseEnter={(e) => {\n e.currentTarget.style.backgroundColor = '#1d4ed8'\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.backgroundColor = '#2563eb'\n }}\n title={iconOnly ? label : undefined}\n >\n <PuckIcon size={iconOnly ? 20 : 18} />\n {!iconOnly && label}\n </a>\n )\n}\n\nexport default EditWithPuckButton\n","'use client'\n\nimport type { DefaultCellComponentProps } from 'payload'\n\n/**\n * Props for configuring the EditWithPuckCell component\n */\nexport interface EditWithPuckCellConfig {\n /**\n * Collection slug for building the editor URL\n * @default 'pages'\n */\n collectionSlug?: string\n /**\n * Custom editor path pattern\n * Use {id} as placeholder for the document ID\n * @default '/admin/puck/{collectionSlug}/{id}/edit'\n */\n editorPathPattern?: string\n}\n\n/**\n * Pencil/Edit icon component\n */\nfunction PuckIcon({ size = 16 }: { size?: number }) {\n return (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width={size}\n height={size}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <path d=\"M12 3H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7\" />\n <path d=\"M18.375 2.625a2.121 2.121 0 1 1 3 3L12 15l-4 1 1-4Z\" />\n </svg>\n )\n}\n\n/**\n * Custom cell component that renders an \"Edit with Puck\" button in list views\n *\n * Add this to a UI field in your collection to show the visual editor button\n * in the list view table.\n *\n * @example\n * ```ts\n * // In your collection config:\n * {\n * name: 'puckEdit',\n * type: 'ui',\n * admin: {\n * components: {\n * Cell: '@delmaredigital/payload-puck/admin#EditWithPuckCell',\n * },\n * custom: {\n * collectionSlug: 'pages',\n * },\n * },\n * }\n * ```\n */\nexport const EditWithPuckCell: React.FC<DefaultCellComponentProps> = ({\n rowData,\n field,\n collectionSlug: contextCollectionSlug,\n}) => {\n // Get document ID from row data\n const id = rowData?.id as string | undefined\n\n // Get custom config from field\n const customConfig = (field as any)?.custom as EditWithPuckCellConfig | undefined\n const collectionSlug = customConfig?.collectionSlug || contextCollectionSlug || 'pages'\n\n if (!id) {\n return null\n }\n\n // Build editor URL\n const editorPath = customConfig?.editorPathPattern\n ? customConfig.editorPathPattern.replace('{id}', id).replace('{collectionSlug}', collectionSlug)\n : `/admin/puck/${collectionSlug}/${id}/edit`\n\n return (\n <a\n href={editorPath}\n onClick={(e) => e.stopPropagation()}\n style={{\n display: 'inline-flex',\n alignItems: 'center',\n justifyContent: 'center',\n padding: '6px 10px',\n backgroundColor: '#2563eb',\n color: '#fff',\n borderRadius: '4px',\n textDecoration: 'none',\n fontSize: '12px',\n fontWeight: 500,\n gap: '4px',\n transition: 'background-color 0.2s',\n whiteSpace: 'nowrap',\n }}\n onMouseEnter={(e) => {\n e.currentTarget.style.backgroundColor = '#1d4ed8'\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.backgroundColor = '#2563eb'\n }}\n title=\"Edit with Puck Visual Editor\"\n >\n <PuckIcon size={14} />\n <span>Visual Editor</span>\n </a>\n )\n}\n\nexport default EditWithPuckCell\n"]}
|
package/dist/admin/index.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/admin/generateAdminComponents.ts"],"names":[],"mappings":";;;AAmDO,SAAS,qBAAA,CAAsB,MAAA,GAAgC,EAAC,EAAU;AAC/E,EAAA,MAAM;AAAA,IACJ,cAAA,GAAiB,OAAA;AAAA,IACjB,iBAAA,GAAoB,kBAAA;AAAA,IACpB,WAAA,GAAc,gBAAA;AAAA,IACd,cAAA,GAAiB;AAAA,GACnB,GAAI,MAAA;AAEJ,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,UAAA;AAAA,IACN,IAAA,EAAM,IAAA;AAAA,IACN,KAAA,EAAO;AAAA,MACL,QAAA,EAAU,cAAA;AAAA,MACV,UAAA,EAAY;AAAA,QACV,KAAA,EAAO,8DAAA;AAAA,QACP,IAAA,EAAM;AAAA,OACR;AAAA,MACA,MAAA,EAAQ;AAAA,QACN,cAAA;AAAA,QACA,iBAAA;AAAA,QACA,KAAA,EAAO;AAAA;AACT;AACF,GACF;AACF","file":"index.js","sourcesContent":["import type { Field } from 'payload'\n\n/**\n * Configuration for generating the edit button field\n */\nexport interface AdminComponentsConfig {\n /**\n * Collection slug for the pages collection\n * @default 'pages'\n */\n collectionSlug?: string\n /**\n * URL pattern for the Puck editor page\n * Use {id} as placeholder for document ID\n * @default '/pages/{id}/edit'\n */\n editorPathPattern?: string\n /**\n * Button label text\n * @default 'Edit with Puck'\n */\n buttonLabel?: string\n /**\n * Position of the edit button in admin\n * @default 'sidebar'\n */\n buttonPosition?: 'sidebar' | 'main'\n}\n\n/**\n * Generates the UI field configuration for the Edit with Puck button\n *\n * Use this if you want to manually add the edit button field to your\n * collection instead of using the plugin's auto-generation.\n *\n * @example\n * ```ts\n * import { generatePuckEditField } from '@delmaredigital/payload-puck/admin'\n *\n * const Pages: CollectionConfig = {\n * slug: 'pages',\n * fields: [\n * // ... other fields\n * generatePuckEditField({\n * editorPathPattern: '/pages/{id}/edit',\n * buttonLabel: 'Visual Editor',\n * }),\n * ],\n * }\n * ```\n */\nexport function generatePuckEditField(config: AdminComponentsConfig = {}): Field {\n const {\n collectionSlug = 'pages',\n editorPathPattern = '/pages/{id}/edit',\n buttonLabel = 'Edit with Puck',\n buttonPosition = 'sidebar',\n } = config\n\n return {\n name: 'puckEdit',\n type: 'ui',\n admin: {\n position: buttonPosition,\n components: {\n Field: '@delmaredigital/payload-puck/admin/client#EditWithPuckButton',\n Cell: '@delmaredigital/payload-puck/admin/client#EditWithPuckCell',\n },\n custom: {\n collectionSlug,\n editorPathPattern,\n label: buttonLabel,\n },\n },\n }\n}\n"]}
|
package/dist/admin/index.mjs.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/admin/generateAdminComponents.ts"],"names":[],"mappings":";AAmDO,SAAS,qBAAA,CAAsB,MAAA,GAAgC,EAAC,EAAU;AAC/E,EAAA,MAAM;AAAA,IACJ,cAAA,GAAiB,OAAA;AAAA,IACjB,iBAAA,GAAoB,kBAAA;AAAA,IACpB,WAAA,GAAc,gBAAA;AAAA,IACd,cAAA,GAAiB;AAAA,GACnB,GAAI,MAAA;AAEJ,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,UAAA;AAAA,IACN,IAAA,EAAM,IAAA;AAAA,IACN,KAAA,EAAO;AAAA,MACL,QAAA,EAAU,cAAA;AAAA,MACV,UAAA,EAAY;AAAA,QACV,KAAA,EAAO,8DAAA;AAAA,QACP,IAAA,EAAM;AAAA,OACR;AAAA,MACA,MAAA,EAAQ;AAAA,QACN,cAAA;AAAA,QACA,iBAAA;AAAA,QACA,KAAA,EAAO;AAAA;AACT;AACF,GACF;AACF","file":"index.mjs","sourcesContent":["import type { Field } from 'payload'\n\n/**\n * Configuration for generating the edit button field\n */\nexport interface AdminComponentsConfig {\n /**\n * Collection slug for the pages collection\n * @default 'pages'\n */\n collectionSlug?: string\n /**\n * URL pattern for the Puck editor page\n * Use {id} as placeholder for document ID\n * @default '/pages/{id}/edit'\n */\n editorPathPattern?: string\n /**\n * Button label text\n * @default 'Edit with Puck'\n */\n buttonLabel?: string\n /**\n * Position of the edit button in admin\n * @default 'sidebar'\n */\n buttonPosition?: 'sidebar' | 'main'\n}\n\n/**\n * Generates the UI field configuration for the Edit with Puck button\n *\n * Use this if you want to manually add the edit button field to your\n * collection instead of using the plugin's auto-generation.\n *\n * @example\n * ```ts\n * import { generatePuckEditField } from '@delmaredigital/payload-puck/admin'\n *\n * const Pages: CollectionConfig = {\n * slug: 'pages',\n * fields: [\n * // ... other fields\n * generatePuckEditField({\n * editorPathPattern: '/pages/{id}/edit',\n * buttonLabel: 'Visual Editor',\n * }),\n * ],\n * }\n * ```\n */\nexport function generatePuckEditField(config: AdminComponentsConfig = {}): Field {\n const {\n collectionSlug = 'pages',\n editorPathPattern = '/pages/{id}/edit',\n buttonLabel = 'Edit with Puck',\n buttonPosition = 'sidebar',\n } = config\n\n return {\n name: 'puckEdit',\n type: 'ui',\n admin: {\n position: buttonPosition,\n components: {\n Field: '@delmaredigital/payload-puck/admin/client#EditWithPuckButton',\n Cell: '@delmaredigital/payload-puck/admin/client#EditWithPuckCell',\n },\n custom: {\n collectionSlug,\n editorPathPattern,\n label: buttonLabel,\n },\n },\n }\n}\n"]}
|
package/dist/api/index.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/api/createPuckApiRoutes.ts","../../src/api/utils/mapRootProps.ts","../../src/api/createPuckApiRoutesWithId.ts","../../src/api/createPuckApiRoutesVersions.ts"],"names":["NextResponse","payload","getPayload"],"mappings":"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","file":"index.js","sourcesContent":["import { NextRequest, NextResponse } from 'next/server'\nimport { getPayload } from 'payload'\nimport type { Where } from 'payload'\nimport type { Data as PuckData } from '@measured/puck'\nimport type {\n PuckApiRoutesConfig,\n PuckApiRouteHandlers,\n CreatePageBody,\n RouteHandlerContext,\n} from './types'\n\n/**\n * Default Puck data for new pages\n */\nconst DEFAULT_PUCK_DATA: PuckData = {\n root: {\n props: {\n title: '',\n } as Record<string, unknown>,\n },\n content: [],\n zones: {},\n}\n\n/**\n * Create API route handlers for /api/puck/pages\n *\n * Provides GET (list pages) and POST (create page) handlers\n * with configurable authentication and authorization.\n *\n * @example\n * ```typescript\n * // src/app/api/puck/pages/route.ts\n * import { createPuckApiRoutes } from '@delmaredigital/payload-puck/api'\n * import config from '@payload-config'\n *\n * export const { GET, POST } = createPuckApiRoutes({\n * collection: 'pages',\n * payloadConfig: config,\n * auth: {\n * authenticate: async (request) => {\n * const session = await getSession(request)\n * if (!session?.user) return { authenticated: false }\n * return { authenticated: true, user: session.user }\n * },\n * canCreate: async (user) => {\n * return { allowed: user.role === 'admin' || user.role === 'editor' }\n * },\n * },\n * })\n * ```\n */\nexport function createPuckApiRoutes(\n routeConfig: PuckApiRoutesConfig\n): PuckApiRouteHandlers {\n const {\n collection = 'pages',\n payloadConfig,\n auth,\n defaultPuckData = DEFAULT_PUCK_DATA,\n enableDrafts = true,\n onError,\n } = routeConfig\n\n /**\n * GET /api/puck/pages\n * List all pages with optional filtering\n *\n * Query Parameters:\n * - page: Page number (default: 1)\n * - limit: Items per page (default: 10)\n * - search: Search in title field\n * - status: Filter by _status ('draft', 'published', 'all')\n * - editorVersion: Filter by editorVersion field\n * - sort: Sort field (default: '-updatedAt')\n */\n async function GET(request: NextRequest, _context: RouteHandlerContext): Promise<Response> {\n try {\n // Authenticate\n const authResult = await auth.authenticate(request)\n if (!authResult.authenticated || !authResult.user) {\n return NextResponse.json(\n { error: authResult.error || 'Unauthorized' },\n { status: 401 }\n )\n }\n\n // Check list permission\n if (auth.canList) {\n const permission = await auth.canList(authResult.user)\n if (!permission.allowed) {\n return NextResponse.json(\n { error: permission.error || 'Forbidden' },\n { status: 403 }\n )\n }\n }\n\n // Parse query parameters\n const { searchParams } = new URL(request.url)\n const page = parseInt(searchParams.get('page') || '1', 10)\n const limit = Math.min(parseInt(searchParams.get('limit') || '10', 10), 100)\n const search = searchParams.get('search') || ''\n const status = searchParams.get('status')\n const editorVersion = searchParams.get('editorVersion')\n const sort = searchParams.get('sort') || '-updatedAt'\n\n // Get Payload instance with provided config\n const config = await payloadConfig\n const payload = await getPayload({ config })\n\n // Build where clause\n const conditions: Where[] = []\n\n if (search) {\n conditions.push({ title: { contains: search } })\n }\n\n if (status && status !== 'all') {\n conditions.push({ _status: { equals: status } })\n }\n\n if (editorVersion && editorVersion !== 'all') {\n conditions.push({ editorVersion: { equals: editorVersion } })\n }\n\n const where: Where | undefined =\n conditions.length > 0\n ? conditions.length === 1\n ? conditions[0]\n : { and: conditions }\n : undefined\n\n const result = await payload.find({\n collection,\n page,\n limit,\n sort,\n where,\n })\n\n return NextResponse.json(result)\n } catch (error) {\n if (onError) {\n onError(error, { operation: 'list', request })\n }\n console.error('Error listing pages:', error)\n return NextResponse.json(\n { error: 'Failed to list pages' },\n { status: 500 }\n )\n }\n }\n\n /**\n * POST /api/puck/pages\n * Create a new page with Puck data\n *\n * Request Body:\n * - title: string (required)\n * - slug: string (required)\n * - puckData?: PuckData (optional, uses default if not provided)\n * - status?: 'draft' | 'published' (default: 'draft')\n */\n async function POST(request: NextRequest, _context: RouteHandlerContext): Promise<Response> {\n try {\n // Authenticate\n const authResult = await auth.authenticate(request)\n if (!authResult.authenticated || !authResult.user) {\n return NextResponse.json(\n { error: authResult.error || 'Unauthorized' },\n { status: 401 }\n )\n }\n\n // Check create permission\n if (auth.canCreate) {\n const permission = await auth.canCreate(authResult.user)\n if (!permission.allowed) {\n return NextResponse.json(\n { error: permission.error || 'Forbidden' },\n { status: 403 }\n )\n }\n }\n\n // Parse request body\n const body = (await request.json()) as CreatePageBody\n const { title, slug, puckData, status = 'draft' } = body\n\n // Validate required fields\n if (!title || !slug) {\n return NextResponse.json(\n { error: 'Title and slug are required' },\n { status: 400 }\n )\n }\n\n // Get Payload instance with provided config\n const config = await payloadConfig\n const payload = await getPayload({ config })\n\n // Check if slug already exists\n const existing = await payload.find({\n collection,\n where: { slug: { equals: slug } },\n limit: 1,\n })\n\n if (existing.docs.length > 0) {\n return NextResponse.json(\n { error: 'A page with this slug already exists' },\n { status: 409 }\n )\n }\n\n // Prepare initial Puck data with title in root.props\n const initialPuckData = puckData || {\n ...defaultPuckData,\n root: {\n ...defaultPuckData.root,\n props: {\n ...(defaultPuckData.root as { props?: Record<string, unknown> })?.props,\n title,\n },\n },\n }\n\n // Create the page\n const newPage = await payload.create({\n collection,\n draft: enableDrafts,\n data: {\n title,\n slug,\n editorVersion: 'puck',\n puckData: initialPuckData,\n _status: status,\n },\n })\n\n return NextResponse.json({ doc: newPage }, { status: 201 })\n } catch (error) {\n if (onError) {\n onError(error, { operation: 'create', request })\n }\n console.error('Error creating page:', error)\n return NextResponse.json(\n { error: 'Failed to create page' },\n { status: 500 }\n )\n }\n }\n\n return { GET, POST }\n}\n","import type { RootPropsMapping } from '../types'\n\n/**\n * Default mappings from Puck root.props to Payload fields\n *\n * These mappings sync common page properties from Puck's visual editor\n * to the corresponding Payload collection fields.\n *\n * SEO fields use the official @payloadcms/plugin-seo convention: meta.title, meta.description\n */\nexport const DEFAULT_ROOT_PROPS_MAPPINGS: RootPropsMapping[] = [\n // Core page fields\n { from: 'title', to: 'title' },\n { from: 'slug', to: 'slug' },\n { from: 'pageLayout', to: 'pageLayout' },\n { from: 'pageType', to: 'pageType' },\n { from: 'isHomepage', to: 'isHomepage' },\n\n // SEO/Meta fields (uses official @payloadcms/plugin-seo convention)\n { from: 'metaTitle', to: 'meta.title' },\n { from: 'metaDescription', to: 'meta.description' },\n { from: 'noindex', to: 'meta.noindex' },\n { from: 'nofollow', to: 'meta.nofollow' },\n { from: 'excludeFromSitemap', to: 'meta.excludeFromSitemap' },\n\n // Conversion tracking fields\n { from: 'isConversionPage', to: 'conversionTracking.isConversionPage' },\n { from: 'conversionType', to: 'conversionTracking.conversionType' },\n { from: 'conversionValue', to: 'conversionTracking.conversionValue' },\n]\n\n/**\n * Set a nested value in an object using dot notation path\n *\n * @example\n * ```typescript\n * const obj = {}\n * setNestedValue(obj, 'meta.title', 'My Title')\n * // Result: { meta: { title: 'My Title' } }\n * ```\n */\nexport function setNestedValue(\n obj: Record<string, unknown>,\n path: string,\n value: unknown\n): void {\n const keys = path.split('.')\n let current = obj\n\n for (let i = 0; i < keys.length - 1; i++) {\n const key = keys[i]\n if (!(key in current) || typeof current[key] !== 'object') {\n current[key] = {}\n }\n current = current[key] as Record<string, unknown>\n }\n\n const finalKey = keys[keys.length - 1]\n current[finalKey] = value\n}\n\n/**\n * Get a nested value from an object using dot notation path\n *\n * @example\n * ```typescript\n * const obj = { meta: { title: 'My Title' } }\n * getNestedValue(obj, 'meta.title') // 'My Title'\n * ```\n */\nexport function getNestedValue(\n obj: Record<string, unknown>,\n path: string\n): unknown {\n const keys = path.split('.')\n let current: unknown = obj\n\n for (const key of keys) {\n if (current === null || current === undefined) {\n return undefined\n }\n if (typeof current !== 'object') {\n return undefined\n }\n current = (current as Record<string, unknown>)[key]\n }\n\n return current\n}\n\n/**\n * Merge mappings, with custom mappings taking precedence over defaults\n *\n * @param customMappings - Custom mappings to merge with defaults\n * @returns Merged array of mappings with duplicates resolved (custom wins)\n */\nexport function mergeMappings(\n customMappings?: RootPropsMapping[]\n): RootPropsMapping[] {\n if (!customMappings || customMappings.length === 0) {\n return DEFAULT_ROOT_PROPS_MAPPINGS\n }\n\n // Create a map to track unique mappings by 'from' field\n const mappingMap = new Map<string, RootPropsMapping>()\n\n // Add defaults first\n for (const mapping of DEFAULT_ROOT_PROPS_MAPPINGS) {\n mappingMap.set(mapping.from, mapping)\n }\n\n // Custom mappings override defaults\n for (const mapping of customMappings) {\n mappingMap.set(mapping.from, mapping)\n }\n\n return Array.from(mappingMap.values())\n}\n\n/**\n * Map Puck root.props to Payload field update data\n *\n * Takes the root.props from Puck data and maps them to the appropriate\n * Payload fields based on the provided mappings.\n *\n * @param rootProps - The root.props object from Puck data\n * @param customMappings - Optional custom mappings to merge with defaults\n * @returns Object ready to be spread into Payload update data\n *\n * @example\n * ```typescript\n * const rootProps = {\n * title: 'My Page',\n * metaTitle: 'My Page | Site Name',\n * metaDescription: 'Description here',\n * }\n *\n * const updateData = mapRootPropsToPayloadFields(rootProps)\n * // Result: {\n * // title: 'My Page',\n * // meta: {\n * // title: 'My Page | Site Name',\n * // description: 'Description here',\n * // },\n * // }\n * ```\n */\nexport function mapRootPropsToPayloadFields(\n rootProps: Record<string, unknown>,\n customMappings?: RootPropsMapping[]\n): Record<string, unknown> {\n const mappings = mergeMappings(customMappings)\n const result: Record<string, unknown> = {}\n\n for (const mapping of mappings) {\n const value = rootProps[mapping.from]\n\n // Skip undefined values to avoid overwriting existing data\n if (value === undefined) {\n continue\n }\n\n // Apply transformation if provided\n const transformedValue = mapping.transform ? mapping.transform(value) : value\n\n // Set the value at the target path\n setNestedValue(result, mapping.to, transformedValue)\n }\n\n return result\n}\n\n/**\n * Deep merge objects, with source values overwriting target values\n *\n * @param target - The target object to merge into\n * @param source - The source object to merge from\n * @returns The merged object (target is modified in place)\n */\nexport function deepMerge(\n target: Record<string, unknown>,\n source: Record<string, unknown>\n): Record<string, unknown> {\n for (const key of Object.keys(source)) {\n const sourceValue = source[key]\n const targetValue = target[key]\n\n if (\n sourceValue !== null &&\n typeof sourceValue === 'object' &&\n !Array.isArray(sourceValue) &&\n targetValue !== null &&\n typeof targetValue === 'object' &&\n !Array.isArray(targetValue)\n ) {\n // Recursively merge nested objects\n target[key] = deepMerge(\n targetValue as Record<string, unknown>,\n sourceValue as Record<string, unknown>\n )\n } else {\n // Direct assignment for non-object values or arrays\n target[key] = sourceValue\n }\n }\n\n return target\n}\n","import { NextRequest, NextResponse } from 'next/server'\nimport { getPayload } from 'payload'\nimport type {\n PuckApiRoutesConfig,\n PuckApiRouteWithIdHandlers,\n UpdatePageBody,\n RouteHandlerWithIdContext,\n} from './types'\nimport { mapRootPropsToPayloadFields, deepMerge } from './utils/mapRootProps'\n\n/**\n * Create API route handlers for /api/puck/pages/[id]\n *\n * Provides GET (fetch page), PATCH (update page), and DELETE (delete page)\n * handlers with configurable authentication and authorization.\n *\n * @example\n * ```typescript\n * // src/app/api/puck/pages/[id]/route.ts\n * import { createPuckApiRoutesWithId } from '@delmaredigital/payload-puck/api'\n * import config from '@payload-config'\n *\n * export const { GET, PATCH, DELETE } = createPuckApiRoutesWithId({\n * collection: 'pages',\n * payloadConfig: config,\n * auth: {\n * authenticate: async (request) => {\n * const session = await getSession(request)\n * if (!session?.user) return { authenticated: false }\n * return { authenticated: true, user: session.user }\n * },\n * canPublish: async (user) => {\n * return { allowed: user.role === 'admin' }\n * },\n * },\n * rootPropsMapping: [\n * { from: 'customField', to: 'customPayloadField' },\n * ],\n * })\n * ```\n */\nexport function createPuckApiRoutesWithId(\n routeConfig: PuckApiRoutesConfig\n): PuckApiRouteWithIdHandlers {\n const {\n collection = 'pages',\n payloadConfig,\n auth,\n rootPropsMapping,\n onError,\n } = routeConfig\n\n /**\n * GET /api/puck/pages/[id]\n * Fetch a single page by ID\n */\n async function GET(\n request: NextRequest,\n context: RouteHandlerWithIdContext\n ): Promise<Response> {\n try {\n // Get page ID from params\n const params = await context.params\n const id = params.id\n\n if (!id) {\n return NextResponse.json(\n { error: 'Page ID is required' },\n { status: 400 }\n )\n }\n\n // Authenticate\n const authResult = await auth.authenticate(request)\n if (!authResult.authenticated || !authResult.user) {\n return NextResponse.json(\n { error: authResult.error || 'Unauthorized' },\n { status: 401 }\n )\n }\n\n // Check view permission\n if (auth.canView) {\n const permission = await auth.canView(authResult.user, id)\n if (!permission.allowed) {\n return NextResponse.json(\n { error: permission.error || 'Forbidden' },\n { status: 403 }\n )\n }\n }\n\n // Get Payload instance with provided config\n const config = await payloadConfig\n const payload = await getPayload({ config })\n\n // Check if caller wants draft or published version\n // Default to draft=true for editor use (load latest draft)\n const url = new URL(request.url)\n const wantsDraft = url.searchParams.get('draft') !== 'false'\n\n const page = await payload.findByID({\n collection,\n id,\n draft: wantsDraft, // Load draft version by default for editing\n })\n\n if (!page) {\n return NextResponse.json({ error: 'Page not found' }, { status: 404 })\n }\n\n return NextResponse.json({ doc: page })\n } catch (error) {\n const params = await context.params\n if (onError) {\n onError(error, { operation: 'read', request, pageId: params.id })\n }\n console.error('Error fetching page:', error)\n return NextResponse.json(\n { error: 'Failed to fetch page' },\n { status: 500 }\n )\n }\n }\n\n /**\n * PATCH /api/puck/pages/[id]\n * Update a page with Puck data\n *\n * Request Body:\n * - puckData?: PuckData - Full Puck editor data\n * - title?: string - Override title (also synced from root.props)\n * - slug?: string - Override slug (also synced from root.props)\n * - status?: 'draft' | 'published' - Publishing status\n *\n * Root props from puckData are automatically synced to Payload fields\n * based on the configured mappings.\n */\n async function PATCH(\n request: NextRequest,\n context: RouteHandlerWithIdContext\n ): Promise<Response> {\n try {\n // Get page ID from params\n const params = await context.params\n const id = params.id\n\n if (!id) {\n return NextResponse.json(\n { error: 'Page ID is required' },\n { status: 400 }\n )\n }\n\n // Authenticate\n const authResult = await auth.authenticate(request)\n if (!authResult.authenticated || !authResult.user) {\n return NextResponse.json(\n { error: authResult.error || 'Unauthorized' },\n { status: 401 }\n )\n }\n\n // Check edit permission\n if (auth.canEdit) {\n const permission = await auth.canEdit(authResult.user, id)\n if (!permission.allowed) {\n return NextResponse.json(\n { error: permission.error || 'Forbidden' },\n { status: 403 }\n )\n }\n }\n\n // Parse request body\n const body = (await request.json()) as UpdatePageBody\n const { puckData, title, slug, status, draft } = body\n\n // Check publish permission only if explicitly publishing\n if (status === 'published') {\n const canPublish = auth.canPublish || auth.canEdit\n if (canPublish) {\n const permission = await canPublish(authResult.user, id)\n if (!permission.allowed) {\n return NextResponse.json(\n { error: permission.error || 'Not authorized to publish pages' },\n { status: 403 }\n )\n }\n }\n }\n\n // Get Payload instance with provided config\n const config = await payloadConfig\n const payload = await getPayload({ config })\n\n // Extract root props from puckData for syncing to Payload fields\n const rootProps =\n (puckData?.root as { props?: Record<string, unknown> })?.props || {}\n\n // Build update data starting with editorVersion\n const updateData: Record<string, unknown> = {\n editorVersion: 'puck',\n }\n\n // Add puckData if provided\n if (puckData) {\n updateData.puckData = puckData\n }\n\n // Map root.props to Payload fields\n const mappedFields = mapRootPropsToPayloadFields(rootProps, rootPropsMapping)\n\n // Merge mapped fields into update data (deep merge for nested objects)\n deepMerge(updateData, mappedFields)\n\n // Explicit title/slug override the mapped values\n if (title !== undefined) {\n updateData.title = title\n }\n if (slug !== undefined) {\n updateData.slug = slug\n }\n\n // Set status if provided (for explicit publish)\n if (status) {\n updateData._status = status\n }\n\n // Call payload.update with draft parameter for Payload's versions.drafts system\n // When draft=true, saves without publishing\n // When draft=false or status='published', publishes the document\n const updatedPage = await payload.update({\n collection,\n id,\n data: updateData,\n draft: draft === true,\n })\n\n return NextResponse.json({ doc: updatedPage })\n } catch (error) {\n const params = await context.params\n if (onError) {\n onError(error, { operation: 'update', request, pageId: params.id })\n }\n console.error('Error updating page:', error)\n\n // Handle Payload validation errors gracefully\n if (error instanceof Error && error.name === 'ValidationError') {\n const validationError = error as Error & {\n data?: { errors?: Array<{ field: string; message: string }> }\n }\n const fieldErrors = validationError.data?.errors || []\n\n // Check for common validation issues and provide friendly messages\n const slugError = fieldErrors.find((e) => e.field === 'slug')\n if (slugError) {\n return NextResponse.json(\n {\n error: 'A page with this slug already exists. Please choose a different slug.',\n field: 'slug',\n details: fieldErrors,\n },\n { status: 400 }\n )\n }\n\n // Generic validation error\n return NextResponse.json(\n {\n error: `Validation failed: ${fieldErrors.map((e) => e.message || e.field).join(', ')}`,\n details: fieldErrors,\n },\n { status: 400 }\n )\n }\n\n return NextResponse.json(\n { error: 'Failed to update page' },\n { status: 500 }\n )\n }\n }\n\n /**\n * DELETE /api/puck/pages/[id]\n * Delete a page by ID\n */\n async function DELETE(\n request: NextRequest,\n context: RouteHandlerWithIdContext\n ): Promise<Response> {\n try {\n // Get page ID from params\n const params = await context.params\n const id = params.id\n\n if (!id) {\n return NextResponse.json(\n { error: 'Page ID is required' },\n { status: 400 }\n )\n }\n\n // Authenticate\n const authResult = await auth.authenticate(request)\n if (!authResult.authenticated || !authResult.user) {\n return NextResponse.json(\n { error: authResult.error || 'Unauthorized' },\n { status: 401 }\n )\n }\n\n // Check delete permission\n if (auth.canDelete) {\n const permission = await auth.canDelete(authResult.user, id)\n if (!permission.allowed) {\n return NextResponse.json(\n { error: permission.error || 'Forbidden' },\n { status: 403 }\n )\n }\n }\n\n // Get Payload instance with provided config\n const config = await payloadConfig\n const payload = await getPayload({ config })\n\n await payload.delete({\n collection,\n id,\n })\n\n return NextResponse.json({ success: true })\n } catch (error) {\n const params = await context.params\n if (onError) {\n onError(error, { operation: 'delete', request, pageId: params.id })\n }\n console.error('Error deleting page:', error)\n return NextResponse.json(\n { error: 'Failed to delete page' },\n { status: 500 }\n )\n }\n }\n\n return { GET, PATCH, DELETE }\n}\n","import { NextRequest, NextResponse } from 'next/server'\nimport { getPayload } from 'payload'\nimport type {\n PuckApiRoutesConfig,\n PuckApiVersionsRouteHandlers,\n RouteHandlerWithIdContext,\n} from './types'\n\n/**\n * Create API route handlers for /api/puck/pages/[id]/versions\n *\n * Provides GET (list versions) and POST (restore version) handlers\n * for managing page version history.\n *\n * @example\n * ```typescript\n * // src/app/api/puck/pages/[id]/versions/route.ts\n * import { createPuckApiRoutesVersions } from '@delmaredigital/payload-puck/api'\n * import config from '@payload-config'\n *\n * export const { GET, POST } = createPuckApiRoutesVersions({\n * collection: 'pages',\n * payloadConfig: config,\n * auth: {\n * authenticate: async (request) => {\n * const session = await getSession(request)\n * if (!session?.user) return { authenticated: false }\n * return { authenticated: true, user: session.user }\n * },\n * },\n * })\n * ```\n */\nexport function createPuckApiRoutesVersions(\n routeConfig: PuckApiRoutesConfig\n): PuckApiVersionsRouteHandlers {\n const {\n collection = 'pages',\n payloadConfig,\n auth,\n onError,\n } = routeConfig\n\n /**\n * GET /api/puck/pages/[id]/versions\n * Fetch version history for a page\n */\n async function GET(\n request: NextRequest,\n context: RouteHandlerWithIdContext\n ): Promise<Response> {\n try {\n // Get page ID from params\n const params = await context.params\n const id = params.id\n\n if (!id) {\n return NextResponse.json(\n { error: 'Page ID is required' },\n { status: 400 }\n )\n }\n\n // Authenticate\n const authResult = await auth.authenticate(request)\n if (!authResult.authenticated || !authResult.user) {\n return NextResponse.json(\n { error: authResult.error || 'Unauthorized' },\n { status: 401 }\n )\n }\n\n // Check view permission\n if (auth.canView) {\n const permission = await auth.canView(authResult.user, id)\n if (!permission.allowed) {\n return NextResponse.json(\n { error: permission.error || 'Forbidden' },\n { status: 403 }\n )\n }\n }\n\n // Get Payload instance with provided config\n const config = await payloadConfig\n const payload = await getPayload({ config })\n\n // Parse query params for pagination\n const url = new URL(request.url)\n const limit = parseInt(url.searchParams.get('limit') || '20', 10)\n const page = parseInt(url.searchParams.get('page') || '1', 10)\n\n // Fetch versions for this page\n const versions = await payload.findVersions({\n collection,\n where: {\n parent: { equals: id },\n },\n sort: '-updatedAt',\n limit,\n page,\n })\n\n return NextResponse.json({\n docs: versions.docs,\n totalDocs: versions.totalDocs,\n totalPages: versions.totalPages,\n page: versions.page,\n limit: versions.limit,\n hasPrevPage: versions.hasPrevPage,\n hasNextPage: versions.hasNextPage,\n })\n } catch (error) {\n const params = await context.params\n if (onError) {\n onError(error, { operation: 'listVersions', request, pageId: params.id })\n }\n console.error('Error fetching versions:', error)\n return NextResponse.json(\n { error: 'Failed to fetch versions' },\n { status: 500 }\n )\n }\n }\n\n /**\n * POST /api/puck/pages/[id]/versions\n * Restore a specific version\n *\n * Request Body:\n * - versionId: string - The version ID to restore\n */\n async function POST(\n request: NextRequest,\n context: RouteHandlerWithIdContext\n ): Promise<Response> {\n try {\n // Get page ID from params\n const params = await context.params\n const id = params.id\n\n if (!id) {\n return NextResponse.json(\n { error: 'Page ID is required' },\n { status: 400 }\n )\n }\n\n // Authenticate\n const authResult = await auth.authenticate(request)\n if (!authResult.authenticated || !authResult.user) {\n return NextResponse.json(\n { error: authResult.error || 'Unauthorized' },\n { status: 401 }\n )\n }\n\n // Check edit permission\n if (auth.canEdit) {\n const permission = await auth.canEdit(authResult.user, id)\n if (!permission.allowed) {\n return NextResponse.json(\n { error: permission.error || 'Forbidden' },\n { status: 403 }\n )\n }\n }\n\n // Parse request body\n const body = await request.json()\n const { versionId } = body as { versionId: string }\n\n if (!versionId) {\n return NextResponse.json(\n { error: 'Version ID is required' },\n { status: 400 }\n )\n }\n\n // Get Payload instance with provided config\n const config = await payloadConfig\n const payload = await getPayload({ config })\n\n // Restore the version\n const restoredDoc = await payload.restoreVersion({\n collection,\n id: versionId,\n })\n\n return NextResponse.json({ doc: restoredDoc })\n } catch (error) {\n const params = await context.params\n if (onError) {\n onError(error, { operation: 'restoreVersion', request, pageId: params.id })\n }\n console.error('Error restoring version:', error)\n return NextResponse.json(\n { error: 'Failed to restore version' },\n { status: 500 }\n )\n }\n }\n\n return { GET, POST }\n}\n"]}
|
package/dist/api/index.mjs.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/api/createPuckApiRoutes.ts","../../src/api/utils/mapRootProps.ts","../../src/api/createPuckApiRoutesWithId.ts","../../src/api/createPuckApiRoutesVersions.ts"],"names":["NextResponse","getPayload"],"mappings":"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","file":"index.mjs","sourcesContent":["import { NextRequest, NextResponse } from 'next/server'\nimport { getPayload } from 'payload'\nimport type { Where } from 'payload'\nimport type { Data as PuckData } from '@measured/puck'\nimport type {\n PuckApiRoutesConfig,\n PuckApiRouteHandlers,\n CreatePageBody,\n RouteHandlerContext,\n} from './types'\n\n/**\n * Default Puck data for new pages\n */\nconst DEFAULT_PUCK_DATA: PuckData = {\n root: {\n props: {\n title: '',\n } as Record<string, unknown>,\n },\n content: [],\n zones: {},\n}\n\n/**\n * Create API route handlers for /api/puck/pages\n *\n * Provides GET (list pages) and POST (create page) handlers\n * with configurable authentication and authorization.\n *\n * @example\n * ```typescript\n * // src/app/api/puck/pages/route.ts\n * import { createPuckApiRoutes } from '@delmaredigital/payload-puck/api'\n * import config from '@payload-config'\n *\n * export const { GET, POST } = createPuckApiRoutes({\n * collection: 'pages',\n * payloadConfig: config,\n * auth: {\n * authenticate: async (request) => {\n * const session = await getSession(request)\n * if (!session?.user) return { authenticated: false }\n * return { authenticated: true, user: session.user }\n * },\n * canCreate: async (user) => {\n * return { allowed: user.role === 'admin' || user.role === 'editor' }\n * },\n * },\n * })\n * ```\n */\nexport function createPuckApiRoutes(\n routeConfig: PuckApiRoutesConfig\n): PuckApiRouteHandlers {\n const {\n collection = 'pages',\n payloadConfig,\n auth,\n defaultPuckData = DEFAULT_PUCK_DATA,\n enableDrafts = true,\n onError,\n } = routeConfig\n\n /**\n * GET /api/puck/pages\n * List all pages with optional filtering\n *\n * Query Parameters:\n * - page: Page number (default: 1)\n * - limit: Items per page (default: 10)\n * - search: Search in title field\n * - status: Filter by _status ('draft', 'published', 'all')\n * - editorVersion: Filter by editorVersion field\n * - sort: Sort field (default: '-updatedAt')\n */\n async function GET(request: NextRequest, _context: RouteHandlerContext): Promise<Response> {\n try {\n // Authenticate\n const authResult = await auth.authenticate(request)\n if (!authResult.authenticated || !authResult.user) {\n return NextResponse.json(\n { error: authResult.error || 'Unauthorized' },\n { status: 401 }\n )\n }\n\n // Check list permission\n if (auth.canList) {\n const permission = await auth.canList(authResult.user)\n if (!permission.allowed) {\n return NextResponse.json(\n { error: permission.error || 'Forbidden' },\n { status: 403 }\n )\n }\n }\n\n // Parse query parameters\n const { searchParams } = new URL(request.url)\n const page = parseInt(searchParams.get('page') || '1', 10)\n const limit = Math.min(parseInt(searchParams.get('limit') || '10', 10), 100)\n const search = searchParams.get('search') || ''\n const status = searchParams.get('status')\n const editorVersion = searchParams.get('editorVersion')\n const sort = searchParams.get('sort') || '-updatedAt'\n\n // Get Payload instance with provided config\n const config = await payloadConfig\n const payload = await getPayload({ config })\n\n // Build where clause\n const conditions: Where[] = []\n\n if (search) {\n conditions.push({ title: { contains: search } })\n }\n\n if (status && status !== 'all') {\n conditions.push({ _status: { equals: status } })\n }\n\n if (editorVersion && editorVersion !== 'all') {\n conditions.push({ editorVersion: { equals: editorVersion } })\n }\n\n const where: Where | undefined =\n conditions.length > 0\n ? conditions.length === 1\n ? conditions[0]\n : { and: conditions }\n : undefined\n\n const result = await payload.find({\n collection,\n page,\n limit,\n sort,\n where,\n })\n\n return NextResponse.json(result)\n } catch (error) {\n if (onError) {\n onError(error, { operation: 'list', request })\n }\n console.error('Error listing pages:', error)\n return NextResponse.json(\n { error: 'Failed to list pages' },\n { status: 500 }\n )\n }\n }\n\n /**\n * POST /api/puck/pages\n * Create a new page with Puck data\n *\n * Request Body:\n * - title: string (required)\n * - slug: string (required)\n * - puckData?: PuckData (optional, uses default if not provided)\n * - status?: 'draft' | 'published' (default: 'draft')\n */\n async function POST(request: NextRequest, _context: RouteHandlerContext): Promise<Response> {\n try {\n // Authenticate\n const authResult = await auth.authenticate(request)\n if (!authResult.authenticated || !authResult.user) {\n return NextResponse.json(\n { error: authResult.error || 'Unauthorized' },\n { status: 401 }\n )\n }\n\n // Check create permission\n if (auth.canCreate) {\n const permission = await auth.canCreate(authResult.user)\n if (!permission.allowed) {\n return NextResponse.json(\n { error: permission.error || 'Forbidden' },\n { status: 403 }\n )\n }\n }\n\n // Parse request body\n const body = (await request.json()) as CreatePageBody\n const { title, slug, puckData, status = 'draft' } = body\n\n // Validate required fields\n if (!title || !slug) {\n return NextResponse.json(\n { error: 'Title and slug are required' },\n { status: 400 }\n )\n }\n\n // Get Payload instance with provided config\n const config = await payloadConfig\n const payload = await getPayload({ config })\n\n // Check if slug already exists\n const existing = await payload.find({\n collection,\n where: { slug: { equals: slug } },\n limit: 1,\n })\n\n if (existing.docs.length > 0) {\n return NextResponse.json(\n { error: 'A page with this slug already exists' },\n { status: 409 }\n )\n }\n\n // Prepare initial Puck data with title in root.props\n const initialPuckData = puckData || {\n ...defaultPuckData,\n root: {\n ...defaultPuckData.root,\n props: {\n ...(defaultPuckData.root as { props?: Record<string, unknown> })?.props,\n title,\n },\n },\n }\n\n // Create the page\n const newPage = await payload.create({\n collection,\n draft: enableDrafts,\n data: {\n title,\n slug,\n editorVersion: 'puck',\n puckData: initialPuckData,\n _status: status,\n },\n })\n\n return NextResponse.json({ doc: newPage }, { status: 201 })\n } catch (error) {\n if (onError) {\n onError(error, { operation: 'create', request })\n }\n console.error('Error creating page:', error)\n return NextResponse.json(\n { error: 'Failed to create page' },\n { status: 500 }\n )\n }\n }\n\n return { GET, POST }\n}\n","import type { RootPropsMapping } from '../types'\n\n/**\n * Default mappings from Puck root.props to Payload fields\n *\n * These mappings sync common page properties from Puck's visual editor\n * to the corresponding Payload collection fields.\n *\n * SEO fields use the official @payloadcms/plugin-seo convention: meta.title, meta.description\n */\nexport const DEFAULT_ROOT_PROPS_MAPPINGS: RootPropsMapping[] = [\n // Core page fields\n { from: 'title', to: 'title' },\n { from: 'slug', to: 'slug' },\n { from: 'pageLayout', to: 'pageLayout' },\n { from: 'pageType', to: 'pageType' },\n { from: 'isHomepage', to: 'isHomepage' },\n\n // SEO/Meta fields (uses official @payloadcms/plugin-seo convention)\n { from: 'metaTitle', to: 'meta.title' },\n { from: 'metaDescription', to: 'meta.description' },\n { from: 'noindex', to: 'meta.noindex' },\n { from: 'nofollow', to: 'meta.nofollow' },\n { from: 'excludeFromSitemap', to: 'meta.excludeFromSitemap' },\n\n // Conversion tracking fields\n { from: 'isConversionPage', to: 'conversionTracking.isConversionPage' },\n { from: 'conversionType', to: 'conversionTracking.conversionType' },\n { from: 'conversionValue', to: 'conversionTracking.conversionValue' },\n]\n\n/**\n * Set a nested value in an object using dot notation path\n *\n * @example\n * ```typescript\n * const obj = {}\n * setNestedValue(obj, 'meta.title', 'My Title')\n * // Result: { meta: { title: 'My Title' } }\n * ```\n */\nexport function setNestedValue(\n obj: Record<string, unknown>,\n path: string,\n value: unknown\n): void {\n const keys = path.split('.')\n let current = obj\n\n for (let i = 0; i < keys.length - 1; i++) {\n const key = keys[i]\n if (!(key in current) || typeof current[key] !== 'object') {\n current[key] = {}\n }\n current = current[key] as Record<string, unknown>\n }\n\n const finalKey = keys[keys.length - 1]\n current[finalKey] = value\n}\n\n/**\n * Get a nested value from an object using dot notation path\n *\n * @example\n * ```typescript\n * const obj = { meta: { title: 'My Title' } }\n * getNestedValue(obj, 'meta.title') // 'My Title'\n * ```\n */\nexport function getNestedValue(\n obj: Record<string, unknown>,\n path: string\n): unknown {\n const keys = path.split('.')\n let current: unknown = obj\n\n for (const key of keys) {\n if (current === null || current === undefined) {\n return undefined\n }\n if (typeof current !== 'object') {\n return undefined\n }\n current = (current as Record<string, unknown>)[key]\n }\n\n return current\n}\n\n/**\n * Merge mappings, with custom mappings taking precedence over defaults\n *\n * @param customMappings - Custom mappings to merge with defaults\n * @returns Merged array of mappings with duplicates resolved (custom wins)\n */\nexport function mergeMappings(\n customMappings?: RootPropsMapping[]\n): RootPropsMapping[] {\n if (!customMappings || customMappings.length === 0) {\n return DEFAULT_ROOT_PROPS_MAPPINGS\n }\n\n // Create a map to track unique mappings by 'from' field\n const mappingMap = new Map<string, RootPropsMapping>()\n\n // Add defaults first\n for (const mapping of DEFAULT_ROOT_PROPS_MAPPINGS) {\n mappingMap.set(mapping.from, mapping)\n }\n\n // Custom mappings override defaults\n for (const mapping of customMappings) {\n mappingMap.set(mapping.from, mapping)\n }\n\n return Array.from(mappingMap.values())\n}\n\n/**\n * Map Puck root.props to Payload field update data\n *\n * Takes the root.props from Puck data and maps them to the appropriate\n * Payload fields based on the provided mappings.\n *\n * @param rootProps - The root.props object from Puck data\n * @param customMappings - Optional custom mappings to merge with defaults\n * @returns Object ready to be spread into Payload update data\n *\n * @example\n * ```typescript\n * const rootProps = {\n * title: 'My Page',\n * metaTitle: 'My Page | Site Name',\n * metaDescription: 'Description here',\n * }\n *\n * const updateData = mapRootPropsToPayloadFields(rootProps)\n * // Result: {\n * // title: 'My Page',\n * // meta: {\n * // title: 'My Page | Site Name',\n * // description: 'Description here',\n * // },\n * // }\n * ```\n */\nexport function mapRootPropsToPayloadFields(\n rootProps: Record<string, unknown>,\n customMappings?: RootPropsMapping[]\n): Record<string, unknown> {\n const mappings = mergeMappings(customMappings)\n const result: Record<string, unknown> = {}\n\n for (const mapping of mappings) {\n const value = rootProps[mapping.from]\n\n // Skip undefined values to avoid overwriting existing data\n if (value === undefined) {\n continue\n }\n\n // Apply transformation if provided\n const transformedValue = mapping.transform ? mapping.transform(value) : value\n\n // Set the value at the target path\n setNestedValue(result, mapping.to, transformedValue)\n }\n\n return result\n}\n\n/**\n * Deep merge objects, with source values overwriting target values\n *\n * @param target - The target object to merge into\n * @param source - The source object to merge from\n * @returns The merged object (target is modified in place)\n */\nexport function deepMerge(\n target: Record<string, unknown>,\n source: Record<string, unknown>\n): Record<string, unknown> {\n for (const key of Object.keys(source)) {\n const sourceValue = source[key]\n const targetValue = target[key]\n\n if (\n sourceValue !== null &&\n typeof sourceValue === 'object' &&\n !Array.isArray(sourceValue) &&\n targetValue !== null &&\n typeof targetValue === 'object' &&\n !Array.isArray(targetValue)\n ) {\n // Recursively merge nested objects\n target[key] = deepMerge(\n targetValue as Record<string, unknown>,\n sourceValue as Record<string, unknown>\n )\n } else {\n // Direct assignment for non-object values or arrays\n target[key] = sourceValue\n }\n }\n\n return target\n}\n","import { NextRequest, NextResponse } from 'next/server'\nimport { getPayload } from 'payload'\nimport type {\n PuckApiRoutesConfig,\n PuckApiRouteWithIdHandlers,\n UpdatePageBody,\n RouteHandlerWithIdContext,\n} from './types'\nimport { mapRootPropsToPayloadFields, deepMerge } from './utils/mapRootProps'\n\n/**\n * Create API route handlers for /api/puck/pages/[id]\n *\n * Provides GET (fetch page), PATCH (update page), and DELETE (delete page)\n * handlers with configurable authentication and authorization.\n *\n * @example\n * ```typescript\n * // src/app/api/puck/pages/[id]/route.ts\n * import { createPuckApiRoutesWithId } from '@delmaredigital/payload-puck/api'\n * import config from '@payload-config'\n *\n * export const { GET, PATCH, DELETE } = createPuckApiRoutesWithId({\n * collection: 'pages',\n * payloadConfig: config,\n * auth: {\n * authenticate: async (request) => {\n * const session = await getSession(request)\n * if (!session?.user) return { authenticated: false }\n * return { authenticated: true, user: session.user }\n * },\n * canPublish: async (user) => {\n * return { allowed: user.role === 'admin' }\n * },\n * },\n * rootPropsMapping: [\n * { from: 'customField', to: 'customPayloadField' },\n * ],\n * })\n * ```\n */\nexport function createPuckApiRoutesWithId(\n routeConfig: PuckApiRoutesConfig\n): PuckApiRouteWithIdHandlers {\n const {\n collection = 'pages',\n payloadConfig,\n auth,\n rootPropsMapping,\n onError,\n } = routeConfig\n\n /**\n * GET /api/puck/pages/[id]\n * Fetch a single page by ID\n */\n async function GET(\n request: NextRequest,\n context: RouteHandlerWithIdContext\n ): Promise<Response> {\n try {\n // Get page ID from params\n const params = await context.params\n const id = params.id\n\n if (!id) {\n return NextResponse.json(\n { error: 'Page ID is required' },\n { status: 400 }\n )\n }\n\n // Authenticate\n const authResult = await auth.authenticate(request)\n if (!authResult.authenticated || !authResult.user) {\n return NextResponse.json(\n { error: authResult.error || 'Unauthorized' },\n { status: 401 }\n )\n }\n\n // Check view permission\n if (auth.canView) {\n const permission = await auth.canView(authResult.user, id)\n if (!permission.allowed) {\n return NextResponse.json(\n { error: permission.error || 'Forbidden' },\n { status: 403 }\n )\n }\n }\n\n // Get Payload instance with provided config\n const config = await payloadConfig\n const payload = await getPayload({ config })\n\n // Check if caller wants draft or published version\n // Default to draft=true for editor use (load latest draft)\n const url = new URL(request.url)\n const wantsDraft = url.searchParams.get('draft') !== 'false'\n\n const page = await payload.findByID({\n collection,\n id,\n draft: wantsDraft, // Load draft version by default for editing\n })\n\n if (!page) {\n return NextResponse.json({ error: 'Page not found' }, { status: 404 })\n }\n\n return NextResponse.json({ doc: page })\n } catch (error) {\n const params = await context.params\n if (onError) {\n onError(error, { operation: 'read', request, pageId: params.id })\n }\n console.error('Error fetching page:', error)\n return NextResponse.json(\n { error: 'Failed to fetch page' },\n { status: 500 }\n )\n }\n }\n\n /**\n * PATCH /api/puck/pages/[id]\n * Update a page with Puck data\n *\n * Request Body:\n * - puckData?: PuckData - Full Puck editor data\n * - title?: string - Override title (also synced from root.props)\n * - slug?: string - Override slug (also synced from root.props)\n * - status?: 'draft' | 'published' - Publishing status\n *\n * Root props from puckData are automatically synced to Payload fields\n * based on the configured mappings.\n */\n async function PATCH(\n request: NextRequest,\n context: RouteHandlerWithIdContext\n ): Promise<Response> {\n try {\n // Get page ID from params\n const params = await context.params\n const id = params.id\n\n if (!id) {\n return NextResponse.json(\n { error: 'Page ID is required' },\n { status: 400 }\n )\n }\n\n // Authenticate\n const authResult = await auth.authenticate(request)\n if (!authResult.authenticated || !authResult.user) {\n return NextResponse.json(\n { error: authResult.error || 'Unauthorized' },\n { status: 401 }\n )\n }\n\n // Check edit permission\n if (auth.canEdit) {\n const permission = await auth.canEdit(authResult.user, id)\n if (!permission.allowed) {\n return NextResponse.json(\n { error: permission.error || 'Forbidden' },\n { status: 403 }\n )\n }\n }\n\n // Parse request body\n const body = (await request.json()) as UpdatePageBody\n const { puckData, title, slug, status, draft } = body\n\n // Check publish permission only if explicitly publishing\n if (status === 'published') {\n const canPublish = auth.canPublish || auth.canEdit\n if (canPublish) {\n const permission = await canPublish(authResult.user, id)\n if (!permission.allowed) {\n return NextResponse.json(\n { error: permission.error || 'Not authorized to publish pages' },\n { status: 403 }\n )\n }\n }\n }\n\n // Get Payload instance with provided config\n const config = await payloadConfig\n const payload = await getPayload({ config })\n\n // Extract root props from puckData for syncing to Payload fields\n const rootProps =\n (puckData?.root as { props?: Record<string, unknown> })?.props || {}\n\n // Build update data starting with editorVersion\n const updateData: Record<string, unknown> = {\n editorVersion: 'puck',\n }\n\n // Add puckData if provided\n if (puckData) {\n updateData.puckData = puckData\n }\n\n // Map root.props to Payload fields\n const mappedFields = mapRootPropsToPayloadFields(rootProps, rootPropsMapping)\n\n // Merge mapped fields into update data (deep merge for nested objects)\n deepMerge(updateData, mappedFields)\n\n // Explicit title/slug override the mapped values\n if (title !== undefined) {\n updateData.title = title\n }\n if (slug !== undefined) {\n updateData.slug = slug\n }\n\n // Set status if provided (for explicit publish)\n if (status) {\n updateData._status = status\n }\n\n // Call payload.update with draft parameter for Payload's versions.drafts system\n // When draft=true, saves without publishing\n // When draft=false or status='published', publishes the document\n const updatedPage = await payload.update({\n collection,\n id,\n data: updateData,\n draft: draft === true,\n })\n\n return NextResponse.json({ doc: updatedPage })\n } catch (error) {\n const params = await context.params\n if (onError) {\n onError(error, { operation: 'update', request, pageId: params.id })\n }\n console.error('Error updating page:', error)\n\n // Handle Payload validation errors gracefully\n if (error instanceof Error && error.name === 'ValidationError') {\n const validationError = error as Error & {\n data?: { errors?: Array<{ field: string; message: string }> }\n }\n const fieldErrors = validationError.data?.errors || []\n\n // Check for common validation issues and provide friendly messages\n const slugError = fieldErrors.find((e) => e.field === 'slug')\n if (slugError) {\n return NextResponse.json(\n {\n error: 'A page with this slug already exists. Please choose a different slug.',\n field: 'slug',\n details: fieldErrors,\n },\n { status: 400 }\n )\n }\n\n // Generic validation error\n return NextResponse.json(\n {\n error: `Validation failed: ${fieldErrors.map((e) => e.message || e.field).join(', ')}`,\n details: fieldErrors,\n },\n { status: 400 }\n )\n }\n\n return NextResponse.json(\n { error: 'Failed to update page' },\n { status: 500 }\n )\n }\n }\n\n /**\n * DELETE /api/puck/pages/[id]\n * Delete a page by ID\n */\n async function DELETE(\n request: NextRequest,\n context: RouteHandlerWithIdContext\n ): Promise<Response> {\n try {\n // Get page ID from params\n const params = await context.params\n const id = params.id\n\n if (!id) {\n return NextResponse.json(\n { error: 'Page ID is required' },\n { status: 400 }\n )\n }\n\n // Authenticate\n const authResult = await auth.authenticate(request)\n if (!authResult.authenticated || !authResult.user) {\n return NextResponse.json(\n { error: authResult.error || 'Unauthorized' },\n { status: 401 }\n )\n }\n\n // Check delete permission\n if (auth.canDelete) {\n const permission = await auth.canDelete(authResult.user, id)\n if (!permission.allowed) {\n return NextResponse.json(\n { error: permission.error || 'Forbidden' },\n { status: 403 }\n )\n }\n }\n\n // Get Payload instance with provided config\n const config = await payloadConfig\n const payload = await getPayload({ config })\n\n await payload.delete({\n collection,\n id,\n })\n\n return NextResponse.json({ success: true })\n } catch (error) {\n const params = await context.params\n if (onError) {\n onError(error, { operation: 'delete', request, pageId: params.id })\n }\n console.error('Error deleting page:', error)\n return NextResponse.json(\n { error: 'Failed to delete page' },\n { status: 500 }\n )\n }\n }\n\n return { GET, PATCH, DELETE }\n}\n","import { NextRequest, NextResponse } from 'next/server'\nimport { getPayload } from 'payload'\nimport type {\n PuckApiRoutesConfig,\n PuckApiVersionsRouteHandlers,\n RouteHandlerWithIdContext,\n} from './types'\n\n/**\n * Create API route handlers for /api/puck/pages/[id]/versions\n *\n * Provides GET (list versions) and POST (restore version) handlers\n * for managing page version history.\n *\n * @example\n * ```typescript\n * // src/app/api/puck/pages/[id]/versions/route.ts\n * import { createPuckApiRoutesVersions } from '@delmaredigital/payload-puck/api'\n * import config from '@payload-config'\n *\n * export const { GET, POST } = createPuckApiRoutesVersions({\n * collection: 'pages',\n * payloadConfig: config,\n * auth: {\n * authenticate: async (request) => {\n * const session = await getSession(request)\n * if (!session?.user) return { authenticated: false }\n * return { authenticated: true, user: session.user }\n * },\n * },\n * })\n * ```\n */\nexport function createPuckApiRoutesVersions(\n routeConfig: PuckApiRoutesConfig\n): PuckApiVersionsRouteHandlers {\n const {\n collection = 'pages',\n payloadConfig,\n auth,\n onError,\n } = routeConfig\n\n /**\n * GET /api/puck/pages/[id]/versions\n * Fetch version history for a page\n */\n async function GET(\n request: NextRequest,\n context: RouteHandlerWithIdContext\n ): Promise<Response> {\n try {\n // Get page ID from params\n const params = await context.params\n const id = params.id\n\n if (!id) {\n return NextResponse.json(\n { error: 'Page ID is required' },\n { status: 400 }\n )\n }\n\n // Authenticate\n const authResult = await auth.authenticate(request)\n if (!authResult.authenticated || !authResult.user) {\n return NextResponse.json(\n { error: authResult.error || 'Unauthorized' },\n { status: 401 }\n )\n }\n\n // Check view permission\n if (auth.canView) {\n const permission = await auth.canView(authResult.user, id)\n if (!permission.allowed) {\n return NextResponse.json(\n { error: permission.error || 'Forbidden' },\n { status: 403 }\n )\n }\n }\n\n // Get Payload instance with provided config\n const config = await payloadConfig\n const payload = await getPayload({ config })\n\n // Parse query params for pagination\n const url = new URL(request.url)\n const limit = parseInt(url.searchParams.get('limit') || '20', 10)\n const page = parseInt(url.searchParams.get('page') || '1', 10)\n\n // Fetch versions for this page\n const versions = await payload.findVersions({\n collection,\n where: {\n parent: { equals: id },\n },\n sort: '-updatedAt',\n limit,\n page,\n })\n\n return NextResponse.json({\n docs: versions.docs,\n totalDocs: versions.totalDocs,\n totalPages: versions.totalPages,\n page: versions.page,\n limit: versions.limit,\n hasPrevPage: versions.hasPrevPage,\n hasNextPage: versions.hasNextPage,\n })\n } catch (error) {\n const params = await context.params\n if (onError) {\n onError(error, { operation: 'listVersions', request, pageId: params.id })\n }\n console.error('Error fetching versions:', error)\n return NextResponse.json(\n { error: 'Failed to fetch versions' },\n { status: 500 }\n )\n }\n }\n\n /**\n * POST /api/puck/pages/[id]/versions\n * Restore a specific version\n *\n * Request Body:\n * - versionId: string - The version ID to restore\n */\n async function POST(\n request: NextRequest,\n context: RouteHandlerWithIdContext\n ): Promise<Response> {\n try {\n // Get page ID from params\n const params = await context.params\n const id = params.id\n\n if (!id) {\n return NextResponse.json(\n { error: 'Page ID is required' },\n { status: 400 }\n )\n }\n\n // Authenticate\n const authResult = await auth.authenticate(request)\n if (!authResult.authenticated || !authResult.user) {\n return NextResponse.json(\n { error: authResult.error || 'Unauthorized' },\n { status: 401 }\n )\n }\n\n // Check edit permission\n if (auth.canEdit) {\n const permission = await auth.canEdit(authResult.user, id)\n if (!permission.allowed) {\n return NextResponse.json(\n { error: permission.error || 'Forbidden' },\n { status: 403 }\n )\n }\n }\n\n // Parse request body\n const body = await request.json()\n const { versionId } = body as { versionId: string }\n\n if (!versionId) {\n return NextResponse.json(\n { error: 'Version ID is required' },\n { status: 400 }\n )\n }\n\n // Get Payload instance with provided config\n const config = await payloadConfig\n const payload = await getPayload({ config })\n\n // Restore the version\n const restoredDoc = await payload.restoreVersion({\n collection,\n id: versionId,\n })\n\n return NextResponse.json({ doc: restoredDoc })\n } catch (error) {\n const params = await context.params\n if (onError) {\n onError(error, { operation: 'restoreVersion', request, pageId: params.id })\n }\n console.error('Error restoring version:', error)\n return NextResponse.json(\n { error: 'Failed to restore version' },\n { status: 500 }\n )\n }\n }\n\n return { GET, POST }\n}\n"]}
|