import React, { CSSProperties } from 'react'; import { useNode, UserComponent } from '@craftjs/core'; import { cssPropsToString } from '../../utils/style-helpers'; import { relayFormWiring } from '../../utils/form-relay-wiring'; import { escapeHtml, escapeAttr } from '../../utils/escape'; interface SubscribeFormProps { heading?: string; placeholder?: string; buttonText?: string; buttonColor?: string; layout?: 'inline' | 'stacked'; style?: CSSProperties; /** "Send submissions to" address -- same relay contract as ContactForm/ * FormContainer (see utils/form-relay-wiring.ts). Blank = no relay; the * published form then has no working action at all, which is the bug * this prop exists to fix. */ recipientEmail?: string; thankYouUrl?: string; animation?: string; animationDelay?: string; hideOnDesktop?: boolean; hideOnTablet?: boolean; hideOnMobile?: boolean; } export const SubscribeForm: UserComponent = ({ heading = 'Subscribe to our newsletter', placeholder = 'Enter your email', buttonText = 'Subscribe', buttonColor = '#3b82f6', layout = 'inline', style = {}, }) => { const { connectors: { connect, drag }, selected, } = useNode((node) => ({ selected: node.events.selected, })); const isInline = layout === 'inline'; return (
{ if (ref) connect(drag(ref)); }} style={{ padding: '40px 24px', textAlign: 'center', outline: selected ? '2px solid #3b82f6' : 'none', ...style, }} > {heading && (

{heading}

)}
e.preventDefault()} style={{ display: 'flex', flexDirection: isInline ? 'row' : 'column', gap: isInline ? '0' : '12px', maxWidth: isInline ? '480px' : '360px', margin: '0 auto', alignItems: 'stretch', }} >
); }; /* ---------- Craft config ---------- */ SubscribeForm.craft = { displayName: 'Subscribe Form', props: { heading: 'Subscribe to our newsletter', placeholder: 'Enter your email', buttonText: 'Subscribe', buttonColor: '#3b82f6', layout: 'inline', style: { backgroundColor: '#f8fafc' }, recipientEmail: '', thankYouUrl: '', animation: '', animationDelay: '', hideOnDesktop: false, hideOnTablet: false, hideOnMobile: false, }, rules: { canDrag: () => true, canMoveIn: () => false, canMoveOut: () => true, }, }; /* ---------- HTML export ---------- */ (SubscribeForm as any).toHtml = (props: SubscribeFormProps, _childrenHtml: string, nodeId?: string) => { const { heading = 'Subscribe to our newsletter', placeholder = 'Enter your email', buttonText = 'Subscribe', buttonColor = '#3b82f6', layout = 'inline', style = {}, } = props; const isInline = layout === 'inline'; const wrapperStyle = cssPropsToString({ padding: '40px 24px', textAlign: 'center', ...style, }); const headingHtml = heading ? `

${escapeHtml(heading)}

` : ''; const formStyle = cssPropsToString({ display: 'flex', flexDirection: isInline ? 'row' : 'column', gap: isInline ? '0' : '12px', maxWidth: isInline ? '480px' : '360px', margin: '0 auto', alignItems: 'stretch', }); const inputStyleStr = `flex:1;padding:12px 16px;font-size:15px;font-family:Inter,sans-serif;border:1px solid #d1d5db;border-radius:${isInline ? '8px 0 0 8px' : '8px'};background-color:#ffffff;color:#1f2937;outline:none;box-sizing:border-box`; const btnStyle = cssPropsToString({ padding: '12px 24px', fontSize: '15px', fontWeight: '600', fontFamily: 'Inter, sans-serif', color: '#ffffff', backgroundColor: buttonColor, border: 'none', borderRadius: isInline ? '0 8px 8px 0' : '8px', cursor: 'pointer', whiteSpace: 'nowrap', }); // Same relay contract as ContactForm/FormContainer: a recipientEmail wires // the form through the WHP form-sender relay (marker + placeholder action // + honeypot, provisioned/rewritten at publish time). Previously this form // always emitted `
` with NO action at all -- a // published subscribe form silently did nothing on submit. Falling back to // `formAction`-less relay wiring (fallbackAction undefined -> '#') keeps // the old no-recipient case visually identical (action="#") while making // the relay path actually functional once an admin sets an email. const { marker, actionAttr, honeypot } = relayFormWiring(props.recipientEmail, props.thankYouUrl, undefined, nodeId); return { html: `${marker} ${headingHtml} ${honeypot ? ` ${honeypot}\n` : ''} `, }; };