@10x-media/form-builder 0.1.0-beta.10 → 0.1.0-beta.11
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/CHANGELOG.md +11 -0
- package/dist/actions/assertNoBlockCollision.js +18 -0
- package/dist/actions/assertNoBlockCollision.js.map +1 -0
- package/dist/actions/builtin/confirmation.js +2 -1
- package/dist/actions/builtin/confirmation.js.map +1 -1
- package/dist/actions/builtin/emailAction.d.ts +3 -1
- package/dist/actions/builtin/emailAction.js +43 -12
- package/dist/actions/builtin/emailAction.js.map +1 -1
- package/dist/actions/builtin/emailTeam.js +11 -5
- package/dist/actions/builtin/emailTeam.js.map +1 -1
- package/dist/actions/defineAction.d.ts +3 -1
- package/dist/actions/defineAction.js.map +1 -1
- package/dist/actions/dispatch.js +1 -1
- package/dist/actions/dispatch.js.map +1 -1
- package/dist/actions/emailRecipients.js +34 -7
- package/dist/actions/emailRecipients.js.map +1 -1
- package/dist/actions/recipientSources.d.ts +34 -0
- package/dist/actions/recipientSources.js +11 -0
- package/dist/actions/recipientSources.js.map +1 -0
- package/dist/actions/task.js +20 -0
- package/dist/actions/task.js.map +1 -1
- package/dist/client/RecipientsSelect.d.ts +5 -1
- package/dist/client/RecipientsSelect.js +22 -3
- package/dist/client/RecipientsSelect.js.map +1 -1
- package/dist/collections/formSubmissions.js +27 -7
- package/dist/collections/formSubmissions.js.map +1 -1
- package/dist/collections/forms.js +7 -0
- package/dist/collections/forms.js.map +1 -1
- package/dist/context/formContext.d.ts +30 -0
- package/dist/context/formContext.js +54 -0
- package/dist/context/formContext.js.map +1 -0
- package/dist/exports/rsc.d.ts +2 -1
- package/dist/exports/rsc.js +2 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +6 -2
- package/dist/index.js.map +1 -1
- package/dist/options.d.ts +7 -0
- package/dist/react/Form.d.ts +8 -1
- package/dist/react/Form.js +6 -2
- package/dist/react/Form.js.map +1 -1
- package/dist/spam/constants.js +7 -1
- package/dist/spam/constants.js.map +1 -1
- package/dist/submissions/verifyContext.js +35 -0
- package/dist/submissions/verifyContext.js.map +1 -0
- package/dist/translations/de.js +4 -0
- package/dist/translations/de.js.map +1 -1
- package/dist/translations/en.js +4 -0
- package/dist/translations/en.js.map +1 -1
- package/dist/translations/keys.d.ts +4 -0
- package/dist/translations/keys.js +4 -0
- package/dist/translations/keys.js.map +1 -1
- package/package.json +3 -3
package/dist/react/Form.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Form.js","names":[],"sources":["../../src/react/Form.tsx"],"sourcesContent":["'use client'\n\nimport {\n\ttype CSSProperties,\n\ttype FormEvent as ReactFormEvent,\n\ttype KeyboardEvent as ReactKeyboardEvent,\n\ttype ReactNode,\n\tuseCallback,\n\tuseEffect,\n\tuseMemo,\n\tuseReducer,\n\tuseRef,\n\tuseState,\n} from 'react'\nimport type { BodyConverter } from '../actions/body/converters'\nimport { serializeBody } from '../actions/body/serializeBody'\nimport { calcExpressionOf, computeCalcFields } from '../calc/computeCalcFields'\nimport { evaluateCondition } from '../conditions/evaluate'\nimport { noopEventSink } from '../events/noopSink'\nimport type { FormEventSink } from '../events/types'\nimport { fieldKey, isNamedField, type NamedFormFieldInstance } from '../fields/fieldKey'\nimport type { AnyFormFieldDefinition } from '../fields/types'\nimport { firstStepId, isTerminalStepId, resolveNextStepId, stepFieldNames } from '../flow/engine'\nimport type { FormFlow } from '../flow/types'\nimport type {\n\tFormButtonSettings,\n\tFormDocument,\n\tFormPollSettings,\n\tFormResponseSettings,\n} from '../form/types'\nimport {\n\tDEFAULT_PRESENTATION_NAME,\n\tdefaultPresentationDescriptors,\n} from '../presentations/defaults'\nimport { interpolate } from '../recall/interpolate'\nimport { buildRecallResolver, descriptorsFor } from '../recall/resolver'\nimport { CAPTCHA_TOKEN_KEY, DEFAULT_HONEYPOT_FIELD, HONEYPOT_VALUE_KEY } from '../spam/constants'\nimport type { FormFieldInstance, SubmissionValue } from '../submissions/types'\nimport { en } from '../translations/en'\nimport { keys } from '../translations/keys'\nimport { makeTranslate } from '../translations/makeTranslate'\nimport { resolveMessage } from '../validation/message'\nimport type { AnyValidationRuleDefinition } from '../validation/types'\nimport { cn } from './cn'\nimport type { RendererTranslate } from './contract'\nimport { emitFormEvent } from './events'\nimport { FormContext, type FormContextValue, type FormStepInfo } from './FormContext'\nimport {\n\ttype BackButtonRenderProps,\n\tFormControls,\n\ttype NextButtonRenderProps,\n\ttype SubmitButtonRenderProps,\n} from './FormControls'\nimport { FormFields } from './FormFields'\nimport { Honeypot } from './Honeypot'\nimport { defaultPresentations } from './presentation/presentations'\nimport { type PresentationsConfig, resolvePresentations } from './presentation/registry'\nimport type { FormPresentation } from './presentation/types'\nimport { type RenderersConfig, resolveRenderers } from './registry'\nimport { defaultRenderers } from './renderers'\nimport { buildFieldTypeRegistry, buildValidationRuleRegistry, visibleFields } from './resolveForm'\nimport {\n\tDEFAULT_STEP_ID,\n\ttype FieldErrors,\n\ttype FormAction,\n\tformReducer,\n\tinitialFormState,\n\tseedFieldValues,\n} from './state'\nimport { type SubmitFormResult, type SubmitHandler, submitForm } from './submitForm'\nimport { validateFieldValue } from './validateField'\n\nexport type {\n\tBackButtonRenderProps,\n\tNextButtonRenderProps,\n\tSubmitButtonRenderProps,\n} from './FormControls'\n// FormResponseSettings, FormButtonSettings, FormPollSettings, and FormDocument live in\n// `../form/types` (no 'use client') so server code (e.g. `toFormDocument` in a Server Component)\n// can use them without pulling in this client module. Re-exported here so `./react` and existing\n// `from './Form'` imports keep working unchanged.\nexport type { FormButtonSettings, FormDocument, FormPollSettings, FormResponseSettings }\n\n/**\n * The success response passed to `onSuccess`, recall-resolved and (for a message) serialized with the\n * form's active converters, so a host can render or toast the resolved response without re-deriving it.\n */\nexport type FormSuccessResponse =\n\t| { type: 'message'; html?: string }\n\t| { type: 'redirect'; url?: string }\n\n/** The second argument to `onSuccess`: the resolved success response (an object, so it can grow). */\nexport type FormSuccessResult = { response?: FormSuccessResponse }\n\nexport type FormProps = {\n\tform: FormDocument\n\tfieldTypes?: AnyFormFieldDefinition[]\n\trules?: AnyValidationRuleDefinition[]\n\trenderers?: RenderersConfig\n\tapiRoute?: string\n\tonSubmit?: SubmitHandler\n\t/**\n\t * Called after a successful submission with the submission id and the resolved success response\n\t * (recall-applied, serialized with `converters`), so a host can toast or render it. Fires in both\n\t * `successBehavior` modes and on the custom-`children` path.\n\t */\n\tonSuccess?: (submissionId?: string, result?: FormSuccessResult) => void\n\tonError?: (message: string) => void\n\t/**\n\t * Custom Lexical block converters (e.g. host `icon`/`badge` blocks) spread over the defaults for the\n\t * client serializer, so those blocks survive in the success message and in the `onSuccess` response.\n\t */\n\tconverters?: Record<string, BodyConverter>\n\t/**\n\t * What happens on a successful submit. `'replace'` (default) swaps the form for the success screen;\n\t * `'reset'` clears the fields in place and shows no success screen, so a host can toast via `onSuccess`\n\t * and keep the form usable.\n\t */\n\tsuccessBehavior?: 'replace' | 'reset'\n\tevents?: FormEventSink\n\tt?: RendererTranslate\n\tlocale?: string\n\tlayout?: boolean\n\t/** Submit button label. Precedence: this prop, then the form's `buttons.submitLabel`, then the translated default. */\n\tsubmitLabel?: string\n\t/** \"Next\" button label for multi-step forms. Precedence: this prop, then the form's `buttons.nextLabel`, then the translated default. */\n\tnextLabel?: string\n\t/** \"Back\" button label for multi-step forms. Precedence: this prop, then the form's `buttons.prevLabel`, then the translated default. */\n\tprevLabel?: string\n\t/** Label for the overlay close control (modal/drawer). */\n\tcloseLabel?: string\n\tsuccessMessage?: string\n\t/** Active presentation: a name into the registry or an inline presentation. Defaults to `'page'` when omitted. */\n\tpresentation?: string | FormPresentation\n\t/** Per-render presentation overrides merged onto the defaults (add, replace, or `false` to remove). */\n\tpresentations?: PresentationsConfig\n\t/** Invoked when an overlay presentation dismisses (close button, Escape, outside click, or `dismissOnSuccess`). */\n\tonClose?: () => void\n\t/**\n\t * Accessible name for an overlay surface (modal/drawer). Hosts choosing between a trigger\n\t * label and the form's own admin title should prefer `form.title` when set, falling back to\n\t * their own label otherwise.\n\t */\n\ttitle?: string\n\t/** Seed initial field values (e.g. from `valuesFromSearchParams`). Still validated on submit. */\n\tinitialValues?: Record<string, unknown>\n\t/** Honeypot decoy (on by default). `false` removes it; `{ name }` matches a customized server `spam.honeypot.fieldName`. */\n\thoneypot?: false | { name?: string }\n\t/** A token from your captcha widget; verified server-side when a captcha provider is configured. */\n\tcaptchaToken?: string\n\t/** Custom layout: render fields with `useField`/`useFormState` instead of the auto-rendered field loop. */\n\tchildren?: ReactNode\n\t/** Chrome rendered inside the form, above the fields, in default mode (e.g. `<FormSteps />`). */\n\theader?: ReactNode\n\t/** Additional CSS class names applied to the root `<form>` element (and the success node). */\n\tclassName?: string\n\t/** Replace the default submit button entirely. Receives the resolved label and submitting state. */\n\trenderSubmit?: (props: SubmitButtonRenderProps) => ReactNode\n\t/** Replace the default \"Next\" button in multi-step forms. */\n\trenderNext?: (props: NextButtonRenderProps) => ReactNode\n\t/** Replace the default \"Back\" button in multi-step forms. */\n\trenderBack?: (props: BackButtonRenderProps) => ReactNode\n\t/** CSS class forwarded to the default submit `<button>`. Ignored when `renderSubmit` is provided. */\n\tsubmitButtonClassName?: string\n\t/** CSS class forwarded to the default \"Next\" `<button>`. Ignored when `renderNext` is provided. */\n\tnextButtonClassName?: string\n\t/** CSS class forwarded to the default \"Back\" `<button>`. Ignored when `renderBack` is provided. */\n\tbackButtonClassName?: string\n}\n\nconst isEmpty = (value: unknown): boolean =>\n\tvalue == null || value === '' || (Array.isArray(value) && value.length === 0)\n\n/** Visually hidden but screen-reader-announced, for the \"Step X of Y\" live region (no host CSS required). */\nconst SR_ONLY: CSSProperties = {\n\tposition: 'absolute',\n\twidth: 1,\n\theight: 1,\n\tpadding: 0,\n\tmargin: -1,\n\toverflow: 'hidden',\n\tclip: 'rect(0, 0, 0, 0)',\n\twhiteSpace: 'nowrap',\n\tborder: 0,\n}\n\n/** The base field name of an error key: the part before a repeater composite suffix (`name[0].sub`). */\nconst baseFieldKey = (key: string): string => {\n\tconst bracket = key.indexOf('[')\n\treturn bracket === -1 ? key : key.slice(0, bracket)\n}\n\n/** The id of the first flow step (in order) that owns an errored field, or undefined when none does. */\nconst firstStepWithError = (flow: FormFlow, errors: FieldErrors): string | undefined => {\n\tconst errored = new Set(Object.keys(errors).map(baseFieldKey))\n\treturn flow.steps.find((flowStep) => flowStep.fields.some((key) => errored.has(key)))?.id\n}\n\n/** The first focusable element under `root` that a step transition should land on (skips hidden/honeypot). */\nconst focusFirstIn = (root: HTMLElement | null, selector: string): void => {\n\tconst target = root?.querySelector<HTMLElement>(selector)\n\ttarget?.focus()\n}\n\n/** A stored button label counts only when it is a non-empty string; anything else falls through. */\nconst storedLabel = (value: unknown): string | undefined =>\n\ttypeof value === 'string' && value.length > 0 ? value : undefined\n\n/** The headless form controller: state, progressive client validation, conditional visibility, submission, events. */\nexport const Form = ({\n\tform,\n\tfieldTypes,\n\trules,\n\trenderers,\n\tapiRoute,\n\tonSubmit,\n\tonSuccess,\n\tonError,\n\tconverters,\n\tsuccessBehavior = 'replace',\n\tevents,\n\tt,\n\tlocale = 'en',\n\tlayout,\n\tsubmitLabel,\n\tnextLabel,\n\tprevLabel,\n\tcloseLabel,\n\tsuccessMessage,\n\tpresentation,\n\tpresentations,\n\tonClose,\n\ttitle,\n\tinitialValues,\n\thoneypot,\n\tcaptchaToken,\n\tchildren,\n\theader,\n\tclassName,\n\trenderSubmit,\n\trenderNext,\n\trenderBack,\n\tsubmitButtonClassName,\n\tnextButtonClassName,\n\tbackButtonClassName,\n}: FormProps) => {\n\tconst honeypotName = honeypot === false ? null : (honeypot?.name ?? DEFAULT_HONEYPOT_FIELD)\n\tconst honeypotRef = useRef<HTMLInputElement>(null)\n\tconst registry = useMemo(() => buildFieldTypeRegistry(fieldTypes), [fieldTypes])\n\tconst ruleRegistry = useMemo(() => buildValidationRuleRegistry(rules), [rules])\n\tconst rendererRegistry = useMemo(() => resolveRenderers(defaultRenderers, renderers), [renderers])\n\tconst presentationRegistry = useMemo(\n\t\t() => resolvePresentations(defaultPresentations, presentations),\n\t\t[presentations]\n\t)\n\tconst activePresentation: FormPresentation =\n\t\ttypeof presentation === 'object'\n\t\t\t? presentation\n\t\t\t: (presentationRegistry.get(presentation ?? DEFAULT_PRESENTATION_NAME) ??\n\t\t\t\tpresentationRegistry.get(DEFAULT_PRESENTATION_NAME) ??\n\t\t\t\tdefaultPresentationDescriptors.page)\n\tconst fieldsByName = useMemo(\n\t\t() => new Map(form.fields.filter(isNamedField).map((field) => [field.name, field])),\n\t\t[form.fields]\n\t)\n\tconst translate = useMemo<RendererTranslate>(() => t ?? makeTranslate(en), [t])\n\tconst resolvedCloseLabel = closeLabel ?? translate(keys.formClose)\n\tconst resolvedSuccessMessage = successMessage ?? translate(keys.formSuccess)\n\tconst docButtons: FormButtonSettings | undefined = form.buttons\n\tconst labels = useMemo(\n\t\t() => ({\n\t\t\tprev: prevLabel ?? storedLabel(docButtons?.prevLabel) ?? translate(keys.formBack),\n\t\t\tnext: nextLabel ?? storedLabel(docButtons?.nextLabel) ?? translate(keys.formNext),\n\t\t\tsubmit: submitLabel ?? storedLabel(docButtons?.submitLabel) ?? translate(keys.formSubmit),\n\t\t}),\n\t\t[prevLabel, nextLabel, submitLabel, docButtons, translate]\n\t)\n\n\t// Latest-value refs so event emission and the mount/unmount effect tolerate an inline `events` prop or a changing form id.\n\tconst sinkRef = useRef<FormEventSink>(noopEventSink)\n\tsinkRef.current = events ?? noopEventSink\n\tconst formIdRef = useRef('')\n\tformIdRef.current = String(form.id)\n\n\tconst [state, rawDispatch] = useReducer(formReducer, form.fields, (fields) =>\n\t\tinitialFormState({\n\t\t\t...seedFieldValues(fields),\n\t\t\t...(initialValues ?? {}),\n\t\t})\n\t)\n\n\t// Authoritative values for derived (calc) fields, recomputed from user answers on every change. The\n\t// server recomputes these too at submit; the client copy drives the live calc renderer, recall, and submit.\n\tconst effectiveValues = useMemo(\n\t\t() => computeCalcFields(form.fields, state.values),\n\t\t[form.fields, state.values]\n\t)\n\n\tconst recall = useMemo(\n\t\t() =>\n\t\t\tbuildRecallResolver({\n\t\t\t\tfields: form.fields,\n\t\t\t\tvalues: effectiveValues,\n\t\t\t\tregistry,\n\t\t\t\tlocale,\n\t\t\t\tt: translate,\n\t\t\t}),\n\t\t[form.fields, effectiveValues, registry, locale, translate]\n\t)\n\n\t// Multi-step is active only when the form is flagged `multistep` and its flow declares two or more\n\t// steps. With the flag off the form renders as a single page even if flow data is still stored.\n\tconst flow =\n\t\tform.multistep === true && form.flow && form.flow.steps.length >= 2 ? form.flow : undefined\n\tconst [currentStepId, setCurrentStepId] = useState<string | undefined>(() =>\n\t\tflow ? firstStepId(flow) : undefined\n\t)\n\tconst [history, setHistory] = useState<string[]>([])\n\n\tconst startedRef = useRef(false)\n\tconst submittedRef = useRef(false)\n\tconst submittingRef = useRef(false)\n\tconst advancingRef = useRef(false)\n\tconst flowRef = useRef(flow)\n\tflowRef.current = flow\n\n\t// Per-step error reveal: a field maps to the id of the flow step whose `fields` include it, else the\n\t// default step (single-step forms, or a field assigned to no step), so a single-step form collapses to\n\t// one step and today's behavior.\n\tconst stepIdOfField = useMemo(() => {\n\t\tconst map = new Map<string, string>()\n\t\tif (flow) {\n\t\t\tfor (const flowStep of flow.steps) {\n\t\t\t\tfor (const key of flowStep.fields) {\n\t\t\t\t\tmap.set(key, flowStep.id)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn (fieldKey: string): string => map.get(fieldKey) ?? DEFAULT_STEP_ID\n\t}, [flow])\n\tconst allStepIds = useMemo(\n\t\t() => (flow ? flow.steps.map((flowStep) => flowStep.id) : [DEFAULT_STEP_ID]),\n\t\t[flow]\n\t)\n\n\t// Focus management for step transitions and blocked advances/submits. A pending request is performed\n\t// by an effect after the render it triggers, so focus lands on the DOM that reflects the new state.\n\tconst formRef = useRef<HTMLFormElement>(null)\n\tconst pendingFocusRef = useRef<'stepStart' | 'firstInvalid' | null>(null)\n\tconst [focusNonce, setFocusNonce] = useState(0)\n\tconst requestFocus = (intent: 'stepStart' | 'firstInvalid') => {\n\t\tpendingFocusRef.current = intent\n\t\tsetFocusNonce((nonce) => nonce + 1)\n\t}\n\n\tconst dispatch = useCallback((action: FormAction) => {\n\t\tif (action.type === 'SET_VALUE' && !startedRef.current) {\n\t\t\tstartedRef.current = true\n\t\t\temitFormEvent(sinkRef.current, formIdRef.current, { type: 'form.started' })\n\t\t}\n\t\trawDispatch(action)\n\t}, [])\n\n\tconst validateField = useCallback(\n\t\t(name: string, value: unknown) => {\n\t\t\tconst field = fieldsByName.get(name)\n\t\t\tif (!field) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst answers = { ...effectiveValues, [name]: value }\n\t\t\t// Mirror the server: a field whose `validateWhen` is unmet is not validated; clear any stale error.\n\t\t\tif (!evaluateCondition(field.validateWhen, answers)) {\n\t\t\t\trawDispatch({ type: 'SET_FIELD_ISSUES', name, errors: [] })\n\t\t\t\treturn\n\t\t\t}\n\t\t\tvoid validateFieldValue({\n\t\t\t\tfield,\n\t\t\t\tvalue,\n\t\t\t\tregistry,\n\t\t\t\truleRegistry,\n\t\t\t\tanswers,\n\t\t\t\tlocale,\n\t\t\t\tt: translate,\n\t\t\t}).then(({ errors }) => {\n\t\t\t\trawDispatch({ type: 'SET_FIELD_ISSUES', name, errors })\n\t\t\t\tconst [firstError] = errors\n\t\t\t\tif (firstError !== undefined) {\n\t\t\t\t\temitFormEvent(sinkRef.current, formIdRef.current, {\n\t\t\t\t\t\ttype: 'field.errored',\n\t\t\t\t\t\tfield: name,\n\t\t\t\t\t\tmessage: firstError,\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t})\n\t\t},\n\t\t[fieldsByName, effectiveValues, registry, ruleRegistry, locale, translate]\n\t)\n\n\tconst visible = visibleFields(form.fields, effectiveValues)\n\n\t/** Visible, answered named fields. Display-only ('none' kind) and nameless (bare) fields never contribute. */\n\tconst answerableFields = (): NamedFormFieldInstance[] =>\n\t\tvisibleFields(form.fields, effectiveValues)\n\t\t\t.filter((field) => registry.get(field.blockType)?.value !== 'none')\n\t\t\t.filter(isNamedField)\n\t\t\t.filter((field) => !isEmpty(effectiveValues[field.name]))\n\n\t/** Answered visible fields as raw submission values, sent to the server on submit. */\n\tconst answeredValues = (): SubmissionValue[] =>\n\t\tanswerableFields().map((field) => ({ field: field.name, value: effectiveValues[field.name] }))\n\n\t/**\n\t * Same fields, formatted via `recall` (option labels, Yes/No, localized dates): recall-fidelity\n\t * values for client-rendered templates, matching what the server gives email-team's body.\n\t */\n\tconst formattedValues = (): SubmissionValue[] =>\n\t\tanswerableFields().map((field) => ({ field: field.name, value: recall(field.name) }))\n\n\t/**\n\t * The recall-resolved success response: a redirect's url, or the response message serialized with\n\t * the active `converters` (so host blocks survive). Shared by the success screen and the value\n\t * handed to `onSuccess`, so both stay identical.\n\t */\n\tconst resolveSuccessResponse = (): FormSuccessResponse | undefined => {\n\t\tconst response = form.response\n\t\tif (response?.type === 'redirect') {\n\t\t\treturn { type: 'redirect', url: response.redirect?.url ?? undefined }\n\t\t}\n\t\tconst message =\n\t\t\tresponse?.type === 'message' || response?.type == null ? response?.message : undefined\n\t\tif (!message) {\n\t\t\treturn undefined\n\t\t}\n\t\treturn {\n\t\t\ttype: 'message',\n\t\t\thtml: serializeBody(message, {\n\t\t\t\tvalues: formattedValues(),\n\t\t\t\tdescriptors: descriptorsFor(answerableFields()),\n\t\t\t\tconverters,\n\t\t\t}),\n\t\t}\n\t}\n\n\t// Steps address fields by key: machine names for named fields, block row ids for bare blocks.\n\t// `step.fields` is membership only; render order follows `form.fields` (the order of `visible`),\n\t// so a step shows its fields in the form's field order, not the flow-builder entry order.\n\tconst stepKeys = flow && currentStepId ? stepFieldNames(flow, currentStepId) : []\n\tconst stepKeySet = new Set(stepKeys)\n\tconst stepVisible: FormFieldInstance[] = visible.filter((field) =>\n\t\tstepKeySet.has(fieldKey(field))\n\t)\n\n\t// Validate the sub-fields of the given repeaters, one pass per visible row, returning composite-key\n\t// errors (`fieldName[rowIndex].subFieldName`). Shared by submit and step navigation so both mirror\n\t// the server's per-row pass and neither lets an invalid required sub-field slip through.\n\tconst validateRepeaterSubFields = async (\n\t\trepeaters: FormFieldInstance[]\n\t): Promise<FieldErrors> => {\n\t\tconst errors: FieldErrors = {}\n\t\tfor (const field of repeaters.filter(\n\t\t\t(f): f is NamedFormFieldInstance => f.blockType === 'repeater' && isNamedField(f)\n\t\t)) {\n\t\t\tconst rows = Array.isArray(effectiveValues[field.name])\n\t\t\t\t? (effectiveValues[field.name] as Array<Record<string, unknown>>)\n\t\t\t\t: []\n\t\t\tconst subFields = (\n\t\t\t\tArray.isArray(field.subFields) ? (field.subFields as FormFieldInstance[]) : []\n\t\t\t).filter(isNamedField)\n\t\t\tfor (let rowIndex = 0; rowIndex < rows.length; rowIndex++) {\n\t\t\t\tconst row = rows[rowIndex] ?? {}\n\t\t\t\tfor (const subField of subFields) {\n\t\t\t\t\tif (!evaluateCondition(subField.visibleWhen, row)) continue\n\t\t\t\t\tif (!evaluateCondition(subField.validateWhen, row)) continue\n\t\t\t\t\tconst subResult = await validateFieldValue({\n\t\t\t\t\t\tfield: subField,\n\t\t\t\t\t\tvalue: row[subField.name],\n\t\t\t\t\t\tregistry,\n\t\t\t\t\t\truleRegistry,\n\t\t\t\t\t\tanswers: row,\n\t\t\t\t\t\tlocale,\n\t\t\t\t\t\tt: translate,\n\t\t\t\t\t})\n\t\t\t\t\tconst compositeKey = `${field.name}[${rowIndex}].${subField.name}`\n\t\t\t\t\tif (subResult.errors.length > 0) errors[compositeKey] = subResult.errors\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn errors\n\t}\n\n\tconst goNext = async () => {\n\t\t// Re-entrancy guard: a double-click during async validation must not push the same step onto\n\t\t// history twice (which would need two Back presses to undo).\n\t\tif (!flow || !currentStepId || advancingRef.current) {\n\t\t\treturn\n\t\t}\n\t\tadvancingRef.current = true\n\t\ttry {\n\t\t\tconst results = await Promise.all(\n\t\t\t\tstepVisible\n\t\t\t\t\t.filter((field) => !calcExpressionOf(field))\n\t\t\t\t\t.filter((field) => registry.get(field.blockType)?.value !== 'none')\n\t\t\t\t\t.filter(isNamedField)\n\t\t\t\t\t.filter((field) => evaluateCondition(field.validateWhen, effectiveValues))\n\t\t\t\t\t.map(async (field) => ({\n\t\t\t\t\t\tfield,\n\t\t\t\t\t\t...(await validateFieldValue({\n\t\t\t\t\t\t\tfield,\n\t\t\t\t\t\t\tvalue: effectiveValues[field.name],\n\t\t\t\t\t\t\tregistry,\n\t\t\t\t\t\t\truleRegistry,\n\t\t\t\t\t\t\tanswers: effectiveValues,\n\t\t\t\t\t\t\tlocale,\n\t\t\t\t\t\t\tt: translate,\n\t\t\t\t\t\t})),\n\t\t\t\t\t}))\n\t\t\t)\n\t\t\tlet hasError = false\n\t\t\tfor (const result of results) {\n\t\t\t\trawDispatch({ type: 'TOUCH', name: result.field.name })\n\t\t\t\trawDispatch({\n\t\t\t\t\ttype: 'SET_FIELD_ISSUES',\n\t\t\t\t\tname: result.field.name,\n\t\t\t\t\terrors: result.errors,\n\t\t\t\t})\n\t\t\t\tif (result.errors.length > 0) {\n\t\t\t\t\thasError = true\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Mirror submit: validate the step's repeater sub-fields too, so a required sub-field can't be\n\t\t\t// skipped past on a non-terminal step (errors surface inline via the composite key).\n\t\t\tconst repeaterErrors = await validateRepeaterSubFields(stepVisible)\n\t\t\tfor (const [compositeKey, errs] of Object.entries(repeaterErrors)) {\n\t\t\t\trawDispatch({ type: 'SET_FIELD_ISSUES', name: compositeKey, errors: errs })\n\t\t\t\thasError = true\n\t\t\t}\n\t\t\tif (hasError) {\n\t\t\t\t// Mark this step attempted so its fields reveal their errors, then focus the first invalid one.\n\t\t\t\trawDispatch({ type: 'MARK_STEP_ATTEMPTED', stepId: currentStepId })\n\t\t\t\trequestFocus('firstInvalid')\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst next = resolveNextStepId(flow, currentStepId, effectiveValues)\n\t\t\tif (!next) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\temitFormEvent(sinkRef.current, formIdRef.current, {\n\t\t\t\ttype: 'step.completed',\n\t\t\t\tstepId: currentStepId,\n\t\t\t})\n\t\t\tsetHistory((prev) => [...prev, currentStepId])\n\t\t\tsetCurrentStepId(next)\n\t\t\trequestFocus('stepStart')\n\t\t\temitFormEvent(sinkRef.current, formIdRef.current, { type: 'step.viewed', stepId: next })\n\t\t} finally {\n\t\t\tadvancingRef.current = false\n\t\t}\n\t}\n\n\tconst goBack = () => {\n\t\tconst prev = history[history.length - 1]\n\t\tif (prev === undefined) {\n\t\t\treturn\n\t\t}\n\t\tsetHistory((entries) => entries.slice(0, -1))\n\t\tsetCurrentStepId(prev)\n\t\trequestFocus('stepStart')\n\t\temitFormEvent(sinkRef.current, formIdRef.current, { type: 'step.viewed', stepId: prev })\n\t}\n\n\t// Jump to an earlier step (from the terminal Submit when an earlier step is invalid), rebuilding the\n\t// Back stack as the flow's linear path up to it so Back still works.\n\tconst navigateToStep = (stepId: string) => {\n\t\tif (!flow || stepId === currentStepId) {\n\t\t\treturn\n\t\t}\n\t\tconst idx = flow.steps.findIndex((flowStep) => flowStep.id === stepId)\n\t\tif (idx < 0) {\n\t\t\treturn\n\t\t}\n\t\tsetHistory(flow.steps.slice(0, idx).map((flowStep) => flowStep.id))\n\t\tsetCurrentStepId(stepId)\n\t\temitFormEvent(sinkRef.current, formIdRef.current, { type: 'step.viewed', stepId })\n\t}\n\n\t// Perform a pending focus request after the render it triggered, so it lands on the DOM that reflects\n\t// the new state (a changed step, or freshly revealed errors). Null on mount, so the first render never\n\t// steals focus. currentStepId and focusNonce are intentional re-run triggers: a blocked advance keeps\n\t// the same step, so the nonce forces a fresh run; the body reads only refs, hence the ignore.\n\t// biome-ignore lint/correctness/useExhaustiveDependencies: currentStepId/focusNonce are re-run triggers, not read in the body\n\tuseEffect(() => {\n\t\tconst intent = pendingFocusRef.current\n\t\tif (!intent) {\n\t\t\treturn\n\t\t}\n\t\tpendingFocusRef.current = null\n\t\tif (intent === 'firstInvalid') {\n\t\t\tfocusFirstIn(formRef.current, '[aria-invalid=\"true\"]')\n\t\t\treturn\n\t\t}\n\t\tconst region = formRef.current?.querySelector<HTMLElement>('[data-fb-step-region]')\n\t\tif (region) {\n\t\t\tregion.focus()\n\t\t} else {\n\t\t\tfocusFirstIn(formRef.current, 'input:not([type=\"hidden\"]), select, textarea')\n\t\t}\n\t}, [currentStepId, focusNonce])\n\n\tuseEffect(() => {\n\t\temitFormEvent(sinkRef.current, formIdRef.current, { type: 'form.viewed' })\n\t\tconst mountFlow = flowRef.current\n\t\tif (mountFlow) {\n\t\t\tconst first = firstStepId(mountFlow)\n\t\t\tif (first) {\n\t\t\t\temitFormEvent(sinkRef.current, formIdRef.current, { type: 'step.viewed', stepId: first })\n\t\t\t}\n\t\t}\n\t\treturn () => {\n\t\t\tif (!submittedRef.current && !submittingRef.current) {\n\t\t\t\temitFormEvent(sinkRef.current, formIdRef.current, { type: 'form.abandoned' })\n\t\t\t}\n\t\t}\n\t}, [])\n\n\tconst handleClose = useCallback(() => {\n\t\tonClose?.()\n\t}, [onClose])\n\n\tconst handleSubmit = async (event: ReactFormEvent<HTMLFormElement>) => {\n\t\tevent.preventDefault()\n\t\t// Re-entrancy guard: claim the in-flight slot before the async validation window so a fast second\n\t\t// activation (double-click, Enter + click) cannot reach the transport and POST the submission twice.\n\t\tif (submittingRef.current) {\n\t\t\treturn\n\t\t}\n\t\tsubmittingRef.current = true\n\t\tconst visible = visibleFields(form.fields, effectiveValues)\n\t\tconst results = await Promise.all(\n\t\t\t// Calc fields carry no rules and have no input; they are always satisfied, so skip validating them.\n\t\t\t// Display-only ('none' kind, e.g. message) and nameless (bare) fields are skipped too, mirroring the server.\n\t\t\t// A field whose `validateWhen` is unmet is skipped too, mirroring the server (no client/server divergence).\n\t\t\tvisible\n\t\t\t\t.filter((field) => !calcExpressionOf(field))\n\t\t\t\t.filter((field) => registry.get(field.blockType)?.value !== 'none')\n\t\t\t\t.filter(isNamedField)\n\t\t\t\t.filter((field) => evaluateCondition(field.validateWhen, effectiveValues))\n\t\t\t\t.map(async (field) => ({\n\t\t\t\t\tfield,\n\t\t\t\t\t...(await validateFieldValue({\n\t\t\t\t\t\tfield,\n\t\t\t\t\t\tvalue: effectiveValues[field.name],\n\t\t\t\t\t\tregistry,\n\t\t\t\t\t\truleRegistry,\n\t\t\t\t\t\tanswers: effectiveValues,\n\t\t\t\t\t\tlocale,\n\t\t\t\t\t\tt: translate,\n\t\t\t\t\t})),\n\t\t\t\t}))\n\t\t)\n\t\tconst errors: FieldErrors = {}\n\t\tfor (const result of results) {\n\t\t\tif (result.errors.length > 0) {\n\t\t\t\terrors[result.field.name] = result.errors\n\t\t\t\tconst [firstError] = result.errors\n\t\t\t\tif (firstError !== undefined) {\n\t\t\t\t\temitFormEvent(sinkRef.current, formIdRef.current, {\n\t\t\t\t\t\ttype: 'field.errored',\n\t\t\t\t\t\tfield: result.field.name,\n\t\t\t\t\t\tmessage: firstError,\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Validate sub-fields within each visible repeater (composite keys `fieldName[rowIndex].subFieldName`),\n\t\t// mirroring the server's per-row pass, so the repeater renderer surfaces them inline.\n\t\tObject.assign(errors, await validateRepeaterSubFields(visible))\n\n\t\tconst hasErrors = Object.keys(errors).length > 0\n\t\t// A terminal submit validates every step, so every step is attempted (its errors may now reveal);\n\t\t// a valid submit clears stale errors without marking anything.\n\t\trawDispatch({ type: 'SET_ALL_ISSUES', errors, steps: hasErrors ? allStepIds : [] })\n\t\tif (hasErrors) {\n\t\t\tsubmittingRef.current = false\n\t\t\t// On a multi-step form, route to the first step that owns an invalid field rather than failing in\n\t\t\t// place on the terminal step, then focus its first invalid field.\n\t\t\tif (flow && currentStepId) {\n\t\t\t\tconst target = firstStepWithError(flow, errors)\n\t\t\t\tif (target) {\n\t\t\t\t\tnavigateToStep(target)\n\t\t\t\t}\n\t\t\t}\n\t\t\trequestFocus('firstInvalid')\n\t\t\treturn\n\t\t}\n\t\trawDispatch({ type: 'SUBMIT_START' })\n\t\tconst values: SubmissionValue[] = answeredValues()\n\t\tif (honeypotName) {\n\t\t\tconst decoy = honeypotRef.current?.value ?? ''\n\t\t\tif (decoy !== '') {\n\t\t\t\t// Submit the decoy under a reserved key, not its cosmetic DOM name, so a real field sharing\n\t\t\t\t// that name is never stripped or mistaken for the honeypot on the server.\n\t\t\t\tvalues.push({ field: HONEYPOT_VALUE_KEY, value: decoy })\n\t\t\t}\n\t\t}\n\t\tif (captchaToken) {\n\t\t\tvalues.push({ field: CAPTCHA_TOKEN_KEY, value: captchaToken })\n\t\t}\n\t\tconst result: SubmitFormResult = onSubmit\n\t\t\t? await onSubmit({ formId: form.id, values })\n\t\t\t: await submitForm({ formId: form.id, values, apiRoute })\n\t\tsubmittingRef.current = false\n\t\tif (result.ok) {\n\t\t\t// A submission happened, so the unmount effect must not emit `form.abandoned`, in either mode.\n\t\t\tsubmittedRef.current = true\n\t\t\temitFormEvent(sinkRef.current, formIdRef.current, {\n\t\t\t\ttype: 'submission.created',\n\t\t\t\tsubmissionId: result.submissionId,\n\t\t\t})\n\t\t\t// Resolve the response before a reset clears the answers the recall reads from.\n\t\t\tonSuccess?.(result.submissionId, { response: resolveSuccessResponse() })\n\t\t\tif (successBehavior === 'reset') {\n\t\t\t\t// Reset in place: the host handles feedback (e.g. a toast via onSuccess); no success screen.\n\t\t\t\trawDispatch({\n\t\t\t\t\ttype: 'RESET',\n\t\t\t\t\tvalues: { ...seedFieldValues(form.fields), ...(initialValues ?? {}) },\n\t\t\t\t})\n\t\t\t\t// The reducer holds only values/errors; flow position and the lifecycle `started` ref live\n\t\t\t\t// outside it. Reset them too so a multi-step form returns to its first step (not stranded on\n\t\t\t\t// the terminal one) and a fresh fill re-emits `form.started`. `submittedRef` stays set: a\n\t\t\t\t// submission did happen, so the unmount guard must not report the completed form abandoned.\n\t\t\t\tif (flow) {\n\t\t\t\t\tsetCurrentStepId(firstStepId(flow))\n\t\t\t\t\tsetHistory([])\n\t\t\t\t}\n\t\t\t\tstartedRef.current = false\n\t\t\t} else {\n\t\t\t\trawDispatch({ type: 'SUBMIT_SUCCESS' })\n\t\t\t\tif (activePresentation.dismissOnSuccess) {\n\t\t\t\t\thandleClose()\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst redirectUrl =\n\t\t\t\tform.response?.type === 'redirect' ? form.response.redirect?.url : undefined\n\t\t\t// Part of submit handling, not rendering: fires on the custom-`children` path too.\n\t\t\t// Browser-only: no-op during SSR or in non-DOM test environments.\n\t\t\tif (\n\t\t\t\ttypeof redirectUrl === 'string' &&\n\t\t\t\tredirectUrl.length > 0 &&\n\t\t\t\ttypeof window !== 'undefined'\n\t\t\t) {\n\t\t\t\twindow.location.assign(redirectUrl)\n\t\t\t}\n\t\t} else {\n\t\t\tif (result.fieldErrors) {\n\t\t\t\trawDispatch({ type: 'SET_ALL_ISSUES', errors: result.fieldErrors, steps: allStepIds })\n\t\t\t}\n\t\t\tconst message = result.message ?? translate(keys.formSubmitFailed)\n\t\t\trawDispatch({ type: 'SUBMIT_ERROR', message })\n\t\t\tonError?.(message)\n\t\t}\n\t}\n\n\tconst isTerminalStep =\n\t\tflow && currentStepId ? isTerminalStepId(flow, currentStepId, effectiveValues) : true\n\n\t// Enter on a multi-step form: on a non-terminal step, advance like Next (validate, then advance or\n\t// reveal + focus); on the terminal step, fall through to native submit (guarded by `submittingRef`).\n\t// A textarea (Enter = newline), select (confirm), and buttons/submit inputs (activation) are exempt.\n\t// Single-step forms keep native Enter-to-submit. The `<form>` is the plugin's even in children mode,\n\t// so this is the only place a host could get this behavior.\n\tconst handleKeyDown = (event: ReactKeyboardEvent<HTMLFormElement>) => {\n\t\tif (!flow || event.key !== 'Enter') {\n\t\t\treturn\n\t\t}\n\t\tconst target = event.target\n\t\tif (\n\t\t\ttarget instanceof HTMLTextAreaElement ||\n\t\t\ttarget instanceof HTMLSelectElement ||\n\t\t\ttarget instanceof HTMLButtonElement\n\t\t) {\n\t\t\treturn\n\t\t}\n\t\tif (\n\t\t\ttarget instanceof HTMLInputElement &&\n\t\t\t(target.type === 'submit' || target.type === 'button')\n\t\t) {\n\t\t\treturn\n\t\t}\n\t\tif (!isTerminalStep) {\n\t\t\tevent.preventDefault()\n\t\t\tvoid goNext()\n\t\t}\n\t}\n\n\tconst step: FormStepInfo = flow\n\t\t? {\n\t\t\t\tflow,\n\t\t\t\tcurrentStepId,\n\t\t\t\tstepIndex: flow.steps.findIndex((s) => s.id === currentStepId),\n\t\t\t\tstepCount: flow.steps.length,\n\t\t\t\tisFirst: history.length === 0,\n\t\t\t\tisTerminal: isTerminalStep,\n\t\t\t\tgoNext: () => {\n\t\t\t\t\tvoid goNext()\n\t\t\t\t},\n\t\t\t\tgoBack,\n\t\t\t}\n\t\t: {\n\t\t\t\tstepIndex: 0,\n\t\t\t\tstepCount: 1,\n\t\t\t\tisFirst: true,\n\t\t\t\tisTerminal: true,\n\t\t\t\tgoNext: () => {},\n\t\t\t\tgoBack: () => {},\n\t\t\t}\n\n\t// The \"Step X of Y\" announcement (aria-live + the step region's accessible name).\n\tconst stepStatusText = flow\n\t\t? resolveMessage(translate(keys.formStepStatus), {\n\t\t\t\tcurrent: String(step.stepIndex + 1),\n\t\t\t\ttotal: String(step.stepCount),\n\t\t\t})\n\t\t: ''\n\t// Whether the current step has been attempted and still has a revealed error (drives the step-level alert).\n\tconst currentStepHasError =\n\t\tflow != null &&\n\t\tcurrentStepId != null &&\n\t\tstate.attemptedSteps.has(currentStepId) &&\n\t\tObject.entries(state.errors).some(\n\t\t\t([key, errs]) => errs.length > 0 && stepIdOfField(baseFieldKey(key)) === currentStepId\n\t\t)\n\n\tconst renderedFields = (flow ? stepVisible : visible).filter(\n\t\t(field) => field.hidden !== true && field.calcDisplay !== false\n\t)\n\n\tconst contextValue: FormContextValue = {\n\t\tform,\n\t\tstate,\n\t\tdispatch,\n\t\tvalidateField,\n\t\tlocale,\n\t\tstep,\n\t\trendererRegistry,\n\t\tlabels,\n\t\tt: translate,\n\t\teffectiveValues,\n\t\trecall,\n\t\trenderedFields,\n\t\tconverters,\n\t\tstepIdOfField,\n\t}\n\n\tconst PresentationWrapper = activePresentation.Wrapper\n\tconst wrap = (content: ReactNode): ReactNode =>\n\t\tPresentationWrapper ? (\n\t\t\t<PresentationWrapper\n\t\t\t\tpresentation={activePresentation}\n\t\t\t\topen\n\t\t\t\tonClose={handleClose}\n\t\t\t\ttitle={title}\n\t\t\t\tcloseLabel={resolvedCloseLabel}\n\t\t\t>\n\t\t\t\t{content}\n\t\t\t</PresentationWrapper>\n\t\t) : (\n\t\t\tcontent\n\t\t)\n\n\tif (children !== undefined) {\n\t\treturn (\n\t\t\t<FormContext.Provider value={contextValue}>\n\t\t\t\t{wrap(\n\t\t\t\t\t<form\n\t\t\t\t\t\tref={formRef}\n\t\t\t\t\t\tclassName={cn('fb-form-root', className)}\n\t\t\t\t\t\tnoValidate\n\t\t\t\t\t\tonSubmit={handleSubmit}\n\t\t\t\t\t\tonKeyDown={handleKeyDown}\n\t\t\t\t\t\tdata-fb-presentation={activePresentation.name}\n\t\t\t\t\t\tdata-fb-density={activePresentation.density}\n\t\t\t\t\t>\n\t\t\t\t\t\t{honeypotName ? <Honeypot name={honeypotName} inputRef={honeypotRef} /> : null}\n\t\t\t\t\t\t{children}\n\t\t\t\t\t</form>\n\t\t\t\t)}\n\t\t\t</FormContext.Provider>\n\t\t)\n\t}\n\n\tif (state.submitted) {\n\t\tconst successResponse = resolveSuccessResponse()\n\t\tconst responseHtml = successResponse?.type === 'message' ? successResponse.html : undefined\n\t\treturn (\n\t\t\t<FormContext.Provider value={contextValue}>\n\t\t\t\t{wrap(\n\t\t\t\t\tresponseHtml ? (\n\t\t\t\t\t\t// Safe to inject: serializeBody HTML-escapes all text (recall values included) and sanitizes link URLs.\n\t\t\t\t\t\t<div\n\t\t\t\t\t\t\trole=\"status\"\n\t\t\t\t\t\t\tclassName={cn('fb-form__success', className)}\n\t\t\t\t\t\t\tdata-fb-presentation={activePresentation.name}\n\t\t\t\t\t\t\tdata-fb-density={activePresentation.density}\n\t\t\t\t\t\t\t// biome-ignore lint/security/noDangerouslySetInnerHtml: HTML is produced by our escaping serializer, never raw user input\n\t\t\t\t\t\t\tdangerouslySetInnerHTML={{ __html: responseHtml }}\n\t\t\t\t\t\t/>\n\t\t\t\t\t) : (\n\t\t\t\t\t\t<p\n\t\t\t\t\t\t\trole=\"status\"\n\t\t\t\t\t\t\tclassName={cn('fb-form__success', className)}\n\t\t\t\t\t\t\tdata-fb-presentation={activePresentation.name}\n\t\t\t\t\t\t\tdata-fb-density={activePresentation.density}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{interpolate(resolvedSuccessMessage, recall)}\n\t\t\t\t\t\t</p>\n\t\t\t\t\t)\n\t\t\t\t)}\n\t\t\t</FormContext.Provider>\n\t\t)\n\t}\n\n\treturn (\n\t\t<FormContext.Provider value={contextValue}>\n\t\t\t{wrap(\n\t\t\t\t<form\n\t\t\t\t\tref={formRef}\n\t\t\t\t\tclassName={cn('fb-form-root', className)}\n\t\t\t\t\tnoValidate\n\t\t\t\t\tonSubmit={handleSubmit}\n\t\t\t\t\tonKeyDown={handleKeyDown}\n\t\t\t\t\tdata-fb-presentation={activePresentation.name}\n\t\t\t\t\tdata-fb-density={activePresentation.density}\n\t\t\t\t>\n\t\t\t\t\t{honeypotName ? <Honeypot name={honeypotName} inputRef={honeypotRef} /> : null}\n\t\t\t\t\t{header}\n\t\t\t\t\t{flow ? (\n\t\t\t\t\t\t<>\n\t\t\t\t\t\t\t{/* Announces \"Step X of Y\" politely on each step change. A bare aria-live region, not\n\t\t\t\t\t\t\t role=status, so the single status role stays with the form's success outcome. */}\n\t\t\t\t\t\t\t<div aria-live=\"polite\" aria-atomic=\"true\" style={SR_ONLY}>\n\t\t\t\t\t\t\t\t{stepStatusText}\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t{/* Focus lands here on a step change (the region's start), so keyboard/SR users move with it.\n\t\t\t\t\t\t\t A plain focusable container, not a named group; the aria-live region above does the announcing. */}\n\t\t\t\t\t\t\t<div data-fb-step-region tabIndex={-1} className=\"fb-form__step\">\n\t\t\t\t\t\t\t\t<FormFields layout={layout} />\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t{currentStepHasError ? (\n\t\t\t\t\t\t\t\t<p role=\"alert\" className=\"fb-form__step-error\">\n\t\t\t\t\t\t\t\t\t{translate(keys.formStepInvalid)}\n\t\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t</>\n\t\t\t\t\t) : (\n\t\t\t\t\t\t<FormFields layout={layout} />\n\t\t\t\t\t)}\n\t\t\t\t\t{state.submitError ? (\n\t\t\t\t\t\t<p role=\"alert\" className=\"fb-form__submit-error\">\n\t\t\t\t\t\t\t{state.submitError}\n\t\t\t\t\t\t</p>\n\t\t\t\t\t) : null}\n\t\t\t\t\t<FormControls\n\t\t\t\t\t\tbackButtonClassName={backButtonClassName}\n\t\t\t\t\t\tnextButtonClassName={nextButtonClassName}\n\t\t\t\t\t\tsubmitButtonClassName={submitButtonClassName}\n\t\t\t\t\t\trenderBack={renderBack}\n\t\t\t\t\t\trenderNext={renderNext}\n\t\t\t\t\t\trenderSubmit={renderSubmit}\n\t\t\t\t\t/>\n\t\t\t\t</form>\n\t\t\t)}\n\t\t</FormContext.Provider>\n\t)\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Form.js","names":[],"sources":["../../src/react/Form.tsx"],"sourcesContent":["'use client'\n\nimport {\n\ttype CSSProperties,\n\ttype FormEvent as ReactFormEvent,\n\ttype KeyboardEvent as ReactKeyboardEvent,\n\ttype ReactNode,\n\tuseCallback,\n\tuseEffect,\n\tuseMemo,\n\tuseReducer,\n\tuseRef,\n\tuseState,\n} from 'react'\nimport type { BodyConverter } from '../actions/body/converters'\nimport { serializeBody } from '../actions/body/serializeBody'\nimport { calcExpressionOf, computeCalcFields } from '../calc/computeCalcFields'\nimport { evaluateCondition } from '../conditions/evaluate'\nimport { noopEventSink } from '../events/noopSink'\nimport type { FormEventSink } from '../events/types'\nimport { fieldKey, isNamedField, type NamedFormFieldInstance } from '../fields/fieldKey'\nimport type { AnyFormFieldDefinition } from '../fields/types'\nimport { firstStepId, isTerminalStepId, resolveNextStepId, stepFieldNames } from '../flow/engine'\nimport type { FormFlow } from '../flow/types'\nimport type {\n\tFormButtonSettings,\n\tFormDocument,\n\tFormPollSettings,\n\tFormResponseSettings,\n} from '../form/types'\nimport {\n\tDEFAULT_PRESENTATION_NAME,\n\tdefaultPresentationDescriptors,\n} from '../presentations/defaults'\nimport { interpolate } from '../recall/interpolate'\nimport { buildRecallResolver, descriptorsFor } from '../recall/resolver'\nimport {\n\tCAPTCHA_TOKEN_KEY,\n\tCONTEXT_KEY,\n\tDEFAULT_HONEYPOT_FIELD,\n\tHONEYPOT_VALUE_KEY,\n} from '../spam/constants'\nimport type { FormFieldInstance, SubmissionValue } from '../submissions/types'\nimport { en } from '../translations/en'\nimport { keys } from '../translations/keys'\nimport { makeTranslate } from '../translations/makeTranslate'\nimport { resolveMessage } from '../validation/message'\nimport type { AnyValidationRuleDefinition } from '../validation/types'\nimport { cn } from './cn'\nimport type { RendererTranslate } from './contract'\nimport { emitFormEvent } from './events'\nimport { FormContext, type FormContextValue, type FormStepInfo } from './FormContext'\nimport {\n\ttype BackButtonRenderProps,\n\tFormControls,\n\ttype NextButtonRenderProps,\n\ttype SubmitButtonRenderProps,\n} from './FormControls'\nimport { FormFields } from './FormFields'\nimport { Honeypot } from './Honeypot'\nimport { defaultPresentations } from './presentation/presentations'\nimport { type PresentationsConfig, resolvePresentations } from './presentation/registry'\nimport type { FormPresentation } from './presentation/types'\nimport { type RenderersConfig, resolveRenderers } from './registry'\nimport { defaultRenderers } from './renderers'\nimport { buildFieldTypeRegistry, buildValidationRuleRegistry, visibleFields } from './resolveForm'\nimport {\n\tDEFAULT_STEP_ID,\n\ttype FieldErrors,\n\ttype FormAction,\n\tformReducer,\n\tinitialFormState,\n\tseedFieldValues,\n} from './state'\nimport { type SubmitFormResult, type SubmitHandler, submitForm } from './submitForm'\nimport { validateFieldValue } from './validateField'\n\nexport type {\n\tBackButtonRenderProps,\n\tNextButtonRenderProps,\n\tSubmitButtonRenderProps,\n} from './FormControls'\n// FormResponseSettings, FormButtonSettings, FormPollSettings, and FormDocument live in\n// `../form/types` (no 'use client') so server code (e.g. `toFormDocument` in a Server Component)\n// can use them without pulling in this client module. Re-exported here so `./react` and existing\n// `from './Form'` imports keep working unchanged.\nexport type { FormButtonSettings, FormDocument, FormPollSettings, FormResponseSettings }\n\n/**\n * The success response passed to `onSuccess`, recall-resolved and (for a message) serialized with the\n * form's active converters, so a host can render or toast the resolved response without re-deriving it.\n */\nexport type FormSuccessResponse =\n\t| { type: 'message'; html?: string }\n\t| { type: 'redirect'; url?: string }\n\n/** The second argument to `onSuccess`: the resolved success response (an object, so it can grow). */\nexport type FormSuccessResult = { response?: FormSuccessResponse }\n\nexport type FormProps = {\n\tform: FormDocument\n\tfieldTypes?: AnyFormFieldDefinition[]\n\trules?: AnyValidationRuleDefinition[]\n\trenderers?: RenderersConfig\n\tapiRoute?: string\n\tonSubmit?: SubmitHandler\n\t/**\n\t * Called after a successful submission with the submission id and the resolved success response\n\t * (recall-applied, serialized with `converters`), so a host can toast or render it. Fires in both\n\t * `successBehavior` modes and on the custom-`children` path.\n\t */\n\tonSuccess?: (submissionId?: string, result?: FormSuccessResult) => void\n\tonError?: (message: string) => void\n\t/**\n\t * Custom Lexical block converters (e.g. host `icon`/`badge` blocks) spread over the defaults for the\n\t * client serializer, so those blocks survive in the success message and in the `onSuccess` response.\n\t */\n\tconverters?: Record<string, BodyConverter>\n\t/**\n\t * What happens on a successful submit. `'replace'` (default) swaps the form for the success screen;\n\t * `'reset'` clears the fields in place and shows no success screen, so a host can toast via `onSuccess`\n\t * and keep the form usable.\n\t */\n\tsuccessBehavior?: 'replace' | 'reset'\n\tevents?: FormEventSink\n\tt?: RendererTranslate\n\tlocale?: string\n\tlayout?: boolean\n\t/** Submit button label. Precedence: this prop, then the form's `buttons.submitLabel`, then the translated default. */\n\tsubmitLabel?: string\n\t/** \"Next\" button label for multi-step forms. Precedence: this prop, then the form's `buttons.nextLabel`, then the translated default. */\n\tnextLabel?: string\n\t/** \"Back\" button label for multi-step forms. Precedence: this prop, then the form's `buttons.prevLabel`, then the translated default. */\n\tprevLabel?: string\n\t/** Label for the overlay close control (modal/drawer). */\n\tcloseLabel?: string\n\tsuccessMessage?: string\n\t/** Active presentation: a name into the registry or an inline presentation. Defaults to `'page'` when omitted. */\n\tpresentation?: string | FormPresentation\n\t/** Per-render presentation overrides merged onto the defaults (add, replace, or `false` to remove). */\n\tpresentations?: PresentationsConfig\n\t/** Invoked when an overlay presentation dismisses (close button, Escape, outside click, or `dismissOnSuccess`). */\n\tonClose?: () => void\n\t/**\n\t * Accessible name for an overlay surface (modal/drawer). Hosts choosing between a trigger\n\t * label and the form's own admin title should prefer `form.title` when set, falling back to\n\t * their own label otherwise.\n\t */\n\ttitle?: string\n\t/** Seed initial field values (e.g. from `valuesFromSearchParams`). Still validated on submit. */\n\tinitialValues?: Record<string, unknown>\n\t/** Honeypot decoy (on by default). `false` removes it; `{ name }` matches a customized server `spam.honeypot.fieldName`. */\n\thoneypot?: false | { name?: string }\n\t/** A token from your captcha widget; verified server-side when a captcha provider is configured. */\n\tcaptchaToken?: string\n\t/**\n\t * A signed form-context token from `signFormContext` (server/RSC), tying this render to a document\n\t * (e.g. the profile page it is on). Carried alongside the answers, verified server-side, and\n\t * available to `email.recipientSources`; it is never stored as an answer.\n\t */\n\tcontext?: string\n\t/** Custom layout: render fields with `useField`/`useFormState` instead of the auto-rendered field loop. */\n\tchildren?: ReactNode\n\t/** Chrome rendered inside the form, above the fields, in default mode (e.g. `<FormSteps />`). */\n\theader?: ReactNode\n\t/** Additional CSS class names applied to the root `<form>` element (and the success node). */\n\tclassName?: string\n\t/** Replace the default submit button entirely. Receives the resolved label and submitting state. */\n\trenderSubmit?: (props: SubmitButtonRenderProps) => ReactNode\n\t/** Replace the default \"Next\" button in multi-step forms. */\n\trenderNext?: (props: NextButtonRenderProps) => ReactNode\n\t/** Replace the default \"Back\" button in multi-step forms. */\n\trenderBack?: (props: BackButtonRenderProps) => ReactNode\n\t/** CSS class forwarded to the default submit `<button>`. Ignored when `renderSubmit` is provided. */\n\tsubmitButtonClassName?: string\n\t/** CSS class forwarded to the default \"Next\" `<button>`. Ignored when `renderNext` is provided. */\n\tnextButtonClassName?: string\n\t/** CSS class forwarded to the default \"Back\" `<button>`. Ignored when `renderBack` is provided. */\n\tbackButtonClassName?: string\n}\n\nconst isEmpty = (value: unknown): boolean =>\n\tvalue == null || value === '' || (Array.isArray(value) && value.length === 0)\n\n/** Visually hidden but screen-reader-announced, for the \"Step X of Y\" live region (no host CSS required). */\nconst SR_ONLY: CSSProperties = {\n\tposition: 'absolute',\n\twidth: 1,\n\theight: 1,\n\tpadding: 0,\n\tmargin: -1,\n\toverflow: 'hidden',\n\tclip: 'rect(0, 0, 0, 0)',\n\twhiteSpace: 'nowrap',\n\tborder: 0,\n}\n\n/** The base field name of an error key: the part before a repeater composite suffix (`name[0].sub`). */\nconst baseFieldKey = (key: string): string => {\n\tconst bracket = key.indexOf('[')\n\treturn bracket === -1 ? key : key.slice(0, bracket)\n}\n\n/** The id of the first flow step (in order) that owns an errored field, or undefined when none does. */\nconst firstStepWithError = (flow: FormFlow, errors: FieldErrors): string | undefined => {\n\tconst errored = new Set(Object.keys(errors).map(baseFieldKey))\n\treturn flow.steps.find((flowStep) => flowStep.fields.some((key) => errored.has(key)))?.id\n}\n\n/** The first focusable element under `root` that a step transition should land on (skips hidden/honeypot). */\nconst focusFirstIn = (root: HTMLElement | null, selector: string): void => {\n\tconst target = root?.querySelector<HTMLElement>(selector)\n\ttarget?.focus()\n}\n\n/** A stored button label counts only when it is a non-empty string; anything else falls through. */\nconst storedLabel = (value: unknown): string | undefined =>\n\ttypeof value === 'string' && value.length > 0 ? value : undefined\n\n/** The headless form controller: state, progressive client validation, conditional visibility, submission, events. */\nexport const Form = ({\n\tform,\n\tfieldTypes,\n\trules,\n\trenderers,\n\tapiRoute,\n\tonSubmit,\n\tonSuccess,\n\tonError,\n\tconverters,\n\tsuccessBehavior = 'replace',\n\tevents,\n\tt,\n\tlocale = 'en',\n\tlayout,\n\tsubmitLabel,\n\tnextLabel,\n\tprevLabel,\n\tcloseLabel,\n\tsuccessMessage,\n\tpresentation,\n\tpresentations,\n\tonClose,\n\ttitle,\n\tinitialValues,\n\thoneypot,\n\tcaptchaToken,\n\tcontext,\n\tchildren,\n\theader,\n\tclassName,\n\trenderSubmit,\n\trenderNext,\n\trenderBack,\n\tsubmitButtonClassName,\n\tnextButtonClassName,\n\tbackButtonClassName,\n}: FormProps) => {\n\tconst honeypotName = honeypot === false ? null : (honeypot?.name ?? DEFAULT_HONEYPOT_FIELD)\n\tconst honeypotRef = useRef<HTMLInputElement>(null)\n\tconst registry = useMemo(() => buildFieldTypeRegistry(fieldTypes), [fieldTypes])\n\tconst ruleRegistry = useMemo(() => buildValidationRuleRegistry(rules), [rules])\n\tconst rendererRegistry = useMemo(() => resolveRenderers(defaultRenderers, renderers), [renderers])\n\tconst presentationRegistry = useMemo(\n\t\t() => resolvePresentations(defaultPresentations, presentations),\n\t\t[presentations]\n\t)\n\tconst activePresentation: FormPresentation =\n\t\ttypeof presentation === 'object'\n\t\t\t? presentation\n\t\t\t: (presentationRegistry.get(presentation ?? DEFAULT_PRESENTATION_NAME) ??\n\t\t\t\tpresentationRegistry.get(DEFAULT_PRESENTATION_NAME) ??\n\t\t\t\tdefaultPresentationDescriptors.page)\n\tconst fieldsByName = useMemo(\n\t\t() => new Map(form.fields.filter(isNamedField).map((field) => [field.name, field])),\n\t\t[form.fields]\n\t)\n\tconst translate = useMemo<RendererTranslate>(() => t ?? makeTranslate(en), [t])\n\tconst resolvedCloseLabel = closeLabel ?? translate(keys.formClose)\n\tconst resolvedSuccessMessage = successMessage ?? translate(keys.formSuccess)\n\tconst docButtons: FormButtonSettings | undefined = form.buttons\n\tconst labels = useMemo(\n\t\t() => ({\n\t\t\tprev: prevLabel ?? storedLabel(docButtons?.prevLabel) ?? translate(keys.formBack),\n\t\t\tnext: nextLabel ?? storedLabel(docButtons?.nextLabel) ?? translate(keys.formNext),\n\t\t\tsubmit: submitLabel ?? storedLabel(docButtons?.submitLabel) ?? translate(keys.formSubmit),\n\t\t}),\n\t\t[prevLabel, nextLabel, submitLabel, docButtons, translate]\n\t)\n\n\t// Latest-value refs so event emission and the mount/unmount effect tolerate an inline `events` prop or a changing form id.\n\tconst sinkRef = useRef<FormEventSink>(noopEventSink)\n\tsinkRef.current = events ?? noopEventSink\n\tconst formIdRef = useRef('')\n\tformIdRef.current = String(form.id)\n\n\tconst [state, rawDispatch] = useReducer(formReducer, form.fields, (fields) =>\n\t\tinitialFormState({\n\t\t\t...seedFieldValues(fields),\n\t\t\t...(initialValues ?? {}),\n\t\t})\n\t)\n\n\t// Authoritative values for derived (calc) fields, recomputed from user answers on every change. The\n\t// server recomputes these too at submit; the client copy drives the live calc renderer, recall, and submit.\n\tconst effectiveValues = useMemo(\n\t\t() => computeCalcFields(form.fields, state.values),\n\t\t[form.fields, state.values]\n\t)\n\n\tconst recall = useMemo(\n\t\t() =>\n\t\t\tbuildRecallResolver({\n\t\t\t\tfields: form.fields,\n\t\t\t\tvalues: effectiveValues,\n\t\t\t\tregistry,\n\t\t\t\tlocale,\n\t\t\t\tt: translate,\n\t\t\t}),\n\t\t[form.fields, effectiveValues, registry, locale, translate]\n\t)\n\n\t// Multi-step is active only when the form is flagged `multistep` and its flow declares two or more\n\t// steps. With the flag off the form renders as a single page even if flow data is still stored.\n\tconst flow =\n\t\tform.multistep === true && form.flow && form.flow.steps.length >= 2 ? form.flow : undefined\n\tconst [currentStepId, setCurrentStepId] = useState<string | undefined>(() =>\n\t\tflow ? firstStepId(flow) : undefined\n\t)\n\tconst [history, setHistory] = useState<string[]>([])\n\n\tconst startedRef = useRef(false)\n\tconst submittedRef = useRef(false)\n\tconst submittingRef = useRef(false)\n\tconst advancingRef = useRef(false)\n\tconst flowRef = useRef(flow)\n\tflowRef.current = flow\n\n\t// Per-step error reveal: a field maps to the id of the flow step whose `fields` include it, else the\n\t// default step (single-step forms, or a field assigned to no step), so a single-step form collapses to\n\t// one step and today's behavior.\n\tconst stepIdOfField = useMemo(() => {\n\t\tconst map = new Map<string, string>()\n\t\tif (flow) {\n\t\t\tfor (const flowStep of flow.steps) {\n\t\t\t\tfor (const key of flowStep.fields) {\n\t\t\t\t\tmap.set(key, flowStep.id)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn (fieldKey: string): string => map.get(fieldKey) ?? DEFAULT_STEP_ID\n\t}, [flow])\n\tconst allStepIds = useMemo(\n\t\t() => (flow ? flow.steps.map((flowStep) => flowStep.id) : [DEFAULT_STEP_ID]),\n\t\t[flow]\n\t)\n\n\t// Focus management for step transitions and blocked advances/submits. A pending request is performed\n\t// by an effect after the render it triggers, so focus lands on the DOM that reflects the new state.\n\tconst formRef = useRef<HTMLFormElement>(null)\n\tconst pendingFocusRef = useRef<'stepStart' | 'firstInvalid' | null>(null)\n\tconst [focusNonce, setFocusNonce] = useState(0)\n\tconst requestFocus = (intent: 'stepStart' | 'firstInvalid') => {\n\t\tpendingFocusRef.current = intent\n\t\tsetFocusNonce((nonce) => nonce + 1)\n\t}\n\n\tconst dispatch = useCallback((action: FormAction) => {\n\t\tif (action.type === 'SET_VALUE' && !startedRef.current) {\n\t\t\tstartedRef.current = true\n\t\t\temitFormEvent(sinkRef.current, formIdRef.current, { type: 'form.started' })\n\t\t}\n\t\trawDispatch(action)\n\t}, [])\n\n\tconst validateField = useCallback(\n\t\t(name: string, value: unknown) => {\n\t\t\tconst field = fieldsByName.get(name)\n\t\t\tif (!field) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst answers = { ...effectiveValues, [name]: value }\n\t\t\t// Mirror the server: a field whose `validateWhen` is unmet is not validated; clear any stale error.\n\t\t\tif (!evaluateCondition(field.validateWhen, answers)) {\n\t\t\t\trawDispatch({ type: 'SET_FIELD_ISSUES', name, errors: [] })\n\t\t\t\treturn\n\t\t\t}\n\t\t\tvoid validateFieldValue({\n\t\t\t\tfield,\n\t\t\t\tvalue,\n\t\t\t\tregistry,\n\t\t\t\truleRegistry,\n\t\t\t\tanswers,\n\t\t\t\tlocale,\n\t\t\t\tt: translate,\n\t\t\t}).then(({ errors }) => {\n\t\t\t\trawDispatch({ type: 'SET_FIELD_ISSUES', name, errors })\n\t\t\t\tconst [firstError] = errors\n\t\t\t\tif (firstError !== undefined) {\n\t\t\t\t\temitFormEvent(sinkRef.current, formIdRef.current, {\n\t\t\t\t\t\ttype: 'field.errored',\n\t\t\t\t\t\tfield: name,\n\t\t\t\t\t\tmessage: firstError,\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t})\n\t\t},\n\t\t[fieldsByName, effectiveValues, registry, ruleRegistry, locale, translate]\n\t)\n\n\tconst visible = visibleFields(form.fields, effectiveValues)\n\n\t/** Visible, answered named fields. Display-only ('none' kind) and nameless (bare) fields never contribute. */\n\tconst answerableFields = (): NamedFormFieldInstance[] =>\n\t\tvisibleFields(form.fields, effectiveValues)\n\t\t\t.filter((field) => registry.get(field.blockType)?.value !== 'none')\n\t\t\t.filter(isNamedField)\n\t\t\t.filter((field) => !isEmpty(effectiveValues[field.name]))\n\n\t/** Answered visible fields as raw submission values, sent to the server on submit. */\n\tconst answeredValues = (): SubmissionValue[] =>\n\t\tanswerableFields().map((field) => ({ field: field.name, value: effectiveValues[field.name] }))\n\n\t/**\n\t * Same fields, formatted via `recall` (option labels, Yes/No, localized dates): recall-fidelity\n\t * values for client-rendered templates, matching what the server gives email-team's body.\n\t */\n\tconst formattedValues = (): SubmissionValue[] =>\n\t\tanswerableFields().map((field) => ({ field: field.name, value: recall(field.name) }))\n\n\t/**\n\t * The recall-resolved success response: a redirect's url, or the response message serialized with\n\t * the active `converters` (so host blocks survive). Shared by the success screen and the value\n\t * handed to `onSuccess`, so both stay identical.\n\t */\n\tconst resolveSuccessResponse = (): FormSuccessResponse | undefined => {\n\t\tconst response = form.response\n\t\tif (response?.type === 'redirect') {\n\t\t\treturn { type: 'redirect', url: response.redirect?.url ?? undefined }\n\t\t}\n\t\tconst message =\n\t\t\tresponse?.type === 'message' || response?.type == null ? response?.message : undefined\n\t\tif (!message) {\n\t\t\treturn undefined\n\t\t}\n\t\treturn {\n\t\t\ttype: 'message',\n\t\t\thtml: serializeBody(message, {\n\t\t\t\tvalues: formattedValues(),\n\t\t\t\tdescriptors: descriptorsFor(answerableFields()),\n\t\t\t\tconverters,\n\t\t\t}),\n\t\t}\n\t}\n\n\t// Steps address fields by key: machine names for named fields, block row ids for bare blocks.\n\t// `step.fields` is membership only; render order follows `form.fields` (the order of `visible`),\n\t// so a step shows its fields in the form's field order, not the flow-builder entry order.\n\tconst stepKeys = flow && currentStepId ? stepFieldNames(flow, currentStepId) : []\n\tconst stepKeySet = new Set(stepKeys)\n\tconst stepVisible: FormFieldInstance[] = visible.filter((field) =>\n\t\tstepKeySet.has(fieldKey(field))\n\t)\n\n\t// Validate the sub-fields of the given repeaters, one pass per visible row, returning composite-key\n\t// errors (`fieldName[rowIndex].subFieldName`). Shared by submit and step navigation so both mirror\n\t// the server's per-row pass and neither lets an invalid required sub-field slip through.\n\tconst validateRepeaterSubFields = async (\n\t\trepeaters: FormFieldInstance[]\n\t): Promise<FieldErrors> => {\n\t\tconst errors: FieldErrors = {}\n\t\tfor (const field of repeaters.filter(\n\t\t\t(f): f is NamedFormFieldInstance => f.blockType === 'repeater' && isNamedField(f)\n\t\t)) {\n\t\t\tconst rows = Array.isArray(effectiveValues[field.name])\n\t\t\t\t? (effectiveValues[field.name] as Array<Record<string, unknown>>)\n\t\t\t\t: []\n\t\t\tconst subFields = (\n\t\t\t\tArray.isArray(field.subFields) ? (field.subFields as FormFieldInstance[]) : []\n\t\t\t).filter(isNamedField)\n\t\t\tfor (let rowIndex = 0; rowIndex < rows.length; rowIndex++) {\n\t\t\t\tconst row = rows[rowIndex] ?? {}\n\t\t\t\tfor (const subField of subFields) {\n\t\t\t\t\tif (!evaluateCondition(subField.visibleWhen, row)) continue\n\t\t\t\t\tif (!evaluateCondition(subField.validateWhen, row)) continue\n\t\t\t\t\tconst subResult = await validateFieldValue({\n\t\t\t\t\t\tfield: subField,\n\t\t\t\t\t\tvalue: row[subField.name],\n\t\t\t\t\t\tregistry,\n\t\t\t\t\t\truleRegistry,\n\t\t\t\t\t\tanswers: row,\n\t\t\t\t\t\tlocale,\n\t\t\t\t\t\tt: translate,\n\t\t\t\t\t})\n\t\t\t\t\tconst compositeKey = `${field.name}[${rowIndex}].${subField.name}`\n\t\t\t\t\tif (subResult.errors.length > 0) errors[compositeKey] = subResult.errors\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn errors\n\t}\n\n\tconst goNext = async () => {\n\t\t// Re-entrancy guard: a double-click during async validation must not push the same step onto\n\t\t// history twice (which would need two Back presses to undo).\n\t\tif (!flow || !currentStepId || advancingRef.current) {\n\t\t\treturn\n\t\t}\n\t\tadvancingRef.current = true\n\t\ttry {\n\t\t\tconst results = await Promise.all(\n\t\t\t\tstepVisible\n\t\t\t\t\t.filter((field) => !calcExpressionOf(field))\n\t\t\t\t\t.filter((field) => registry.get(field.blockType)?.value !== 'none')\n\t\t\t\t\t.filter(isNamedField)\n\t\t\t\t\t.filter((field) => evaluateCondition(field.validateWhen, effectiveValues))\n\t\t\t\t\t.map(async (field) => ({\n\t\t\t\t\t\tfield,\n\t\t\t\t\t\t...(await validateFieldValue({\n\t\t\t\t\t\t\tfield,\n\t\t\t\t\t\t\tvalue: effectiveValues[field.name],\n\t\t\t\t\t\t\tregistry,\n\t\t\t\t\t\t\truleRegistry,\n\t\t\t\t\t\t\tanswers: effectiveValues,\n\t\t\t\t\t\t\tlocale,\n\t\t\t\t\t\t\tt: translate,\n\t\t\t\t\t\t})),\n\t\t\t\t\t}))\n\t\t\t)\n\t\t\tlet hasError = false\n\t\t\tfor (const result of results) {\n\t\t\t\trawDispatch({ type: 'TOUCH', name: result.field.name })\n\t\t\t\trawDispatch({\n\t\t\t\t\ttype: 'SET_FIELD_ISSUES',\n\t\t\t\t\tname: result.field.name,\n\t\t\t\t\terrors: result.errors,\n\t\t\t\t})\n\t\t\t\tif (result.errors.length > 0) {\n\t\t\t\t\thasError = true\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Mirror submit: validate the step's repeater sub-fields too, so a required sub-field can't be\n\t\t\t// skipped past on a non-terminal step (errors surface inline via the composite key).\n\t\t\tconst repeaterErrors = await validateRepeaterSubFields(stepVisible)\n\t\t\tfor (const [compositeKey, errs] of Object.entries(repeaterErrors)) {\n\t\t\t\trawDispatch({ type: 'SET_FIELD_ISSUES', name: compositeKey, errors: errs })\n\t\t\t\thasError = true\n\t\t\t}\n\t\t\tif (hasError) {\n\t\t\t\t// Mark this step attempted so its fields reveal their errors, then focus the first invalid one.\n\t\t\t\trawDispatch({ type: 'MARK_STEP_ATTEMPTED', stepId: currentStepId })\n\t\t\t\trequestFocus('firstInvalid')\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst next = resolveNextStepId(flow, currentStepId, effectiveValues)\n\t\t\tif (!next) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\temitFormEvent(sinkRef.current, formIdRef.current, {\n\t\t\t\ttype: 'step.completed',\n\t\t\t\tstepId: currentStepId,\n\t\t\t})\n\t\t\tsetHistory((prev) => [...prev, currentStepId])\n\t\t\tsetCurrentStepId(next)\n\t\t\trequestFocus('stepStart')\n\t\t\temitFormEvent(sinkRef.current, formIdRef.current, { type: 'step.viewed', stepId: next })\n\t\t} finally {\n\t\t\tadvancingRef.current = false\n\t\t}\n\t}\n\n\tconst goBack = () => {\n\t\tconst prev = history[history.length - 1]\n\t\tif (prev === undefined) {\n\t\t\treturn\n\t\t}\n\t\tsetHistory((entries) => entries.slice(0, -1))\n\t\tsetCurrentStepId(prev)\n\t\trequestFocus('stepStart')\n\t\temitFormEvent(sinkRef.current, formIdRef.current, { type: 'step.viewed', stepId: prev })\n\t}\n\n\t// Jump to an earlier step (from the terminal Submit when an earlier step is invalid), rebuilding the\n\t// Back stack as the flow's linear path up to it so Back still works.\n\tconst navigateToStep = (stepId: string) => {\n\t\tif (!flow || stepId === currentStepId) {\n\t\t\treturn\n\t\t}\n\t\tconst idx = flow.steps.findIndex((flowStep) => flowStep.id === stepId)\n\t\tif (idx < 0) {\n\t\t\treturn\n\t\t}\n\t\tsetHistory(flow.steps.slice(0, idx).map((flowStep) => flowStep.id))\n\t\tsetCurrentStepId(stepId)\n\t\temitFormEvent(sinkRef.current, formIdRef.current, { type: 'step.viewed', stepId })\n\t}\n\n\t// Perform a pending focus request after the render it triggered, so it lands on the DOM that reflects\n\t// the new state (a changed step, or freshly revealed errors). Null on mount, so the first render never\n\t// steals focus. currentStepId and focusNonce are intentional re-run triggers: a blocked advance keeps\n\t// the same step, so the nonce forces a fresh run; the body reads only refs, hence the ignore.\n\t// biome-ignore lint/correctness/useExhaustiveDependencies: currentStepId/focusNonce are re-run triggers, not read in the body\n\tuseEffect(() => {\n\t\tconst intent = pendingFocusRef.current\n\t\tif (!intent) {\n\t\t\treturn\n\t\t}\n\t\tpendingFocusRef.current = null\n\t\tif (intent === 'firstInvalid') {\n\t\t\tfocusFirstIn(formRef.current, '[aria-invalid=\"true\"]')\n\t\t\treturn\n\t\t}\n\t\tconst region = formRef.current?.querySelector<HTMLElement>('[data-fb-step-region]')\n\t\tif (region) {\n\t\t\tregion.focus()\n\t\t} else {\n\t\t\tfocusFirstIn(formRef.current, 'input:not([type=\"hidden\"]), select, textarea')\n\t\t}\n\t}, [currentStepId, focusNonce])\n\n\tuseEffect(() => {\n\t\temitFormEvent(sinkRef.current, formIdRef.current, { type: 'form.viewed' })\n\t\tconst mountFlow = flowRef.current\n\t\tif (mountFlow) {\n\t\t\tconst first = firstStepId(mountFlow)\n\t\t\tif (first) {\n\t\t\t\temitFormEvent(sinkRef.current, formIdRef.current, { type: 'step.viewed', stepId: first })\n\t\t\t}\n\t\t}\n\t\treturn () => {\n\t\t\tif (!submittedRef.current && !submittingRef.current) {\n\t\t\t\temitFormEvent(sinkRef.current, formIdRef.current, { type: 'form.abandoned' })\n\t\t\t}\n\t\t}\n\t}, [])\n\n\tconst handleClose = useCallback(() => {\n\t\tonClose?.()\n\t}, [onClose])\n\n\tconst handleSubmit = async (event: ReactFormEvent<HTMLFormElement>) => {\n\t\tevent.preventDefault()\n\t\t// Re-entrancy guard: claim the in-flight slot before the async validation window so a fast second\n\t\t// activation (double-click, Enter + click) cannot reach the transport and POST the submission twice.\n\t\tif (submittingRef.current) {\n\t\t\treturn\n\t\t}\n\t\tsubmittingRef.current = true\n\t\tconst visible = visibleFields(form.fields, effectiveValues)\n\t\tconst results = await Promise.all(\n\t\t\t// Calc fields carry no rules and have no input; they are always satisfied, so skip validating them.\n\t\t\t// Display-only ('none' kind, e.g. message) and nameless (bare) fields are skipped too, mirroring the server.\n\t\t\t// A field whose `validateWhen` is unmet is skipped too, mirroring the server (no client/server divergence).\n\t\t\tvisible\n\t\t\t\t.filter((field) => !calcExpressionOf(field))\n\t\t\t\t.filter((field) => registry.get(field.blockType)?.value !== 'none')\n\t\t\t\t.filter(isNamedField)\n\t\t\t\t.filter((field) => evaluateCondition(field.validateWhen, effectiveValues))\n\t\t\t\t.map(async (field) => ({\n\t\t\t\t\tfield,\n\t\t\t\t\t...(await validateFieldValue({\n\t\t\t\t\t\tfield,\n\t\t\t\t\t\tvalue: effectiveValues[field.name],\n\t\t\t\t\t\tregistry,\n\t\t\t\t\t\truleRegistry,\n\t\t\t\t\t\tanswers: effectiveValues,\n\t\t\t\t\t\tlocale,\n\t\t\t\t\t\tt: translate,\n\t\t\t\t\t})),\n\t\t\t\t}))\n\t\t)\n\t\tconst errors: FieldErrors = {}\n\t\tfor (const result of results) {\n\t\t\tif (result.errors.length > 0) {\n\t\t\t\terrors[result.field.name] = result.errors\n\t\t\t\tconst [firstError] = result.errors\n\t\t\t\tif (firstError !== undefined) {\n\t\t\t\t\temitFormEvent(sinkRef.current, formIdRef.current, {\n\t\t\t\t\t\ttype: 'field.errored',\n\t\t\t\t\t\tfield: result.field.name,\n\t\t\t\t\t\tmessage: firstError,\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Validate sub-fields within each visible repeater (composite keys `fieldName[rowIndex].subFieldName`),\n\t\t// mirroring the server's per-row pass, so the repeater renderer surfaces them inline.\n\t\tObject.assign(errors, await validateRepeaterSubFields(visible))\n\n\t\tconst hasErrors = Object.keys(errors).length > 0\n\t\t// A terminal submit validates every step, so every step is attempted (its errors may now reveal);\n\t\t// a valid submit clears stale errors without marking anything.\n\t\trawDispatch({ type: 'SET_ALL_ISSUES', errors, steps: hasErrors ? allStepIds : [] })\n\t\tif (hasErrors) {\n\t\t\tsubmittingRef.current = false\n\t\t\t// On a multi-step form, route to the first step that owns an invalid field rather than failing in\n\t\t\t// place on the terminal step, then focus its first invalid field.\n\t\t\tif (flow && currentStepId) {\n\t\t\t\tconst target = firstStepWithError(flow, errors)\n\t\t\t\tif (target) {\n\t\t\t\t\tnavigateToStep(target)\n\t\t\t\t}\n\t\t\t}\n\t\t\trequestFocus('firstInvalid')\n\t\t\treturn\n\t\t}\n\t\trawDispatch({ type: 'SUBMIT_START' })\n\t\tconst values: SubmissionValue[] = answeredValues()\n\t\tif (honeypotName) {\n\t\t\tconst decoy = honeypotRef.current?.value ?? ''\n\t\t\tif (decoy !== '') {\n\t\t\t\t// Submit the decoy under a reserved key, not its cosmetic DOM name, so a real field sharing\n\t\t\t\t// that name is never stripped or mistaken for the honeypot on the server.\n\t\t\t\tvalues.push({ field: HONEYPOT_VALUE_KEY, value: decoy })\n\t\t\t}\n\t\t}\n\t\tif (captchaToken) {\n\t\t\tvalues.push({ field: CAPTCHA_TOKEN_KEY, value: captchaToken })\n\t\t}\n\t\tif (context) {\n\t\t\t// Rides under a reserved key like the captcha token: verified and stored separately server-side,\n\t\t\t// never merged into the answers.\n\t\t\tvalues.push({ field: CONTEXT_KEY, value: context })\n\t\t}\n\t\tconst result: SubmitFormResult = onSubmit\n\t\t\t? await onSubmit({ formId: form.id, values })\n\t\t\t: await submitForm({ formId: form.id, values, apiRoute })\n\t\tsubmittingRef.current = false\n\t\tif (result.ok) {\n\t\t\t// A submission happened, so the unmount effect must not emit `form.abandoned`, in either mode.\n\t\t\tsubmittedRef.current = true\n\t\t\temitFormEvent(sinkRef.current, formIdRef.current, {\n\t\t\t\ttype: 'submission.created',\n\t\t\t\tsubmissionId: result.submissionId,\n\t\t\t})\n\t\t\t// Resolve the response before a reset clears the answers the recall reads from.\n\t\t\tonSuccess?.(result.submissionId, { response: resolveSuccessResponse() })\n\t\t\tif (successBehavior === 'reset') {\n\t\t\t\t// Reset in place: the host handles feedback (e.g. a toast via onSuccess); no success screen.\n\t\t\t\trawDispatch({\n\t\t\t\t\ttype: 'RESET',\n\t\t\t\t\tvalues: { ...seedFieldValues(form.fields), ...(initialValues ?? {}) },\n\t\t\t\t})\n\t\t\t\t// The reducer holds only values/errors; flow position and the lifecycle `started` ref live\n\t\t\t\t// outside it. Reset them too so a multi-step form returns to its first step (not stranded on\n\t\t\t\t// the terminal one) and a fresh fill re-emits `form.started`. `submittedRef` stays set: a\n\t\t\t\t// submission did happen, so the unmount guard must not report the completed form abandoned.\n\t\t\t\tif (flow) {\n\t\t\t\t\tsetCurrentStepId(firstStepId(flow))\n\t\t\t\t\tsetHistory([])\n\t\t\t\t}\n\t\t\t\tstartedRef.current = false\n\t\t\t} else {\n\t\t\t\trawDispatch({ type: 'SUBMIT_SUCCESS' })\n\t\t\t\tif (activePresentation.dismissOnSuccess) {\n\t\t\t\t\thandleClose()\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst redirectUrl =\n\t\t\t\tform.response?.type === 'redirect' ? form.response.redirect?.url : undefined\n\t\t\t// Part of submit handling, not rendering: fires on the custom-`children` path too.\n\t\t\t// Browser-only: no-op during SSR or in non-DOM test environments.\n\t\t\tif (\n\t\t\t\ttypeof redirectUrl === 'string' &&\n\t\t\t\tredirectUrl.length > 0 &&\n\t\t\t\ttypeof window !== 'undefined'\n\t\t\t) {\n\t\t\t\twindow.location.assign(redirectUrl)\n\t\t\t}\n\t\t} else {\n\t\t\tif (result.fieldErrors) {\n\t\t\t\trawDispatch({ type: 'SET_ALL_ISSUES', errors: result.fieldErrors, steps: allStepIds })\n\t\t\t}\n\t\t\tconst message = result.message ?? translate(keys.formSubmitFailed)\n\t\t\trawDispatch({ type: 'SUBMIT_ERROR', message })\n\t\t\tonError?.(message)\n\t\t}\n\t}\n\n\tconst isTerminalStep =\n\t\tflow && currentStepId ? isTerminalStepId(flow, currentStepId, effectiveValues) : true\n\n\t// Enter on a multi-step form: on a non-terminal step, advance like Next (validate, then advance or\n\t// reveal + focus); on the terminal step, fall through to native submit (guarded by `submittingRef`).\n\t// A textarea (Enter = newline), select (confirm), and buttons/submit inputs (activation) are exempt.\n\t// Single-step forms keep native Enter-to-submit. The `<form>` is the plugin's even in children mode,\n\t// so this is the only place a host could get this behavior.\n\tconst handleKeyDown = (event: ReactKeyboardEvent<HTMLFormElement>) => {\n\t\tif (!flow || event.key !== 'Enter') {\n\t\t\treturn\n\t\t}\n\t\tconst target = event.target\n\t\tif (\n\t\t\ttarget instanceof HTMLTextAreaElement ||\n\t\t\ttarget instanceof HTMLSelectElement ||\n\t\t\ttarget instanceof HTMLButtonElement\n\t\t) {\n\t\t\treturn\n\t\t}\n\t\tif (\n\t\t\ttarget instanceof HTMLInputElement &&\n\t\t\t(target.type === 'submit' || target.type === 'button')\n\t\t) {\n\t\t\treturn\n\t\t}\n\t\tif (!isTerminalStep) {\n\t\t\tevent.preventDefault()\n\t\t\tvoid goNext()\n\t\t}\n\t}\n\n\tconst step: FormStepInfo = flow\n\t\t? {\n\t\t\t\tflow,\n\t\t\t\tcurrentStepId,\n\t\t\t\tstepIndex: flow.steps.findIndex((s) => s.id === currentStepId),\n\t\t\t\tstepCount: flow.steps.length,\n\t\t\t\tisFirst: history.length === 0,\n\t\t\t\tisTerminal: isTerminalStep,\n\t\t\t\tgoNext: () => {\n\t\t\t\t\tvoid goNext()\n\t\t\t\t},\n\t\t\t\tgoBack,\n\t\t\t}\n\t\t: {\n\t\t\t\tstepIndex: 0,\n\t\t\t\tstepCount: 1,\n\t\t\t\tisFirst: true,\n\t\t\t\tisTerminal: true,\n\t\t\t\tgoNext: () => {},\n\t\t\t\tgoBack: () => {},\n\t\t\t}\n\n\t// The \"Step X of Y\" announcement (aria-live + the step region's accessible name).\n\tconst stepStatusText = flow\n\t\t? resolveMessage(translate(keys.formStepStatus), {\n\t\t\t\tcurrent: String(step.stepIndex + 1),\n\t\t\t\ttotal: String(step.stepCount),\n\t\t\t})\n\t\t: ''\n\t// Whether the current step has been attempted and still has a revealed error (drives the step-level alert).\n\tconst currentStepHasError =\n\t\tflow != null &&\n\t\tcurrentStepId != null &&\n\t\tstate.attemptedSteps.has(currentStepId) &&\n\t\tObject.entries(state.errors).some(\n\t\t\t([key, errs]) => errs.length > 0 && stepIdOfField(baseFieldKey(key)) === currentStepId\n\t\t)\n\n\tconst renderedFields = (flow ? stepVisible : visible).filter(\n\t\t(field) => field.hidden !== true && field.calcDisplay !== false\n\t)\n\n\tconst contextValue: FormContextValue = {\n\t\tform,\n\t\tstate,\n\t\tdispatch,\n\t\tvalidateField,\n\t\tlocale,\n\t\tstep,\n\t\trendererRegistry,\n\t\tlabels,\n\t\tt: translate,\n\t\teffectiveValues,\n\t\trecall,\n\t\trenderedFields,\n\t\tconverters,\n\t\tstepIdOfField,\n\t}\n\n\tconst PresentationWrapper = activePresentation.Wrapper\n\tconst wrap = (content: ReactNode): ReactNode =>\n\t\tPresentationWrapper ? (\n\t\t\t<PresentationWrapper\n\t\t\t\tpresentation={activePresentation}\n\t\t\t\topen\n\t\t\t\tonClose={handleClose}\n\t\t\t\ttitle={title}\n\t\t\t\tcloseLabel={resolvedCloseLabel}\n\t\t\t>\n\t\t\t\t{content}\n\t\t\t</PresentationWrapper>\n\t\t) : (\n\t\t\tcontent\n\t\t)\n\n\tif (children !== undefined) {\n\t\treturn (\n\t\t\t<FormContext.Provider value={contextValue}>\n\t\t\t\t{wrap(\n\t\t\t\t\t<form\n\t\t\t\t\t\tref={formRef}\n\t\t\t\t\t\tclassName={cn('fb-form-root', className)}\n\t\t\t\t\t\tnoValidate\n\t\t\t\t\t\tonSubmit={handleSubmit}\n\t\t\t\t\t\tonKeyDown={handleKeyDown}\n\t\t\t\t\t\tdata-fb-presentation={activePresentation.name}\n\t\t\t\t\t\tdata-fb-density={activePresentation.density}\n\t\t\t\t\t>\n\t\t\t\t\t\t{honeypotName ? <Honeypot name={honeypotName} inputRef={honeypotRef} /> : null}\n\t\t\t\t\t\t{children}\n\t\t\t\t\t</form>\n\t\t\t\t)}\n\t\t\t</FormContext.Provider>\n\t\t)\n\t}\n\n\tif (state.submitted) {\n\t\tconst successResponse = resolveSuccessResponse()\n\t\tconst responseHtml = successResponse?.type === 'message' ? successResponse.html : undefined\n\t\treturn (\n\t\t\t<FormContext.Provider value={contextValue}>\n\t\t\t\t{wrap(\n\t\t\t\t\tresponseHtml ? (\n\t\t\t\t\t\t// Safe to inject: serializeBody HTML-escapes all text (recall values included) and sanitizes link URLs.\n\t\t\t\t\t\t<div\n\t\t\t\t\t\t\trole=\"status\"\n\t\t\t\t\t\t\tclassName={cn('fb-form__success', className)}\n\t\t\t\t\t\t\tdata-fb-presentation={activePresentation.name}\n\t\t\t\t\t\t\tdata-fb-density={activePresentation.density}\n\t\t\t\t\t\t\t// biome-ignore lint/security/noDangerouslySetInnerHtml: HTML is produced by our escaping serializer, never raw user input\n\t\t\t\t\t\t\tdangerouslySetInnerHTML={{ __html: responseHtml }}\n\t\t\t\t\t\t/>\n\t\t\t\t\t) : (\n\t\t\t\t\t\t<p\n\t\t\t\t\t\t\trole=\"status\"\n\t\t\t\t\t\t\tclassName={cn('fb-form__success', className)}\n\t\t\t\t\t\t\tdata-fb-presentation={activePresentation.name}\n\t\t\t\t\t\t\tdata-fb-density={activePresentation.density}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{interpolate(resolvedSuccessMessage, recall)}\n\t\t\t\t\t\t</p>\n\t\t\t\t\t)\n\t\t\t\t)}\n\t\t\t</FormContext.Provider>\n\t\t)\n\t}\n\n\treturn (\n\t\t<FormContext.Provider value={contextValue}>\n\t\t\t{wrap(\n\t\t\t\t<form\n\t\t\t\t\tref={formRef}\n\t\t\t\t\tclassName={cn('fb-form-root', className)}\n\t\t\t\t\tnoValidate\n\t\t\t\t\tonSubmit={handleSubmit}\n\t\t\t\t\tonKeyDown={handleKeyDown}\n\t\t\t\t\tdata-fb-presentation={activePresentation.name}\n\t\t\t\t\tdata-fb-density={activePresentation.density}\n\t\t\t\t>\n\t\t\t\t\t{honeypotName ? <Honeypot name={honeypotName} inputRef={honeypotRef} /> : null}\n\t\t\t\t\t{header}\n\t\t\t\t\t{flow ? (\n\t\t\t\t\t\t<>\n\t\t\t\t\t\t\t{/* Announces \"Step X of Y\" politely on each step change. A bare aria-live region, not\n\t\t\t\t\t\t\t role=status, so the single status role stays with the form's success outcome. */}\n\t\t\t\t\t\t\t<div aria-live=\"polite\" aria-atomic=\"true\" style={SR_ONLY}>\n\t\t\t\t\t\t\t\t{stepStatusText}\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t{/* Focus lands here on a step change (the region's start), so keyboard/SR users move with it.\n\t\t\t\t\t\t\t A plain focusable container, not a named group; the aria-live region above does the announcing. */}\n\t\t\t\t\t\t\t<div data-fb-step-region tabIndex={-1} className=\"fb-form__step\">\n\t\t\t\t\t\t\t\t<FormFields layout={layout} />\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t{currentStepHasError ? (\n\t\t\t\t\t\t\t\t<p role=\"alert\" className=\"fb-form__step-error\">\n\t\t\t\t\t\t\t\t\t{translate(keys.formStepInvalid)}\n\t\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t</>\n\t\t\t\t\t) : (\n\t\t\t\t\t\t<FormFields layout={layout} />\n\t\t\t\t\t)}\n\t\t\t\t\t{state.submitError ? (\n\t\t\t\t\t\t<p role=\"alert\" className=\"fb-form__submit-error\">\n\t\t\t\t\t\t\t{state.submitError}\n\t\t\t\t\t\t</p>\n\t\t\t\t\t) : null}\n\t\t\t\t\t<FormControls\n\t\t\t\t\t\tbackButtonClassName={backButtonClassName}\n\t\t\t\t\t\tnextButtonClassName={nextButtonClassName}\n\t\t\t\t\t\tsubmitButtonClassName={submitButtonClassName}\n\t\t\t\t\t\trenderBack={renderBack}\n\t\t\t\t\t\trenderNext={renderNext}\n\t\t\t\t\t\trenderSubmit={renderSubmit}\n\t\t\t\t\t/>\n\t\t\t\t</form>\n\t\t\t)}\n\t\t</FormContext.Provider>\n\t)\n}\n"],"mappings":"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"}
|
package/dist/spam/constants.js
CHANGED
|
@@ -8,6 +8,12 @@ const DEFAULT_HONEYPOT_FIELD = "website";
|
|
|
8
8
|
/** Reserved `values` entry carrying a captcha token from the client. */
|
|
9
9
|
const CAPTCHA_TOKEN_KEY = "__fb_captcha";
|
|
10
10
|
/**
|
|
11
|
+
* Reserved `values` entry carrying a signed form-context token (see `context/formContext.ts`). Rides
|
|
12
|
+
* alongside the answers like the captcha token, but is verified and stored separately: it is never an
|
|
13
|
+
* answer and must not appear in `values`, the answers view, or `{{*}}` body output.
|
|
14
|
+
*/
|
|
15
|
+
const CONTEXT_KEY = "__fb_ctx";
|
|
16
|
+
/**
|
|
11
17
|
* Reserved `values` entry the honeypot decoy is submitted under. The decoy's DOM input keeps a
|
|
12
18
|
* plausible cosmetic name (e.g. `website`), but the submitted value rides this fixed key so a real
|
|
13
19
|
* field sharing that name is never stripped or mistaken for the decoy.
|
|
@@ -16,6 +22,6 @@ const HONEYPOT_VALUE_KEY = "__fb_hp";
|
|
|
16
22
|
/** `req.context` key under which the spam guard stashes the resolved identity for upload-ownership verification. */
|
|
17
23
|
const IDENTITY_CONTEXT_KEY = "formBuilderSpamIdentity";
|
|
18
24
|
//#endregion
|
|
19
|
-
export { CAPTCHA_TOKEN_KEY, DEFAULT_HONEYPOT_FIELD, HONEYPOT_VALUE_KEY, IDENTITY_CONTEXT_KEY };
|
|
25
|
+
export { CAPTCHA_TOKEN_KEY, CONTEXT_KEY, DEFAULT_HONEYPOT_FIELD, HONEYPOT_VALUE_KEY, IDENTITY_CONTEXT_KEY };
|
|
20
26
|
|
|
21
27
|
//# sourceMappingURL=constants.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.js","names":[],"sources":["../../src/spam/constants.ts"],"sourcesContent":["/**\n * Default honeypot decoy field name. \"website\" is plausible to bots but doesn't trigger Chrome's\n * email-address autofill (unlike names containing \"email\"). Bots fill every input; real users\n * never see the hidden field.\n */\nexport const DEFAULT_HONEYPOT_FIELD = 'website'\n\n/** Reserved `values` entry carrying a captcha token from the client. */\nexport const CAPTCHA_TOKEN_KEY = '__fb_captcha'\n\n/**\n * Reserved `values` entry the honeypot decoy is submitted under. The decoy's DOM input keeps a\n * plausible cosmetic name (e.g. `website`), but the submitted value rides this fixed key so a real\n * field sharing that name is never stripped or mistaken for the decoy.\n */\nexport const HONEYPOT_VALUE_KEY = '__fb_hp'\n\n/** `req.context` key under which the spam guard stashes the resolved identity for upload-ownership verification. */\nexport const IDENTITY_CONTEXT_KEY = 'formBuilderSpamIdentity'\n"],"mappings":";;;;;;AAKA,MAAa,yBAAyB;;AAGtC,MAAa,oBAAoB;;;;;;AAOjC,MAAa,qBAAqB;;AAGlC,MAAa,uBAAuB"}
|
|
1
|
+
{"version":3,"file":"constants.js","names":[],"sources":["../../src/spam/constants.ts"],"sourcesContent":["/**\n * Default honeypot decoy field name. \"website\" is plausible to bots but doesn't trigger Chrome's\n * email-address autofill (unlike names containing \"email\"). Bots fill every input; real users\n * never see the hidden field.\n */\nexport const DEFAULT_HONEYPOT_FIELD = 'website'\n\n/** Reserved `values` entry carrying a captcha token from the client. */\nexport const CAPTCHA_TOKEN_KEY = '__fb_captcha'\n\n/**\n * Reserved `values` entry carrying a signed form-context token (see `context/formContext.ts`). Rides\n * alongside the answers like the captcha token, but is verified and stored separately: it is never an\n * answer and must not appear in `values`, the answers view, or `{{*}}` body output.\n */\nexport const CONTEXT_KEY = '__fb_ctx'\n\n/**\n * Reserved `values` entry the honeypot decoy is submitted under. The decoy's DOM input keeps a\n * plausible cosmetic name (e.g. `website`), but the submitted value rides this fixed key so a real\n * field sharing that name is never stripped or mistaken for the decoy.\n */\nexport const HONEYPOT_VALUE_KEY = '__fb_hp'\n\n/** `req.context` key under which the spam guard stashes the resolved identity for upload-ownership verification. */\nexport const IDENTITY_CONTEXT_KEY = 'formBuilderSpamIdentity'\n"],"mappings":";;;;;;AAKA,MAAa,yBAAyB;;AAGtC,MAAa,oBAAoB;;;;;;AAOjC,MAAa,cAAc;;;;;;AAO3B,MAAa,qBAAqB;;AAGlC,MAAa,uBAAuB"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { keys } from "../translations/keys.js";
|
|
2
|
+
import { asTranslate } from "../translations/server.js";
|
|
3
|
+
import { CONTEXT_KEY } from "../spam/constants.js";
|
|
4
|
+
import { verifyFormContext } from "../context/formContext.js";
|
|
5
|
+
import { APIError } from "payload";
|
|
6
|
+
//#region src/submissions/verifyContext.ts
|
|
7
|
+
/**
|
|
8
|
+
* beforeValidate: pull the reserved signed-context entry out of the submitted values, verify it, and
|
|
9
|
+
* stamp the verified `{ relationTo, value }` on the submission's separate `context` field. Runs
|
|
10
|
+
* independently of the spam config (context must work with spam off) and before `validateSubmission`
|
|
11
|
+
* stores the answers, so the token never reaches `values`, the answers view, or `{{*}}` output.
|
|
12
|
+
*
|
|
13
|
+
* A missing context is normal (the same form on an ordinary page carries none). An invalid one is
|
|
14
|
+
* rejected loudly rather than dropped to absent, so a tampered reference cannot degrade into a send to
|
|
15
|
+
* the statically configured recipients, which would hide the attack. The stored `value` is a string
|
|
16
|
+
* for cross-adapter consistency; the id it references is already public.
|
|
17
|
+
*/
|
|
18
|
+
const verifyContext = () => async ({ data, operation, req }) => {
|
|
19
|
+
if (operation !== "create" || !data) return data;
|
|
20
|
+
const values = Array.isArray(data.values) ? data.values : [];
|
|
21
|
+
const token = values.find((entry) => entry.field === CONTEXT_KEY)?.value;
|
|
22
|
+
data.values = values.filter((entry) => entry.field !== CONTEXT_KEY);
|
|
23
|
+
if (typeof token !== "string" || token.length === 0) return data;
|
|
24
|
+
const verified = verifyFormContext(token, req.payload.secret);
|
|
25
|
+
if (!verified) throw new APIError(asTranslate(req.i18n.t)(keys.contextInvalid), 400);
|
|
26
|
+
data.context = {
|
|
27
|
+
relationTo: verified.relationTo,
|
|
28
|
+
value: String(verified.value)
|
|
29
|
+
};
|
|
30
|
+
return data;
|
|
31
|
+
};
|
|
32
|
+
//#endregion
|
|
33
|
+
export { verifyContext };
|
|
34
|
+
|
|
35
|
+
//# sourceMappingURL=verifyContext.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verifyContext.js","names":[],"sources":["../../src/submissions/verifyContext.ts"],"sourcesContent":["import { APIError, type CollectionBeforeValidateHook } from 'payload'\nimport { verifyFormContext } from '../context/formContext'\nimport { CONTEXT_KEY } from '../spam/constants'\nimport { keys } from '../translations/keys'\nimport { asTranslate } from '../translations/server'\nimport type { SubmissionValue } from './types'\n\n/**\n * beforeValidate: pull the reserved signed-context entry out of the submitted values, verify it, and\n * stamp the verified `{ relationTo, value }` on the submission's separate `context` field. Runs\n * independently of the spam config (context must work with spam off) and before `validateSubmission`\n * stores the answers, so the token never reaches `values`, the answers view, or `{{*}}` output.\n *\n * A missing context is normal (the same form on an ordinary page carries none). An invalid one is\n * rejected loudly rather than dropped to absent, so a tampered reference cannot degrade into a send to\n * the statically configured recipients, which would hide the attack. The stored `value` is a string\n * for cross-adapter consistency; the id it references is already public.\n */\nexport const verifyContext =\n\t(): CollectionBeforeValidateHook =>\n\tasync ({ data, operation, req }) => {\n\t\tif (operation !== 'create' || !data) {\n\t\t\treturn data\n\t\t}\n\t\tconst values = Array.isArray(data.values) ? (data.values as SubmissionValue[]) : []\n\t\tconst token = values.find((entry) => entry.field === CONTEXT_KEY)?.value\n\t\t// Always strip the reserved entry, verified or not, so it can never land in the answers.\n\t\tdata.values = values.filter((entry) => entry.field !== CONTEXT_KEY)\n\t\tif (typeof token !== 'string' || token.length === 0) {\n\t\t\treturn data\n\t\t}\n\t\tconst verified = verifyFormContext(token, req.payload.secret)\n\t\tif (!verified) {\n\t\t\tthrow new APIError(asTranslate(req.i18n.t)(keys.contextInvalid), 400)\n\t\t}\n\t\tdata.context = { relationTo: verified.relationTo, value: String(verified.value) }\n\t\treturn data\n\t}\n"],"mappings":";;;;;;;;;;;;;;;;;AAkBA,MAAa,sBAEZ,OAAO,EAAE,MAAM,WAAW,UAAU;CACnC,IAAI,cAAc,YAAY,CAAC,MAC9B,OAAO;CAER,MAAM,SAAS,MAAM,QAAQ,KAAK,MAAM,IAAK,KAAK,SAA+B,CAAC;CAClF,MAAM,QAAQ,OAAO,MAAM,UAAU,MAAM,UAAU,WAAW,GAAG;CAEnE,KAAK,SAAS,OAAO,QAAQ,UAAU,MAAM,UAAU,WAAW;CAClE,IAAI,OAAO,UAAU,YAAY,MAAM,WAAW,GACjD,OAAO;CAER,MAAM,WAAW,kBAAkB,OAAO,IAAI,QAAQ,MAAM;CAC5D,IAAI,CAAC,UACJ,MAAM,IAAI,SAAS,YAAY,IAAI,KAAK,CAAC,EAAE,KAAK,cAAc,GAAG,GAAG;CAErE,KAAK,UAAU;EAAE,YAAY,SAAS;EAAY,OAAO,OAAO,SAAS,KAAK;CAAE;CAChF,OAAO;AACR"}
|
package/dist/translations/de.js
CHANGED
|
@@ -132,6 +132,7 @@ const de = {
|
|
|
132
132
|
[keys.actionConfigReplyTo]: "Antwort an",
|
|
133
133
|
[keys.recipientsGroupDepartments]: "Abteilungen",
|
|
134
134
|
[keys.recipientsGroupFields]: "Formularfelder",
|
|
135
|
+
[keys.recipientsGroupSources]: "Quellen",
|
|
135
136
|
[keys.validationRecipientInvalid]: "Gib eine gültige E-Mail-Adresse ein.",
|
|
136
137
|
[keys.validationRecipientUnknownField]: "Verweist auf ein nicht mehr vorhandenes Feld.",
|
|
137
138
|
[keys.validationRecipientNotAllowed]: "Dieser Empfänger steht nicht auf der zulässigen Liste.",
|
|
@@ -216,10 +217,12 @@ const de = {
|
|
|
216
217
|
[keys.spamRateLimited]: "Du hast zu viele Anfragen gesendet. Bitte versuche es später erneut.",
|
|
217
218
|
[keys.spamRejected]: "Deine Übermittlung konnte nicht verarbeitet werden.",
|
|
218
219
|
[keys.spamCaptchaFailed]: "Captcha-Überprüfung fehlgeschlagen. Bitte versuche es erneut.",
|
|
220
|
+
[keys.contextInvalid]: "Dieses Formular konnte nicht verifiziert werden. Bitte lade die Seite neu und versuche es erneut.",
|
|
219
221
|
[keys.collectionFormSingular]: "Formular",
|
|
220
222
|
[keys.collectionFormPlural]: "Formulare",
|
|
221
223
|
[keys.collectionSubmissionSingular]: "Übermittlung",
|
|
222
224
|
[keys.collectionSubmissionPlural]: "Übermittlungen",
|
|
225
|
+
[keys.submissionContext]: "Kontext",
|
|
223
226
|
[keys.statusComplete]: "Vollständig",
|
|
224
227
|
[keys.statusPartial]: "Unvollständig",
|
|
225
228
|
[keys.fieldTypeRepeater]: "Wiederholungsfeld",
|
|
@@ -285,6 +288,7 @@ const de = {
|
|
|
285
288
|
[keys.formSubmit]: "Absenden",
|
|
286
289
|
[keys.formMultistep]: "Mehrstufig",
|
|
287
290
|
[keys.formPollEnabled]: "Umfrage",
|
|
291
|
+
[keys.formPersistSubmissions]: "Übermittlungen speichern",
|
|
288
292
|
[keys.formClose]: "Schließen",
|
|
289
293
|
[keys.formSuccess]: "Vielen Dank.",
|
|
290
294
|
[keys.formSubmitFailed]: "Übermittlung fehlgeschlagen",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"de.js","names":[],"sources":["../../src/translations/de.ts"],"sourcesContent":["import { keys, type TranslationKey } from './keys'\n\n/**\n * German values, keyed by the typed constants in `keys.ts` so the two stay in\n * lockstep. The `Record<TranslationKey, string>` annotation makes a missing or\n * unknown key a type error. `translations/index.ts` nests these for Payload.\n */\nexport const de: Record<TranslationKey, string> = {\n\t[keys.fieldTitle]: 'Titel',\n\t[keys.fieldTypeText]: 'Text',\n\t[keys.fieldTypeTextarea]: 'Textarea',\n\t[keys.fieldTypeEmail]: 'E-Mail',\n\t[keys.fieldTypeNumber]: 'Zahl',\n\t[keys.fieldTypeSelect]: 'Auswahl',\n\t[keys.fieldTypeCountry]: 'Land',\n\t[keys.fieldTypeState]: 'Bundesstaat',\n\t[keys.fieldTypeCheckbox]: 'Checkbox',\n\t[keys.fieldTypeDate]: 'Datum',\n\t[keys.configOptions]: 'Optionen',\n\t[keys.configOption]: 'Option',\n\t[keys.configOptionLabel]: 'Bezeichnung',\n\t[keys.configOptionValue]: 'Wert',\n\t[keys.validationRequired]: 'Dieses Feld ist erforderlich',\n\t[keys.validationEmail]: 'Gib eine gültige E-Mail-Adresse ein',\n\t[keys.validationNumber]: 'Gib eine gültige Zahl ein',\n\t[keys.validationDate]: 'Gib ein gültiges Datum ein',\n\t[keys.validationSelect]: 'Wähle eine gültige Option',\n\t[keys.validationCountry]: 'Wähle ein gültiges Land',\n\t[keys.validationState]: 'Wähle einen gültigen Bundesstaat',\n\t[keys.validationRegexPattern]: 'Gib einen gültigen regulären Ausdruck ein',\n\t[keys.validationRegexFlags]:\n\t\t'Gib gültige Flags für reguläre Ausdrücke ein, zum Beispiel i oder gi',\n\t[keys.validationEmailFieldUnknown]: 'Wähle ein bestehendes E-Mail-Feld dieses Formulars',\n\t[keys.validationResultsFieldUnknown]: 'Wähle ein geeignetes Auswahlfeld dieses Formulars',\n\t[keys.formatYes]: 'Ja',\n\t[keys.formatNo]: 'Nein',\n\t[keys.configName]: 'Name',\n\t[keys.configLabel]: 'Bezeichnung',\n\t[keys.configRequired]: 'Erforderlich',\n\t[keys.configWidth]: 'Breite',\n\t[keys.configPlaceholder]: 'Platzhalter',\n\t[keys.configDescription]: 'Beschreibung',\n\t[keys.configVisibleWhen]: 'Dieses Feld anzeigen, wenn',\n\t[keys.configValidateWhen]: 'Dieses Feld nur validieren, wenn',\n\t[keys.submissionAnswers]: 'Antworten',\n\t[keys.submissionNoAnswers]: 'Keine Antworten',\n\t[keys.ruleMinLength]: 'Minimale Länge',\n\t[keys.ruleMaxLength]: 'Maximale Länge',\n\t[keys.ruleMin]: 'Minimum',\n\t[keys.ruleMax]: 'Maximum',\n\t[keys.ruleMinDate]: 'Frühestes Datum',\n\t[keys.ruleMaxDate]: 'Spätestes Datum',\n\t[keys.rulePattern]: 'Muster',\n\t[keys.ruleEmail]: 'E-Mail',\n\t[keys.ruleUrl]: 'URL',\n\t[keys.ruleOneOf]: 'Wert aus Liste',\n\t[keys.ruleMatchesField]: 'Stimmt mit Feld überein',\n\t[keys.ruleNotAlreadySubmitted]: 'Noch nicht übermittelt',\n\t[keys.ruleMinLengthMessage]: 'Muss mindestens {min} Zeichen lang sein',\n\t[keys.ruleMaxLengthMessage]: 'Darf höchstens {max} Zeichen lang sein',\n\t[keys.ruleMinMessage]: 'Muss mindestens {min} betragen',\n\t[keys.ruleMaxMessage]: 'Darf höchstens {max} betragen',\n\t[keys.ruleMinDateMessage]: 'Muss am oder nach dem {min} liegen',\n\t[keys.ruleMaxDateMessage]: 'Muss am oder vor dem {max} liegen',\n\t[keys.rulePatternMessage]: 'Ungültiges Format',\n\t[keys.ruleEmailMessage]: 'Gib eine gültige E-Mail-Adresse ein',\n\t[keys.ruleUrlMessage]: 'Gib eine gültige URL ein',\n\t[keys.ruleOneOfMessage]: 'Wähle einen zulässigen Wert',\n\t[keys.ruleMatchesFieldMessage]: 'Stimmt nicht überein',\n\t[keys.ruleNotAlreadySubmittedMessage]: 'Dieser Wert wurde bereits übermittelt',\n\t[keys.ruleMinLengthDescription]:\n\t\t'Schlägt fehl, wenn der eingegebene Text kürzer als die Mindestanzahl an Zeichen ist.',\n\t[keys.ruleMaxLengthDescription]:\n\t\t'Schlägt fehl, wenn der eingegebene Text länger als die maximale Anzahl an Zeichen ist.',\n\t[keys.ruleMinDescription]: 'Schlägt fehl, wenn die eingegebene Zahl unter dem Minimum liegt.',\n\t[keys.ruleMaxDescription]: 'Schlägt fehl, wenn die eingegebene Zahl über dem Maximum liegt.',\n\t[keys.ruleMinDateDescription]:\n\t\t'Schlägt fehl, wenn das gewählte Datum vor dem frühesten Datum liegt.',\n\t[keys.ruleMaxDateDescription]:\n\t\t'Schlägt fehl, wenn das gewählte Datum nach dem spätesten Datum liegt.',\n\t[keys.rulePatternDescription]:\n\t\t'Schlägt fehl, wenn der eingegebene Text nicht zum regulären Ausdruck passt.',\n\t[keys.ruleEmailDescription]:\n\t\t'Schlägt fehl, wenn der eingegebene Wert keine gültige E-Mail-Adresse ist.',\n\t[keys.ruleUrlDescription]:\n\t\t'Schlägt fehl, wenn der eingegebene Wert keine gültige http- oder https-URL ist.',\n\t[keys.ruleOneOfDescription]:\n\t\t'Schlägt fehl, wenn der eingegebene Wert keiner der von dir angegebenen zulässigen Werte ist.',\n\t[keys.ruleMatchesFieldDescription]:\n\t\t'Schlägt fehl, wenn der Wert dieses Feldes nicht dem gewählten Feld entspricht. Nutze es für E-Mail- oder Passwort-Bestätigung.',\n\t[keys.ruleNotAlreadySubmittedDescription]:\n\t\t'Schlägt fehl, wenn genau dieser Wert bereits an dieses Formular übermittelt wurde (serverseitig geprüft).',\n\t[keys.ruleFieldTargetInvalid]:\n\t\t'Das ausgewählte Feld existiert nicht mehr. Wähle ein gültiges Feld.',\n\t[keys.ruleParamMin]: 'Minimum',\n\t[keys.ruleParamMax]: 'Maximum',\n\t[keys.ruleParamMinDate]: 'Frühestes Datum (JJJJ-MM-TT)',\n\t[keys.ruleParamMaxDate]: 'Spätestes Datum (JJJJ-MM-TT)',\n\t[keys.ruleParamPattern]: 'Muster',\n\t[keys.ruleParamFlags]: 'Flags',\n\t[keys.ruleParamValues]: 'Zulässige Werte',\n\t[keys.ruleParamField]: 'Feldname',\n\t[keys.validationsLabel]: 'Validierungsregeln',\n\t[keys.validationMessageLabel]: 'Benutzerdefinierte Nachricht',\n\t[keys.conditionAddCondition]: 'Bedingung hinzufügen',\n\t[keys.conditionAddOr]: '\"Oder\"-Gruppe hinzufügen',\n\t[keys.conditionAnd]: 'Und',\n\t[keys.conditionOr]: 'Oder',\n\t[keys.conditionRemove]: 'Entfernen',\n\t[keys.conditionNoFields]:\n\t\t'Füge diesem Formular benannte Felder hinzu, um eine Bedingung zu erstellen.',\n\t[keys.conditionEmpty]: 'Keine Bedingungen. Dieses Feld wird immer angezeigt.',\n\t[keys.conditionSelectField]: 'Feld auswählen',\n\t[keys.conditionTrue]: 'Wahr',\n\t[keys.conditionFalse]: 'Falsch',\n\t[keys.configHidden]: 'Ausgeblendet (wird erfasst, aber nicht angezeigt)',\n\t[keys.tabFields]: 'Felder',\n\t[keys.tabFlow]: 'Ablauf',\n\t[keys.tabActions]: 'Aktionen',\n\t[keys.tabField]: 'Feld',\n\t[keys.tabValidation]: 'Validierung',\n\t[keys.tabAdvanced]: 'Erweitert',\n\t[keys.fieldTypeCalculation]: 'Berechnung',\n\t[keys.configExpression]: 'Ausdruck (JSON)',\n\t[keys.configExpressionDescription]:\n\t\t'Ausdrucksbaum aus Knoten {\"type\":\"lit\"|\"ref\"|\"op\"|\"neg\"|\"fn\"|\"weight\"}. Beispiel: {\"type\":\"op\",\"op\":\"+\",\"left\":{\"type\":\"ref\",\"field\":\"qty\"},\"right\":{\"type\":\"lit\",\"value\":10}}',\n\t[keys.configCalcDisplay]: 'Berechneten Wert anzeigen',\n\t[keys.validationCalcExpressionInvalid]: 'Gib einen gültigen Berechnungsausdruck ein',\n\t[keys.presentationPage]: 'Seite',\n\t[keys.presentationModal]: 'Modal',\n\t[keys.presentationDrawer]: 'Seitenpanel',\n\t[keys.presentationInline]: 'Inline',\n\t[keys.actionEmailTeam]: 'E-Mail ans Team',\n\t[keys.actionConfirmation]: 'Bestätigungs-E-Mail',\n\t[keys.actionSignedWebhook]: 'Signierter Webhook',\n\t[keys.actionConfigTo]: 'An',\n\t[keys.actionConfigSubject]: 'Betreff',\n\t[keys.actionConfigBody]: 'Nachrichtentext',\n\t[keys.actionConfigBodyDescription]:\n\t\t'Unterstützt {{ fieldName|fallback }}-Platzhalter, {{*}} für alle Antworten als Zeilen und {{*:table}} für alle Antworten als Tabelle.',\n\t[keys.actionConfigToField]: 'Name des E-Mail-Feldes',\n\t[keys.actionConfigToFieldDescription]:\n\t\t'Das E-Mail-Feld dieses Formulars, an das die Bestätigung gesendet wird.',\n\t[keys.actionConfigFrom]: 'Von',\n\t[keys.actionConfigFromDescription]:\n\t\t'Absenderadresse für diese Aktion. Leer lassen, um den Standard des E-Mail-Adapters zu verwenden.',\n\t[keys.actionConfigCc]: 'CC',\n\t[keys.actionConfigBcc]: 'BCC',\n\t[keys.actionConfigReplyTo]: 'Antwort an',\n\t[keys.recipientsGroupDepartments]: 'Abteilungen',\n\t[keys.recipientsGroupFields]: 'Formularfelder',\n\t[keys.validationRecipientInvalid]: 'Gib eine gültige E-Mail-Adresse ein.',\n\t[keys.validationRecipientUnknownField]: 'Verweist auf ein nicht mehr vorhandenes Feld.',\n\t[keys.validationRecipientNotAllowed]: 'Dieser Empfänger steht nicht auf der zulässigen Liste.',\n\t[keys.validationRecipientOptionsUnavailable]:\n\t\t'Empfängeroptionen sind derzeit nicht verfügbar. Bitte versuche es später erneut.',\n\t[keys.validationFromUnknown]: 'Wähle eine der konfigurierten Absenderadressen',\n\t[keys.validationFromUnavailable]:\n\t\t'Absenderadressen sind derzeit nicht verfügbar. Bitte versuche es später erneut.',\n\t[keys.actionConfigUrl]: 'URL',\n\t[keys.actionConfigUrlDescription]:\n\t\t'Der Endpunkt, der für jede Übermittlung einen signierten JSON-POST erhält.',\n\t[keys.actionConfigSecret]: 'Geheimer Schlüssel',\n\t[keys.actionConfigSecretDescription]:\n\t\t'HMAC-Schlüssel für den X-Form-Signature-Header, der mit dem Empfänger geteilt wird.',\n\t[keys.validationUrlInvalid]: 'Gib eine gültige http- oder https-URL ein',\n\t[keys.configActions]: 'Aktionen',\n\t[keys.fieldTypeConsent]: 'Einwilligung',\n\t[keys.consentConfigSource]: 'Quelle',\n\t[keys.consentConfigSourceDescription]:\n\t\t'Die Erklärung, der Besucher zustimmen. Wortlaut und Rechtsseite gehören zur Quelle: eine Änderung dort gilt für jedes Formular, das sie nutzt.',\n\t[keys.consentSourcesField]: 'Einwilligungsquellen',\n\t[keys.consentSourcesFieldDescription]:\n\t\t'Erklärungen, die Formulare in Einwilligungsfeldern verwenden können',\n\t[keys.consentSourceSingular]: 'Einwilligungsquelle',\n\t[keys.consentSourcePlural]: 'Einwilligungsquellen',\n\t[keys.consentSourceLabel]: 'Name',\n\t[keys.consentSourceStatement]: 'Erklärung',\n\t[keys.consentSourcePage]: 'Erklärungsquelle',\n\t[keys.consentSourcePageDescription]:\n\t\t'Muss gesetzt sein, wenn Formulareinsendungen einen Verweis auf deine Richtlinie speichern sollen.',\n\t[keys.consentSourcesUnavailable]:\n\t\t'Einwilligungsquellen sind nicht verfügbar. Versuche es gleich noch einmal.',\n\t[keys.resultsResponses]: 'Antworten',\n\t[keys.resultsNoResponses]: 'Noch keine Antworten',\n\t[keys.resultsTruncated]: 'Zeigt eine Stichprobe der Antworten',\n\t[keys.pollGroup]: 'Umfrage',\n\t[keys.pollResultsField]: 'Abstimmungsfeld',\n\t[keys.pollResultsFieldDescription]:\n\t\t'Das Auswahlfeld, dessen Antworten als Stimmen gezählt werden. Wird automatisch gewählt, wenn dein Formular genau ein Auswahlfeld hat. Verwende ein Auswahlfeld, niemals ein Freitext- oder personenbezogenes Feld.',\n\t[keys.pollVoteFieldChoose]: 'Wähle das Feld, dessen Antworten als Stimmen zählen.',\n\t[keys.pollVoteFieldMissing]: 'Füge ein Auswahlfeld als Abstimmungsfrage hinzu.',\n\t[keys.pollResultsVisibility]: 'Sichtbarkeit der Ergebnisse',\n\t[keys.pollVisibilityAfterVote]: 'Nach der Abstimmung',\n\t[keys.pollVisibilityAfterClose]: 'Nach Ende der Umfrage',\n\t[keys.pollClosesAt]: 'Endet am',\n\t[keys.pollClosed]: 'Diese Umfrage ist beendet.',\n\t[keys.pollResultsAfterClose]: 'Die Ergebnisse werden nach Ende der Umfrage angezeigt.',\n\t[keys.pollOptionSource]: 'Optionsquelle',\n\t[keys.pollOptionSourceDescription]:\n\t\t'Befüllt die Auswahlmöglichkeiten des Ergebnisfeldes mit App-Daten anstelle manuell erstellter Optionen.',\n\t[keys.pollSourceConfig]: 'Quelleinstellungen',\n\t[keys.pollOutcome]: 'Ergebnis',\n\t[keys.pollType]: 'Ergebnistyp',\n\t[keys.pollTypeDescription]: 'Wie die Gewinneroption bestimmt wird, sobald die Umfrage endet.',\n\t[keys.pollTypeManual]: 'Gewinner manuell festlegen',\n\t[keys.pollTypeMostVoted]: 'Meistgewählte Option gewinnt',\n\t[keys.pollTypeSource]: 'Gewinner aus der Optionsquelle',\n\t[keys.pollCloseButton]: 'Umfrage jetzt beenden',\n\t[keys.pollReopenButton]: 'Umfrage wieder öffnen',\n\t[keys.pollCloseHintManual]: 'Beim Beenden wird der ausgewählte Gewinner als Ergebnis erfasst.',\n\t[keys.pollCloseHintMostVoted]: 'Beim Beenden wird die meistgewählte Option zum Gewinner.',\n\t[keys.pollCloseHintSource]: 'Beim Beenden wird der Gewinner aus der Optionsquelle ermittelt.',\n\t[keys.pollReopenHint]:\n\t\t'Beim Wiederöffnen wird der erfasste Gewinner entfernt und es kann erneut abgestimmt werden.',\n\t[keys.pollCloseNeedsWinner]: 'Wähle zuerst einen Siegerwert.',\n\t[keys.pollCloseManualNoWinner]: 'Lege einen Gewinner fest, bevor du die Umfrage beendest.',\n\t[keys.pollWinningValue]: 'Siegerwert',\n\t[keys.pollWinningValueDescription]:\n\t\t'Wähle die Gewinneroption, sobald das Ergebnis feststeht. Beim Speichern wird der Entscheidungszeitpunkt erfasst; leeren öffnet das Ergebnis wieder.',\n\t[keys.pollResolvedAt]: 'Entschieden am',\n\t[keys.validationWinningValueUnknown]: 'Der Siegerwert muss eine der Umfrageoptionen sein.',\n\t[keys.validationWinningValueDisabled]: 'Aktiviere die Umfrage, bevor ein Ergebnis erfasst wird.',\n\t[keys.endpointOptionsLoading]: 'Optionen werden geladen...',\n\t[keys.endpointOptionsError]: 'Optionen konnten nicht geladen werden.',\n\t[keys.pollOptionsUnavailable]:\n\t\t'Umfrageoptionen sind derzeit nicht verfügbar. Bitte versuche es später erneut.',\n\t[keys.pollFinalResult]: 'Endergebnis',\n\t[keys.pollResultsError]: 'Ergebnisse konnten nicht geladen werden.',\n\t[keys.resultsWinner]: 'Gewinner',\n\t[keys.validationFileMissing]: 'Datei hochladen',\n\t[keys.validationFileMimeType]: 'Dateityp nicht erlaubt',\n\t[keys.validationFileTooLarge]: 'Datei ist zu groß',\n\t[keys.fieldTypeFile]: 'Datei-Upload',\n\t[keys.fileConfigMimeTypes]: 'Erlaubte Dateitypen',\n\t[keys.fileConfigMaxSize]: 'Maximale Größe (Bytes)',\n\t[keys.fileConfigMaxSizeDescription]: 'Dateien, die größer sind, werden abgelehnt.',\n\t[keys.fileTooLarge]: 'Datei ist zu groß (max. {max})',\n\t[keys.fileUploadMisconfigured]: 'Datei-Uploads sind für dieses Formular nicht konfiguriert',\n\t[keys.fileHintAccepted]: 'Akzeptiert: {types}',\n\t[keys.fileHintMaxSize]: 'Max. Größe: {max}',\n\t[keys.fileUploaded]: 'Hochgeladene Datei',\n\t[keys.fileUploading]: 'Wird hochgeladen',\n\t[keys.fileUploadFailed]: 'Upload fehlgeschlagen',\n\t[keys.fileRemove]: 'Entfernen',\n\t[keys.spamRateLimited]: 'Du hast zu viele Anfragen gesendet. Bitte versuche es später erneut.',\n\t[keys.spamRejected]: 'Deine Übermittlung konnte nicht verarbeitet werden.',\n\t[keys.spamCaptchaFailed]: 'Captcha-Überprüfung fehlgeschlagen. Bitte versuche es erneut.',\n\t[keys.collectionFormSingular]: 'Formular',\n\t[keys.collectionFormPlural]: 'Formulare',\n\t[keys.collectionSubmissionSingular]: 'Übermittlung',\n\t[keys.collectionSubmissionPlural]: 'Übermittlungen',\n\t[keys.statusComplete]: 'Vollständig',\n\t[keys.statusPartial]: 'Unvollständig',\n\t[keys.fieldTypeRepeater]: 'Wiederholungsfeld',\n\t[keys.configMinRows]: 'Minimale Zeilenanzahl',\n\t[keys.configMaxRows]: 'Maximale Zeilenanzahl',\n\t[keys.configAddLabel]: 'Beschriftung der Schaltfläche zum Hinzufügen',\n\t[keys.configSubFields]: 'Unterfelder',\n\t[keys.validationRepeaterMin]: 'Füge mindestens {min} Zeile(n) hinzu',\n\t[keys.validationRepeaterMax]: 'Entferne Zeilen, um {max} nicht zu überschreiten',\n\t[keys.repeaterAddRow]: 'Zeile hinzufügen',\n\t[keys.repeaterRemoveRow]: 'Entfernen',\n\t[keys.repeaterRow]: 'Zeile {n}',\n\t[keys.repeaterRowCount]: '{count} Zeile(n)',\n\t[keys.submissionConsent]: 'Einwilligung',\n\t[keys.submissionDetails]: 'Details zur Übermittlung',\n\t[keys.submissionConsentAgreed]: 'Zugestimmt',\n\t[keys.submissionConsentDeclined]: 'Abgelehnt',\n\t[keys.submissionMetaLocale]: 'Sprache',\n\t[keys.submissionMetaReceivedAt]: 'Empfangen am',\n\t[keys.submissionMetaIp]: 'IP-Adresse',\n\t[keys.submissionMetaUserAgent]: 'User-Agent',\n\t[keys.submissionMetaCaptcha]: 'Captcha',\n\t[keys.flowDescription]:\n\t\t'Nur für mehrstufige Formulare nötig: Felder zu Schritten gruppieren und den Ablauf dazwischen festlegen. Leer lassen, um das Formular als einzelne Seite anzuzeigen.',\n\t[keys.flowStepFallbackTitle]: 'Schritt {n}',\n\t[keys.flowFieldInStep]: 'in {step}',\n\t[keys.flowUnassigned]: 'In keinem Schritt',\n\t[keys.flowAssignToStep]: 'Zu Schritt hinzufügen',\n\t[keys.flowNextSequential]: 'Nächster Schritt in der Reihenfolge',\n\t[keys.flowNextTerminal]: 'Ende des Formulars',\n\t[keys.flowFields]: 'Felder',\n\t[keys.flowDefaultNext]: 'Standardmäßig weiter zu',\n\t[keys.flowConditionalTransitions]: 'Bedingte Übergänge',\n\t[keys.flowStepTitleLabel]: 'Titel',\n\t[keys.flowSelectStepPlaceholder]: 'Schritt auswählen…',\n\t[keys.flowMoveTransitionUp]: 'Übergang nach oben verschieben',\n\t[keys.flowMoveTransitionDown]: 'Übergang nach unten verschieben',\n\t[keys.flowRemoveTransition]: 'Übergang entfernen',\n\t[keys.flowAddAbove]: 'Oberhalb hinzufügen',\n\t[keys.flowAddBelow]: 'Unterhalb hinzufügen',\n\t[keys.flowGoTo]: 'gehe zu',\n\t[keys.flowWhen]: 'wenn',\n\t[keys.flowNoFields]: 'Noch keine Felder im Formular definiert.',\n\t[keys.flowFirstMatchWins]: '(erste Übereinstimmung gewinnt)',\n\t[keys.flowAddTransition]: 'Übergang hinzufügen',\n\t[keys.flowNoSteps]:\n\t\t'Keine Schritte definiert. Füge mindestens zwei Schritte hinzu, um die mehrseitige Ablaufsteuerung zu aktivieren.',\n\t[keys.flowFallbackTitle]: 'Ablauf',\n\t[keys.fieldTypeMessage]: 'Nachricht',\n\t[keys.configContent]: 'Inhalt',\n\t[keys.tabResponse]: 'Antwort',\n\t[keys.responseType]: 'Nach dem Absenden',\n\t[keys.responseTypeMessage]: 'Eine Nachricht anzeigen',\n\t[keys.responseTypeRedirect]: 'Zu einer URL weiterleiten',\n\t[keys.responseMessage]: 'Nachricht',\n\t[keys.responseRedirect]: 'Weiterleitung',\n\t[keys.responseUrl]: 'URL',\n\t[keys.responseRedirectReference]: 'Dokument',\n\t[keys.responseRedirectReferenceDescription]:\n\t\t'Zu einem internen Dokument statt zu einer URL weiterleiten',\n\t[keys.buttonsSubmitLabel]: 'Beschriftung der Absenden-Schaltfläche',\n\t[keys.buttonsNextLabel]: 'Beschriftung der Weiter-Schaltfläche',\n\t[keys.buttonsPrevLabel]: 'Beschriftung der Zurück-Schaltfläche',\n\t[keys.formBack]: 'Zurück',\n\t[keys.formNext]: 'Weiter',\n\t[keys.formSubmit]: 'Absenden',\n\t[keys.formMultistep]: 'Mehrstufig',\n\t[keys.formPollEnabled]: 'Umfrage',\n\t[keys.formClose]: 'Schließen',\n\t[keys.formSuccess]: 'Vielen Dank.',\n\t[keys.formSubmitFailed]: 'Übermittlung fehlgeschlagen',\n\t[keys.formStepStatus]: 'Schritt {current} von {total}',\n\t[keys.formStepInvalid]: 'Bitte korrigieren Sie die markierten Felder, um fortzufahren.',\n\t[keys.cellStepCountOne]: '{{count}} Schritt',\n\t[keys.cellStepCountOther]: '{{count}} Schritte',\n\t[keys.cellFieldCountOne]: '{{count}} Feld',\n\t[keys.cellFieldCountOther]: '{{count}} Felder',\n\t[keys.departmentsField]: 'Abteilungs-E-Mails',\n\t[keys.departmentsFieldDescription]:\n\t\t'Adressen, an die ein Formular Einsendungen weiterleiten kann, jeweils mit Bezeichnung.',\n\t[keys.departmentSingular]: 'Abteilungs-E-Mail',\n\t[keys.departmentPlural]: 'Abteilungs-E-Mails',\n\t[keys.departmentLabel]: 'Bezeichnung',\n\t[keys.departmentEmail]: 'E-Mail',\n\t[keys.departmentAddRow]: 'E-Mail hinzufügen',\n\t[keys.departmentRemoveRow]: 'E-Mail entfernen',\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"de.js","names":[],"sources":["../../src/translations/de.ts"],"sourcesContent":["import { keys, type TranslationKey } from './keys'\n\n/**\n * German values, keyed by the typed constants in `keys.ts` so the two stay in\n * lockstep. The `Record<TranslationKey, string>` annotation makes a missing or\n * unknown key a type error. `translations/index.ts` nests these for Payload.\n */\nexport const de: Record<TranslationKey, string> = {\n\t[keys.fieldTitle]: 'Titel',\n\t[keys.fieldTypeText]: 'Text',\n\t[keys.fieldTypeTextarea]: 'Textarea',\n\t[keys.fieldTypeEmail]: 'E-Mail',\n\t[keys.fieldTypeNumber]: 'Zahl',\n\t[keys.fieldTypeSelect]: 'Auswahl',\n\t[keys.fieldTypeCountry]: 'Land',\n\t[keys.fieldTypeState]: 'Bundesstaat',\n\t[keys.fieldTypeCheckbox]: 'Checkbox',\n\t[keys.fieldTypeDate]: 'Datum',\n\t[keys.configOptions]: 'Optionen',\n\t[keys.configOption]: 'Option',\n\t[keys.configOptionLabel]: 'Bezeichnung',\n\t[keys.configOptionValue]: 'Wert',\n\t[keys.validationRequired]: 'Dieses Feld ist erforderlich',\n\t[keys.validationEmail]: 'Gib eine gültige E-Mail-Adresse ein',\n\t[keys.validationNumber]: 'Gib eine gültige Zahl ein',\n\t[keys.validationDate]: 'Gib ein gültiges Datum ein',\n\t[keys.validationSelect]: 'Wähle eine gültige Option',\n\t[keys.validationCountry]: 'Wähle ein gültiges Land',\n\t[keys.validationState]: 'Wähle einen gültigen Bundesstaat',\n\t[keys.validationRegexPattern]: 'Gib einen gültigen regulären Ausdruck ein',\n\t[keys.validationRegexFlags]:\n\t\t'Gib gültige Flags für reguläre Ausdrücke ein, zum Beispiel i oder gi',\n\t[keys.validationEmailFieldUnknown]: 'Wähle ein bestehendes E-Mail-Feld dieses Formulars',\n\t[keys.validationResultsFieldUnknown]: 'Wähle ein geeignetes Auswahlfeld dieses Formulars',\n\t[keys.formatYes]: 'Ja',\n\t[keys.formatNo]: 'Nein',\n\t[keys.configName]: 'Name',\n\t[keys.configLabel]: 'Bezeichnung',\n\t[keys.configRequired]: 'Erforderlich',\n\t[keys.configWidth]: 'Breite',\n\t[keys.configPlaceholder]: 'Platzhalter',\n\t[keys.configDescription]: 'Beschreibung',\n\t[keys.configVisibleWhen]: 'Dieses Feld anzeigen, wenn',\n\t[keys.configValidateWhen]: 'Dieses Feld nur validieren, wenn',\n\t[keys.submissionAnswers]: 'Antworten',\n\t[keys.submissionNoAnswers]: 'Keine Antworten',\n\t[keys.ruleMinLength]: 'Minimale Länge',\n\t[keys.ruleMaxLength]: 'Maximale Länge',\n\t[keys.ruleMin]: 'Minimum',\n\t[keys.ruleMax]: 'Maximum',\n\t[keys.ruleMinDate]: 'Frühestes Datum',\n\t[keys.ruleMaxDate]: 'Spätestes Datum',\n\t[keys.rulePattern]: 'Muster',\n\t[keys.ruleEmail]: 'E-Mail',\n\t[keys.ruleUrl]: 'URL',\n\t[keys.ruleOneOf]: 'Wert aus Liste',\n\t[keys.ruleMatchesField]: 'Stimmt mit Feld überein',\n\t[keys.ruleNotAlreadySubmitted]: 'Noch nicht übermittelt',\n\t[keys.ruleMinLengthMessage]: 'Muss mindestens {min} Zeichen lang sein',\n\t[keys.ruleMaxLengthMessage]: 'Darf höchstens {max} Zeichen lang sein',\n\t[keys.ruleMinMessage]: 'Muss mindestens {min} betragen',\n\t[keys.ruleMaxMessage]: 'Darf höchstens {max} betragen',\n\t[keys.ruleMinDateMessage]: 'Muss am oder nach dem {min} liegen',\n\t[keys.ruleMaxDateMessage]: 'Muss am oder vor dem {max} liegen',\n\t[keys.rulePatternMessage]: 'Ungültiges Format',\n\t[keys.ruleEmailMessage]: 'Gib eine gültige E-Mail-Adresse ein',\n\t[keys.ruleUrlMessage]: 'Gib eine gültige URL ein',\n\t[keys.ruleOneOfMessage]: 'Wähle einen zulässigen Wert',\n\t[keys.ruleMatchesFieldMessage]: 'Stimmt nicht überein',\n\t[keys.ruleNotAlreadySubmittedMessage]: 'Dieser Wert wurde bereits übermittelt',\n\t[keys.ruleMinLengthDescription]:\n\t\t'Schlägt fehl, wenn der eingegebene Text kürzer als die Mindestanzahl an Zeichen ist.',\n\t[keys.ruleMaxLengthDescription]:\n\t\t'Schlägt fehl, wenn der eingegebene Text länger als die maximale Anzahl an Zeichen ist.',\n\t[keys.ruleMinDescription]: 'Schlägt fehl, wenn die eingegebene Zahl unter dem Minimum liegt.',\n\t[keys.ruleMaxDescription]: 'Schlägt fehl, wenn die eingegebene Zahl über dem Maximum liegt.',\n\t[keys.ruleMinDateDescription]:\n\t\t'Schlägt fehl, wenn das gewählte Datum vor dem frühesten Datum liegt.',\n\t[keys.ruleMaxDateDescription]:\n\t\t'Schlägt fehl, wenn das gewählte Datum nach dem spätesten Datum liegt.',\n\t[keys.rulePatternDescription]:\n\t\t'Schlägt fehl, wenn der eingegebene Text nicht zum regulären Ausdruck passt.',\n\t[keys.ruleEmailDescription]:\n\t\t'Schlägt fehl, wenn der eingegebene Wert keine gültige E-Mail-Adresse ist.',\n\t[keys.ruleUrlDescription]:\n\t\t'Schlägt fehl, wenn der eingegebene Wert keine gültige http- oder https-URL ist.',\n\t[keys.ruleOneOfDescription]:\n\t\t'Schlägt fehl, wenn der eingegebene Wert keiner der von dir angegebenen zulässigen Werte ist.',\n\t[keys.ruleMatchesFieldDescription]:\n\t\t'Schlägt fehl, wenn der Wert dieses Feldes nicht dem gewählten Feld entspricht. Nutze es für E-Mail- oder Passwort-Bestätigung.',\n\t[keys.ruleNotAlreadySubmittedDescription]:\n\t\t'Schlägt fehl, wenn genau dieser Wert bereits an dieses Formular übermittelt wurde (serverseitig geprüft).',\n\t[keys.ruleFieldTargetInvalid]:\n\t\t'Das ausgewählte Feld existiert nicht mehr. Wähle ein gültiges Feld.',\n\t[keys.ruleParamMin]: 'Minimum',\n\t[keys.ruleParamMax]: 'Maximum',\n\t[keys.ruleParamMinDate]: 'Frühestes Datum (JJJJ-MM-TT)',\n\t[keys.ruleParamMaxDate]: 'Spätestes Datum (JJJJ-MM-TT)',\n\t[keys.ruleParamPattern]: 'Muster',\n\t[keys.ruleParamFlags]: 'Flags',\n\t[keys.ruleParamValues]: 'Zulässige Werte',\n\t[keys.ruleParamField]: 'Feldname',\n\t[keys.validationsLabel]: 'Validierungsregeln',\n\t[keys.validationMessageLabel]: 'Benutzerdefinierte Nachricht',\n\t[keys.conditionAddCondition]: 'Bedingung hinzufügen',\n\t[keys.conditionAddOr]: '\"Oder\"-Gruppe hinzufügen',\n\t[keys.conditionAnd]: 'Und',\n\t[keys.conditionOr]: 'Oder',\n\t[keys.conditionRemove]: 'Entfernen',\n\t[keys.conditionNoFields]:\n\t\t'Füge diesem Formular benannte Felder hinzu, um eine Bedingung zu erstellen.',\n\t[keys.conditionEmpty]: 'Keine Bedingungen. Dieses Feld wird immer angezeigt.',\n\t[keys.conditionSelectField]: 'Feld auswählen',\n\t[keys.conditionTrue]: 'Wahr',\n\t[keys.conditionFalse]: 'Falsch',\n\t[keys.configHidden]: 'Ausgeblendet (wird erfasst, aber nicht angezeigt)',\n\t[keys.tabFields]: 'Felder',\n\t[keys.tabFlow]: 'Ablauf',\n\t[keys.tabActions]: 'Aktionen',\n\t[keys.tabField]: 'Feld',\n\t[keys.tabValidation]: 'Validierung',\n\t[keys.tabAdvanced]: 'Erweitert',\n\t[keys.fieldTypeCalculation]: 'Berechnung',\n\t[keys.configExpression]: 'Ausdruck (JSON)',\n\t[keys.configExpressionDescription]:\n\t\t'Ausdrucksbaum aus Knoten {\"type\":\"lit\"|\"ref\"|\"op\"|\"neg\"|\"fn\"|\"weight\"}. Beispiel: {\"type\":\"op\",\"op\":\"+\",\"left\":{\"type\":\"ref\",\"field\":\"qty\"},\"right\":{\"type\":\"lit\",\"value\":10}}',\n\t[keys.configCalcDisplay]: 'Berechneten Wert anzeigen',\n\t[keys.validationCalcExpressionInvalid]: 'Gib einen gültigen Berechnungsausdruck ein',\n\t[keys.presentationPage]: 'Seite',\n\t[keys.presentationModal]: 'Modal',\n\t[keys.presentationDrawer]: 'Seitenpanel',\n\t[keys.presentationInline]: 'Inline',\n\t[keys.actionEmailTeam]: 'E-Mail ans Team',\n\t[keys.actionConfirmation]: 'Bestätigungs-E-Mail',\n\t[keys.actionSignedWebhook]: 'Signierter Webhook',\n\t[keys.actionConfigTo]: 'An',\n\t[keys.actionConfigSubject]: 'Betreff',\n\t[keys.actionConfigBody]: 'Nachrichtentext',\n\t[keys.actionConfigBodyDescription]:\n\t\t'Unterstützt {{ fieldName|fallback }}-Platzhalter, {{*}} für alle Antworten als Zeilen und {{*:table}} für alle Antworten als Tabelle.',\n\t[keys.actionConfigToField]: 'Name des E-Mail-Feldes',\n\t[keys.actionConfigToFieldDescription]:\n\t\t'Das E-Mail-Feld dieses Formulars, an das die Bestätigung gesendet wird.',\n\t[keys.actionConfigFrom]: 'Von',\n\t[keys.actionConfigFromDescription]:\n\t\t'Absenderadresse für diese Aktion. Leer lassen, um den Standard des E-Mail-Adapters zu verwenden.',\n\t[keys.actionConfigCc]: 'CC',\n\t[keys.actionConfigBcc]: 'BCC',\n\t[keys.actionConfigReplyTo]: 'Antwort an',\n\t[keys.recipientsGroupDepartments]: 'Abteilungen',\n\t[keys.recipientsGroupFields]: 'Formularfelder',\n\t[keys.recipientsGroupSources]: 'Quellen',\n\t[keys.validationRecipientInvalid]: 'Gib eine gültige E-Mail-Adresse ein.',\n\t[keys.validationRecipientUnknownField]: 'Verweist auf ein nicht mehr vorhandenes Feld.',\n\t[keys.validationRecipientNotAllowed]: 'Dieser Empfänger steht nicht auf der zulässigen Liste.',\n\t[keys.validationRecipientOptionsUnavailable]:\n\t\t'Empfängeroptionen sind derzeit nicht verfügbar. Bitte versuche es später erneut.',\n\t[keys.validationFromUnknown]: 'Wähle eine der konfigurierten Absenderadressen',\n\t[keys.validationFromUnavailable]:\n\t\t'Absenderadressen sind derzeit nicht verfügbar. Bitte versuche es später erneut.',\n\t[keys.actionConfigUrl]: 'URL',\n\t[keys.actionConfigUrlDescription]:\n\t\t'Der Endpunkt, der für jede Übermittlung einen signierten JSON-POST erhält.',\n\t[keys.actionConfigSecret]: 'Geheimer Schlüssel',\n\t[keys.actionConfigSecretDescription]:\n\t\t'HMAC-Schlüssel für den X-Form-Signature-Header, der mit dem Empfänger geteilt wird.',\n\t[keys.validationUrlInvalid]: 'Gib eine gültige http- oder https-URL ein',\n\t[keys.configActions]: 'Aktionen',\n\t[keys.fieldTypeConsent]: 'Einwilligung',\n\t[keys.consentConfigSource]: 'Quelle',\n\t[keys.consentConfigSourceDescription]:\n\t\t'Die Erklärung, der Besucher zustimmen. Wortlaut und Rechtsseite gehören zur Quelle: eine Änderung dort gilt für jedes Formular, das sie nutzt.',\n\t[keys.consentSourcesField]: 'Einwilligungsquellen',\n\t[keys.consentSourcesFieldDescription]:\n\t\t'Erklärungen, die Formulare in Einwilligungsfeldern verwenden können',\n\t[keys.consentSourceSingular]: 'Einwilligungsquelle',\n\t[keys.consentSourcePlural]: 'Einwilligungsquellen',\n\t[keys.consentSourceLabel]: 'Name',\n\t[keys.consentSourceStatement]: 'Erklärung',\n\t[keys.consentSourcePage]: 'Erklärungsquelle',\n\t[keys.consentSourcePageDescription]:\n\t\t'Muss gesetzt sein, wenn Formulareinsendungen einen Verweis auf deine Richtlinie speichern sollen.',\n\t[keys.consentSourcesUnavailable]:\n\t\t'Einwilligungsquellen sind nicht verfügbar. Versuche es gleich noch einmal.',\n\t[keys.resultsResponses]: 'Antworten',\n\t[keys.resultsNoResponses]: 'Noch keine Antworten',\n\t[keys.resultsTruncated]: 'Zeigt eine Stichprobe der Antworten',\n\t[keys.pollGroup]: 'Umfrage',\n\t[keys.pollResultsField]: 'Abstimmungsfeld',\n\t[keys.pollResultsFieldDescription]:\n\t\t'Das Auswahlfeld, dessen Antworten als Stimmen gezählt werden. Wird automatisch gewählt, wenn dein Formular genau ein Auswahlfeld hat. Verwende ein Auswahlfeld, niemals ein Freitext- oder personenbezogenes Feld.',\n\t[keys.pollVoteFieldChoose]: 'Wähle das Feld, dessen Antworten als Stimmen zählen.',\n\t[keys.pollVoteFieldMissing]: 'Füge ein Auswahlfeld als Abstimmungsfrage hinzu.',\n\t[keys.pollResultsVisibility]: 'Sichtbarkeit der Ergebnisse',\n\t[keys.pollVisibilityAfterVote]: 'Nach der Abstimmung',\n\t[keys.pollVisibilityAfterClose]: 'Nach Ende der Umfrage',\n\t[keys.pollClosesAt]: 'Endet am',\n\t[keys.pollClosed]: 'Diese Umfrage ist beendet.',\n\t[keys.pollResultsAfterClose]: 'Die Ergebnisse werden nach Ende der Umfrage angezeigt.',\n\t[keys.pollOptionSource]: 'Optionsquelle',\n\t[keys.pollOptionSourceDescription]:\n\t\t'Befüllt die Auswahlmöglichkeiten des Ergebnisfeldes mit App-Daten anstelle manuell erstellter Optionen.',\n\t[keys.pollSourceConfig]: 'Quelleinstellungen',\n\t[keys.pollOutcome]: 'Ergebnis',\n\t[keys.pollType]: 'Ergebnistyp',\n\t[keys.pollTypeDescription]: 'Wie die Gewinneroption bestimmt wird, sobald die Umfrage endet.',\n\t[keys.pollTypeManual]: 'Gewinner manuell festlegen',\n\t[keys.pollTypeMostVoted]: 'Meistgewählte Option gewinnt',\n\t[keys.pollTypeSource]: 'Gewinner aus der Optionsquelle',\n\t[keys.pollCloseButton]: 'Umfrage jetzt beenden',\n\t[keys.pollReopenButton]: 'Umfrage wieder öffnen',\n\t[keys.pollCloseHintManual]: 'Beim Beenden wird der ausgewählte Gewinner als Ergebnis erfasst.',\n\t[keys.pollCloseHintMostVoted]: 'Beim Beenden wird die meistgewählte Option zum Gewinner.',\n\t[keys.pollCloseHintSource]: 'Beim Beenden wird der Gewinner aus der Optionsquelle ermittelt.',\n\t[keys.pollReopenHint]:\n\t\t'Beim Wiederöffnen wird der erfasste Gewinner entfernt und es kann erneut abgestimmt werden.',\n\t[keys.pollCloseNeedsWinner]: 'Wähle zuerst einen Siegerwert.',\n\t[keys.pollCloseManualNoWinner]: 'Lege einen Gewinner fest, bevor du die Umfrage beendest.',\n\t[keys.pollWinningValue]: 'Siegerwert',\n\t[keys.pollWinningValueDescription]:\n\t\t'Wähle die Gewinneroption, sobald das Ergebnis feststeht. Beim Speichern wird der Entscheidungszeitpunkt erfasst; leeren öffnet das Ergebnis wieder.',\n\t[keys.pollResolvedAt]: 'Entschieden am',\n\t[keys.validationWinningValueUnknown]: 'Der Siegerwert muss eine der Umfrageoptionen sein.',\n\t[keys.validationWinningValueDisabled]: 'Aktiviere die Umfrage, bevor ein Ergebnis erfasst wird.',\n\t[keys.endpointOptionsLoading]: 'Optionen werden geladen...',\n\t[keys.endpointOptionsError]: 'Optionen konnten nicht geladen werden.',\n\t[keys.pollOptionsUnavailable]:\n\t\t'Umfrageoptionen sind derzeit nicht verfügbar. Bitte versuche es später erneut.',\n\t[keys.pollFinalResult]: 'Endergebnis',\n\t[keys.pollResultsError]: 'Ergebnisse konnten nicht geladen werden.',\n\t[keys.resultsWinner]: 'Gewinner',\n\t[keys.validationFileMissing]: 'Datei hochladen',\n\t[keys.validationFileMimeType]: 'Dateityp nicht erlaubt',\n\t[keys.validationFileTooLarge]: 'Datei ist zu groß',\n\t[keys.fieldTypeFile]: 'Datei-Upload',\n\t[keys.fileConfigMimeTypes]: 'Erlaubte Dateitypen',\n\t[keys.fileConfigMaxSize]: 'Maximale Größe (Bytes)',\n\t[keys.fileConfigMaxSizeDescription]: 'Dateien, die größer sind, werden abgelehnt.',\n\t[keys.fileTooLarge]: 'Datei ist zu groß (max. {max})',\n\t[keys.fileUploadMisconfigured]: 'Datei-Uploads sind für dieses Formular nicht konfiguriert',\n\t[keys.fileHintAccepted]: 'Akzeptiert: {types}',\n\t[keys.fileHintMaxSize]: 'Max. Größe: {max}',\n\t[keys.fileUploaded]: 'Hochgeladene Datei',\n\t[keys.fileUploading]: 'Wird hochgeladen',\n\t[keys.fileUploadFailed]: 'Upload fehlgeschlagen',\n\t[keys.fileRemove]: 'Entfernen',\n\t[keys.spamRateLimited]: 'Du hast zu viele Anfragen gesendet. Bitte versuche es später erneut.',\n\t[keys.spamRejected]: 'Deine Übermittlung konnte nicht verarbeitet werden.',\n\t[keys.spamCaptchaFailed]: 'Captcha-Überprüfung fehlgeschlagen. Bitte versuche es erneut.',\n\t[keys.contextInvalid]:\n\t\t'Dieses Formular konnte nicht verifiziert werden. Bitte lade die Seite neu und versuche es erneut.',\n\t[keys.collectionFormSingular]: 'Formular',\n\t[keys.collectionFormPlural]: 'Formulare',\n\t[keys.collectionSubmissionSingular]: 'Übermittlung',\n\t[keys.collectionSubmissionPlural]: 'Übermittlungen',\n\t[keys.submissionContext]: 'Kontext',\n\t[keys.statusComplete]: 'Vollständig',\n\t[keys.statusPartial]: 'Unvollständig',\n\t[keys.fieldTypeRepeater]: 'Wiederholungsfeld',\n\t[keys.configMinRows]: 'Minimale Zeilenanzahl',\n\t[keys.configMaxRows]: 'Maximale Zeilenanzahl',\n\t[keys.configAddLabel]: 'Beschriftung der Schaltfläche zum Hinzufügen',\n\t[keys.configSubFields]: 'Unterfelder',\n\t[keys.validationRepeaterMin]: 'Füge mindestens {min} Zeile(n) hinzu',\n\t[keys.validationRepeaterMax]: 'Entferne Zeilen, um {max} nicht zu überschreiten',\n\t[keys.repeaterAddRow]: 'Zeile hinzufügen',\n\t[keys.repeaterRemoveRow]: 'Entfernen',\n\t[keys.repeaterRow]: 'Zeile {n}',\n\t[keys.repeaterRowCount]: '{count} Zeile(n)',\n\t[keys.submissionConsent]: 'Einwilligung',\n\t[keys.submissionDetails]: 'Details zur Übermittlung',\n\t[keys.submissionConsentAgreed]: 'Zugestimmt',\n\t[keys.submissionConsentDeclined]: 'Abgelehnt',\n\t[keys.submissionMetaLocale]: 'Sprache',\n\t[keys.submissionMetaReceivedAt]: 'Empfangen am',\n\t[keys.submissionMetaIp]: 'IP-Adresse',\n\t[keys.submissionMetaUserAgent]: 'User-Agent',\n\t[keys.submissionMetaCaptcha]: 'Captcha',\n\t[keys.flowDescription]:\n\t\t'Nur für mehrstufige Formulare nötig: Felder zu Schritten gruppieren und den Ablauf dazwischen festlegen. Leer lassen, um das Formular als einzelne Seite anzuzeigen.',\n\t[keys.flowStepFallbackTitle]: 'Schritt {n}',\n\t[keys.flowFieldInStep]: 'in {step}',\n\t[keys.flowUnassigned]: 'In keinem Schritt',\n\t[keys.flowAssignToStep]: 'Zu Schritt hinzufügen',\n\t[keys.flowNextSequential]: 'Nächster Schritt in der Reihenfolge',\n\t[keys.flowNextTerminal]: 'Ende des Formulars',\n\t[keys.flowFields]: 'Felder',\n\t[keys.flowDefaultNext]: 'Standardmäßig weiter zu',\n\t[keys.flowConditionalTransitions]: 'Bedingte Übergänge',\n\t[keys.flowStepTitleLabel]: 'Titel',\n\t[keys.flowSelectStepPlaceholder]: 'Schritt auswählen…',\n\t[keys.flowMoveTransitionUp]: 'Übergang nach oben verschieben',\n\t[keys.flowMoveTransitionDown]: 'Übergang nach unten verschieben',\n\t[keys.flowRemoveTransition]: 'Übergang entfernen',\n\t[keys.flowAddAbove]: 'Oberhalb hinzufügen',\n\t[keys.flowAddBelow]: 'Unterhalb hinzufügen',\n\t[keys.flowGoTo]: 'gehe zu',\n\t[keys.flowWhen]: 'wenn',\n\t[keys.flowNoFields]: 'Noch keine Felder im Formular definiert.',\n\t[keys.flowFirstMatchWins]: '(erste Übereinstimmung gewinnt)',\n\t[keys.flowAddTransition]: 'Übergang hinzufügen',\n\t[keys.flowNoSteps]:\n\t\t'Keine Schritte definiert. Füge mindestens zwei Schritte hinzu, um die mehrseitige Ablaufsteuerung zu aktivieren.',\n\t[keys.flowFallbackTitle]: 'Ablauf',\n\t[keys.fieldTypeMessage]: 'Nachricht',\n\t[keys.configContent]: 'Inhalt',\n\t[keys.tabResponse]: 'Antwort',\n\t[keys.responseType]: 'Nach dem Absenden',\n\t[keys.responseTypeMessage]: 'Eine Nachricht anzeigen',\n\t[keys.responseTypeRedirect]: 'Zu einer URL weiterleiten',\n\t[keys.responseMessage]: 'Nachricht',\n\t[keys.responseRedirect]: 'Weiterleitung',\n\t[keys.responseUrl]: 'URL',\n\t[keys.responseRedirectReference]: 'Dokument',\n\t[keys.responseRedirectReferenceDescription]:\n\t\t'Zu einem internen Dokument statt zu einer URL weiterleiten',\n\t[keys.buttonsSubmitLabel]: 'Beschriftung der Absenden-Schaltfläche',\n\t[keys.buttonsNextLabel]: 'Beschriftung der Weiter-Schaltfläche',\n\t[keys.buttonsPrevLabel]: 'Beschriftung der Zurück-Schaltfläche',\n\t[keys.formBack]: 'Zurück',\n\t[keys.formNext]: 'Weiter',\n\t[keys.formSubmit]: 'Absenden',\n\t[keys.formMultistep]: 'Mehrstufig',\n\t[keys.formPollEnabled]: 'Umfrage',\n\t[keys.formPersistSubmissions]: 'Übermittlungen speichern',\n\t[keys.formClose]: 'Schließen',\n\t[keys.formSuccess]: 'Vielen Dank.',\n\t[keys.formSubmitFailed]: 'Übermittlung fehlgeschlagen',\n\t[keys.formStepStatus]: 'Schritt {current} von {total}',\n\t[keys.formStepInvalid]: 'Bitte korrigieren Sie die markierten Felder, um fortzufahren.',\n\t[keys.cellStepCountOne]: '{{count}} Schritt',\n\t[keys.cellStepCountOther]: '{{count}} Schritte',\n\t[keys.cellFieldCountOne]: '{{count}} Feld',\n\t[keys.cellFieldCountOther]: '{{count}} Felder',\n\t[keys.departmentsField]: 'Abteilungs-E-Mails',\n\t[keys.departmentsFieldDescription]:\n\t\t'Adressen, an die ein Formular Einsendungen weiterleiten kann, jeweils mit Bezeichnung.',\n\t[keys.departmentSingular]: 'Abteilungs-E-Mail',\n\t[keys.departmentPlural]: 'Abteilungs-E-Mails',\n\t[keys.departmentLabel]: 'Bezeichnung',\n\t[keys.departmentEmail]: 'E-Mail',\n\t[keys.departmentAddRow]: 'E-Mail hinzufügen',\n\t[keys.departmentRemoveRow]: 'E-Mail entfernen',\n}\n"],"mappings":"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"}
|
package/dist/translations/en.js
CHANGED
|
@@ -132,6 +132,7 @@ const en = {
|
|
|
132
132
|
[keys.actionConfigReplyTo]: "Reply-to",
|
|
133
133
|
[keys.recipientsGroupDepartments]: "Departments",
|
|
134
134
|
[keys.recipientsGroupFields]: "Form fields",
|
|
135
|
+
[keys.recipientsGroupSources]: "Sources",
|
|
135
136
|
[keys.validationRecipientInvalid]: "Enter a valid email address.",
|
|
136
137
|
[keys.validationRecipientUnknownField]: "References a field that no longer exists.",
|
|
137
138
|
[keys.validationRecipientNotAllowed]: "This recipient is not in the allowed list.",
|
|
@@ -216,10 +217,12 @@ const en = {
|
|
|
216
217
|
[keys.spamRateLimited]: "You have sent too many requests. Please try again later.",
|
|
217
218
|
[keys.spamRejected]: "Your submission could not be processed.",
|
|
218
219
|
[keys.spamCaptchaFailed]: "Captcha verification failed. Please try again.",
|
|
220
|
+
[keys.contextInvalid]: "This form could not be verified. Please reload the page and try again.",
|
|
219
221
|
[keys.collectionFormSingular]: "Form",
|
|
220
222
|
[keys.collectionFormPlural]: "Forms",
|
|
221
223
|
[keys.collectionSubmissionSingular]: "Submission",
|
|
222
224
|
[keys.collectionSubmissionPlural]: "Submissions",
|
|
225
|
+
[keys.submissionContext]: "Context",
|
|
223
226
|
[keys.statusComplete]: "Complete",
|
|
224
227
|
[keys.statusPartial]: "Partial",
|
|
225
228
|
[keys.fieldTypeRepeater]: "Repeater",
|
|
@@ -285,6 +288,7 @@ const en = {
|
|
|
285
288
|
[keys.formSubmit]: "Submit",
|
|
286
289
|
[keys.formMultistep]: "Multi-step",
|
|
287
290
|
[keys.formPollEnabled]: "Poll",
|
|
291
|
+
[keys.formPersistSubmissions]: "Store submissions",
|
|
288
292
|
[keys.formClose]: "Close",
|
|
289
293
|
[keys.formSuccess]: "Thank you.",
|
|
290
294
|
[keys.formSubmitFailed]: "Submission failed",
|