import React from 'react' import { useDroppable } from '@dnd-kit/core' import { SortableContext, verticalListSortingStrategy, } from '@dnd-kit/sortable' import { CheckCircle2, RotateCcw } from 'lucide-react' import FormField from './FormField' import { useFormStore } from '../store/useFormStore' import { applyFilters, Slot, useRegistryVersion } from '../extensions/registry' import { shouldFieldBeVisible } from '../utils/evaluateConditions' import { loadFormFont } from '../utils/resolveFieldStyle' export default function Canvas() { useRegistryVersion() const fields = useFormStore((state) => state.fields) const previewData = useFormStore((state) => state.previewData) const setActiveFieldId = useFormStore((state) => state.setActiveFieldId) // The top-level fields drawn now (an extension may show a subset with the `canvas.visibleFields` filter). The // selector returns a string so it only re-renders when the drawn set changes. const visibleKey = useFormStore((state) => (applyFilters('canvas.visibleFields', state.fields, state) || state.fields).map((f) => f.id).join('\u0001')) const dragOverContainer = useFormStore((state) => state.dragOverContainer) const dragOverIndex = useFormStore((state) => state.dragOverIndex) const viewMode = useFormStore((state) => state.viewMode) const isSubmittedInPreview = useFormStore((state) => state.isSubmittedInPreview) const resetPreview = useFormStore((state) => state.resetPreview) const settings = useFormStore((state) => state.settings) const hiddenElements = useFormStore((state) => state.hiddenElements) React.useEffect(() => { if (settings?.fontFamily) { loadFormFont(settings.fontFamily) } // The form font for the canvas typography rules in index.css. const font = (settings?.fontFamily || 'Arial').replace(/['"]/g, '') document.documentElement.style.setProperty('--wpvfb-canvas-font', `'${font}'`) }, [settings?.fontFamily]) const { setNodeRef } = useDroppable({ id: 'canvas-dropzone' }) // Simulated confirmation screen in preview mode if (viewMode === 'preview' && isSubmittedInPreview) { return (

{settings.confirmationTitle || 'Submission Received!'}

{settings.confirmationMessage || settings.confirmations?.[0]?.message || 'Thank you! Your submission has been received successfully in this preview test.'}

) } const visibleIds = new Set(visibleKey ? visibleKey.split('\u0001') : []) const visibleFields = fields.filter((f) => visibleIds.has(f.id)) const isOverCanvas = dragOverContainer && dragOverContainer.type === 'top' // Fields actually drawn on this page (conditional logic in preview, Layers eye toggle). const renderedFields = visibleFields.filter((field) => !(viewMode === 'preview' && !shouldFieldBeVisible(field, previewData, fields)) && !hiddenElements.has(field.id) ) // dragOverIndex is an insertion index into `fields` (0..fields.length; fields.length = after the last field). // The line goes before the first drawn field at or after that index, otherwise after the last one. const dropBeforeField = isOverCanvas && dragOverIndex !== null && dragOverIndex !== undefined && dragOverIndex < fields.length ? renderedFields.find((f) => fields.indexOf(f) >= dragOverIndex) || null : null const showPlaceholderAtEnd = isOverCanvas && !dropBeforeField return (
{/* Extension content above the fields */} {/* 2. Form Fields Canvas dropzone list */}
{ if ( !e.target.closest('[data-field-id]') && !e.target.closest('[data-edit-button]') && !e.target.closest('[data-prevent-outside-click]') ) { setActiveFieldId(null) } }} > {visibleFields.length === 0 ? (
{isOverCanvas && (
{ if (el) { requestAnimationFrame(() => { requestAnimationFrame(() => { el.style.width = '100%' }) }) } }} />
Drag it here
)}

Start building your form

Drag or click fields from the sidebar into this area to build your form.

Tip: Start with a text or email field, then add more from the sidebar.

) : ( f.id)} strategy={verticalListSortingStrategy} >
{renderedFields.map((field) => { const isPlaceholderHere = dropBeforeField === field return ( {isPlaceholderHere && (
{ if (el) { requestAnimationFrame(() => { requestAnimationFrame(() => { el.style.width = '100%' }) }) } }} />
Drag it here
)} ) })} {showPlaceholderAtEnd && (
{ if (el) { requestAnimationFrame(() => { requestAnimationFrame(() => { el.style.width = '100%' }) }) } }} />
Drag it here
)}
)} {/* No auto-added submit button: like the reference builder, the canvas only shows submit fields the form really has. */}
{/* Extension content below the fields */}
) }