Two components of the det-id bug class were missed in the earlier migration: NumberCounter's wrapper/counter ids and count-up script, and the shared form-relay-wiring fid (used by ContactForm/FormContainer). Both used Math.random() for exported HTML ids, breaking caching/diffing across exports. Migrate both to scopeId(nodeId, fallbackSeed, prefix), threading nodeId through NumberCounter.toHtml and relayFormWiring (via ContactForm.toHtml and FormContainer.toHtml, both now passing nodeId as their 3rd arg).
83 lines
2.2 KiB
TypeScript
83 lines
2.2 KiB
TypeScript
import React, { CSSProperties } from 'react';
|
|
import { useNode, Element, UserComponent } from '@craftjs/core';
|
|
import { Container } from '../layout/Container';
|
|
import { cssPropsToString } from '../../utils/style-helpers';
|
|
import { relayFormWiring } from '../../utils/form-relay-wiring';
|
|
|
|
interface FormContainerProps {
|
|
action?: string;
|
|
method?: 'GET' | 'POST';
|
|
recipientEmail?: string;
|
|
thankYouUrl?: string;
|
|
style?: CSSProperties;
|
|
children?: React.ReactNode;
|
|
}
|
|
|
|
export const FormContainer: UserComponent<FormContainerProps> = ({
|
|
action = '#',
|
|
method = 'POST',
|
|
style = {},
|
|
}) => {
|
|
const { connectors: { connect, drag } } = useNode();
|
|
|
|
return (
|
|
<form
|
|
ref={(ref: HTMLFormElement | null): void => { if (ref) connect(drag(ref)); }}
|
|
action={action}
|
|
method={method}
|
|
onSubmit={(e) => e.preventDefault()}
|
|
style={{
|
|
padding: '24px',
|
|
minHeight: '80px',
|
|
...style,
|
|
}}
|
|
>
|
|
<Element
|
|
id="form-inner"
|
|
is={Container}
|
|
canvas
|
|
style={{ display: 'flex', flexDirection: 'column', gap: '16px', padding: '0' }}
|
|
tag="div"
|
|
/>
|
|
</form>
|
|
);
|
|
};
|
|
|
|
/* ---------- Craft config ---------- */
|
|
|
|
FormContainer.craft = {
|
|
displayName: 'Form',
|
|
props: {
|
|
action: '#',
|
|
method: 'POST',
|
|
recipientEmail: '',
|
|
thankYouUrl: '',
|
|
style: {
|
|
padding: '24px',
|
|
backgroundColor: '#ffffff',
|
|
borderRadius: '8px',
|
|
border: '1px solid #e4e4e7',
|
|
},
|
|
},
|
|
rules: {
|
|
canDrag: () => true,
|
|
canMoveIn: () => false,
|
|
canMoveOut: () => true,
|
|
},
|
|
};
|
|
|
|
/* ---------- HTML export ---------- */
|
|
|
|
(FormContainer as any).toHtml = (props: FormContainerProps, childrenHtml: string, nodeId?: string) => {
|
|
const styleStr = cssPropsToString({
|
|
padding: '24px',
|
|
...props.style,
|
|
});
|
|
const { useRelay, marker, actionAttr, honeypot } = relayFormWiring(props.recipientEmail, props.thankYouUrl, props.action, nodeId);
|
|
const method = useRelay ? 'POST' : (props.method || 'POST'); // relay requires POST
|
|
const body = honeypot + childrenHtml; // honeypot as first child
|
|
return {
|
|
html: `${marker}<form action="${actionAttr}" method="${method}"${styleStr ? ` style="${styleStr}"` : ''}>${body}</form>`,
|
|
};
|
|
};
|