@10x-media/form-builder 0.1.0-beta.4 → 0.1.0-beta.5
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 +83 -0
- package/README.md +3 -3
- package/dist/actions/body/serializeBody.d.ts +8 -5
- package/dist/actions/body/serializeBody.js.map +1 -1
- package/dist/actions/body/textOfBody.d.ts +13 -0
- package/dist/actions/body/textOfBody.js +35 -0
- package/dist/actions/body/textOfBody.js.map +1 -0
- package/dist/actions/builtin/confirmation.js +41 -11
- package/dist/actions/builtin/confirmation.js.map +1 -1
- package/dist/actions/builtin/emailTeam.js +77 -38
- package/dist/actions/builtin/emailTeam.js.map +1 -1
- package/dist/actions/builtin/index.d.ts +8 -3
- package/dist/actions/builtin/index.js +8 -5
- package/dist/actions/builtin/index.js.map +1 -1
- package/dist/actions/defineAction.d.ts +1 -1
- package/dist/actions/fromAddresses.d.ts +21 -0
- package/dist/actions/fromAddresses.js +74 -0
- package/dist/actions/fromAddresses.js.map +1 -0
- package/dist/actions/task.js +9 -8
- package/dist/actions/task.js.map +1 -1
- package/dist/aggregation/aggregateResponses.d.ts +9 -0
- package/dist/aggregation/aggregateResponses.js +8 -14
- package/dist/aggregation/aggregateResponses.js.map +1 -1
- package/dist/aggregation/resolveResultsRequest.d.ts +19 -6
- package/dist/aggregation/resolveResultsRequest.js +58 -12
- package/dist/aggregation/resolveResultsRequest.js.map +1 -1
- package/dist/calc/computeCalcFields.js +2 -1
- package/dist/calc/computeCalcFields.js.map +1 -1
- package/dist/client/ByteSizeField.d.ts +8 -0
- package/dist/client/ByteSizeField.js +3 -1
- package/dist/client/ByteSizeField.js.map +1 -1
- package/dist/client/ClosePollButton.d.ts +15 -0
- package/dist/client/ClosePollButton.js +80 -0
- package/dist/client/ClosePollButton.js.map +1 -0
- package/dist/client/CondensedArray.d.ts +15 -0
- package/dist/client/CondensedArray.js +97 -0
- package/dist/client/CondensedArray.js.map +1 -0
- package/dist/client/EndpointOptionsSelect.d.ts +45 -0
- package/dist/client/EndpointOptionsSelect.js +103 -0
- package/dist/client/EndpointOptionsSelect.js.map +1 -0
- package/dist/client/FieldBlockLabel.d.ts +18 -0
- package/dist/client/FieldBlockLabel.js +34 -0
- package/dist/client/FieldBlockLabel.js.map +1 -0
- package/dist/client/FieldNameSelect.d.ts +20 -4
- package/dist/client/FieldNameSelect.js +25 -14
- package/dist/client/FieldNameSelect.js.map +1 -1
- package/dist/client/FlowBuilder.d.ts +2 -1
- package/dist/client/FlowBuilder.js +63 -57
- package/dist/client/FlowBuilder.js.map +1 -1
- package/dist/client/RuleDescription.d.ts +21 -0
- package/dist/client/RuleDescription.js +19 -0
- package/dist/client/RuleDescription.js.map +1 -0
- package/dist/client/admin.css +36 -0
- package/dist/client/endpointOptions.js +29 -0
- package/dist/client/endpointOptions.js.map +1 -0
- package/dist/client/flowAuthoring.js +114 -7
- package/dist/client/flowAuthoring.js.map +1 -1
- package/dist/client/synthesizeClientField.js +15 -8
- package/dist/client/synthesizeClientField.js.map +1 -1
- package/dist/collections/buttonFields.d.ts +34 -0
- package/dist/collections/buttonFields.js +35 -0
- package/dist/collections/buttonFields.js.map +1 -0
- package/dist/collections/cells/FieldCountCell.d.ts +15 -0
- package/dist/collections/cells/FieldCountCell.js +18 -0
- package/dist/collections/cells/FieldCountCell.js.map +1 -0
- package/dist/collections/cells/FlowStepsCell.d.ts +14 -0
- package/dist/collections/cells/FlowStepsCell.js +17 -0
- package/dist/collections/cells/FlowStepsCell.js.map +1 -0
- package/dist/collections/formSubmissions.js +22 -17
- package/dist/collections/formSubmissions.js.map +1 -1
- package/dist/collections/forms.js +310 -137
- package/dist/collections/forms.js.map +1 -1
- package/dist/collections/redirectFields.d.ts +29 -0
- package/dist/consent/applyConsentStatements.d.ts +14 -0
- package/dist/consent/applyConsentStatements.js +17 -0
- package/dist/consent/applyConsentStatements.js.map +1 -0
- package/dist/consent/captureConsent.d.ts +19 -8
- package/dist/consent/captureConsent.js +34 -11
- package/dist/consent/captureConsent.js.map +1 -1
- package/dist/consent/consentSourcesField.d.ts +58 -0
- package/dist/consent/consentSourcesField.js +79 -0
- package/dist/consent/consentSourcesField.js.map +1 -0
- package/dist/consent/resolveConsentEntries.d.ts +24 -0
- package/dist/consent/resolveConsentEntries.js +43 -0
- package/dist/consent/resolveConsentEntries.js.map +1 -0
- package/dist/consent/resolveConsentSourcesRequest.d.ts +37 -0
- package/dist/consent/resolveConsentSourcesRequest.js +55 -0
- package/dist/consent/resolveConsentSourcesRequest.js.map +1 -0
- package/dist/consent/resolveConsentStatements.d.ts +45 -0
- package/dist/consent/resolveConsentStatements.js +44 -0
- package/dist/consent/resolveConsentStatements.js.map +1 -0
- package/dist/consent/resolvePublishedVersionRef.d.ts +17 -11
- package/dist/consent/resolvePublishedVersionRef.js +13 -10
- package/dist/consent/resolvePublishedVersionRef.js.map +1 -1
- package/dist/consent/types.d.ts +49 -0
- package/dist/email/departments.d.ts +55 -0
- package/dist/email/departments.js +130 -0
- package/dist/email/departments.js.map +1 -0
- package/dist/email/departmentsField.d.ts +49 -0
- package/dist/email/departmentsField.js +69 -0
- package/dist/email/departmentsField.js.map +1 -0
- package/dist/exports/client.d.ts +8 -1
- package/dist/exports/client.js +8 -1
- package/dist/exports/react.d.ts +8 -3
- package/dist/exports/react.js +6 -2
- package/dist/exports/rsc.d.ts +3 -1
- package/dist/exports/rsc.js +4 -2
- package/dist/exports/types.d.ts +16 -8
- package/dist/fields/buildFieldBlocks.js +28 -13
- package/dist/fields/buildFieldBlocks.js.map +1 -1
- package/dist/fields/builtin/calculation.js +7 -0
- package/dist/fields/builtin/calculation.js.map +1 -1
- package/dist/fields/builtin/checkbox.js +8 -0
- package/dist/fields/builtin/checkbox.js.map +1 -1
- package/dist/fields/builtin/consent.js +27 -21
- package/dist/fields/builtin/consent.js.map +1 -1
- package/dist/fields/builtin/country.d.ts +13 -0
- package/dist/fields/builtin/country.js +30 -0
- package/dist/fields/builtin/country.js.map +1 -0
- package/dist/fields/builtin/date.js +2 -0
- package/dist/fields/builtin/date.js.map +1 -1
- package/dist/fields/builtin/file.js +5 -4
- package/dist/fields/builtin/file.js.map +1 -1
- package/dist/fields/builtin/index.d.ts +8 -6
- package/dist/fields/builtin/index.js +10 -9
- package/dist/fields/builtin/index.js.map +1 -1
- package/dist/fields/builtin/message.js +8 -4
- package/dist/fields/builtin/message.js.map +1 -1
- package/dist/fields/builtin/repeater.js +1 -0
- package/dist/fields/builtin/repeater.js.map +1 -1
- package/dist/fields/builtin/select.js +1 -0
- package/dist/fields/builtin/select.js.map +1 -1
- package/dist/fields/builtin/state.d.ts +13 -0
- package/dist/fields/builtin/state.js +30 -0
- package/dist/fields/builtin/state.js.map +1 -0
- package/dist/fields/data/regions.d.ts +21 -0
- package/dist/fields/data/regions.js +1238 -0
- package/dist/fields/data/regions.js.map +1 -0
- package/dist/fields/fieldKey.d.ts +15 -0
- package/dist/fields/fieldKey.js +16 -0
- package/dist/fields/fieldKey.js.map +1 -0
- package/dist/fields/fieldNamesOfType.js +13 -8
- package/dist/fields/fieldNamesOfType.js.map +1 -1
- package/dist/fields/instanceOptions.js +20 -0
- package/dist/fields/instanceOptions.js.map +1 -0
- package/dist/fields/registry.d.ts +1 -0
- package/dist/fields/registry.js +21 -2
- package/dist/fields/registry.js.map +1 -1
- package/dist/fields/sharedConfig.js +46 -9
- package/dist/fields/sharedConfig.js.map +1 -1
- package/dist/fields/types.d.ts +54 -3
- package/dist/flow/engine.d.ts +6 -4
- package/dist/flow/engine.js +11 -6
- package/dist/flow/engine.js.map +1 -1
- package/dist/flow/normalizeFlow.js +16 -7
- package/dist/flow/normalizeFlow.js.map +1 -1
- package/dist/flow/types.d.ts +12 -3
- package/dist/flow/types.js +11 -0
- package/dist/flow/types.js.map +1 -0
- package/dist/form/pollState.d.ts +4 -4
- package/dist/form/pollState.js.map +1 -1
- package/dist/form/toFormDocument.d.ts +37 -12
- package/dist/form/toFormDocument.js +43 -7
- package/dist/form/toFormDocument.js.map +1 -1
- package/dist/form/types.d.ts +31 -14
- package/dist/index.d.ts +143 -28
- package/dist/index.js +43 -14
- package/dist/index.js.map +1 -1
- package/dist/plugin/customState.js +26 -0
- package/dist/plugin/customState.js.map +1 -0
- package/dist/plugin/registerCollections.js +23 -13
- package/dist/plugin/registerCollections.js.map +1 -1
- package/dist/plugin/uploadsCollection.d.ts +2 -0
- package/dist/poll/applyPollOptions.js +3 -2
- package/dist/poll/applyPollOptions.js.map +1 -1
- package/dist/poll/buildPollOptionSourceFields.js +2 -5
- package/dist/poll/buildPollOptionSourceFields.js.map +1 -1
- package/dist/poll/closeJob.d.ts +52 -0
- package/dist/poll/closeJob.js +119 -0
- package/dist/poll/closeJob.js.map +1 -0
- package/dist/poll/definePollOptionSource.d.ts +10 -1
- package/dist/poll/definePollOptionSource.js.map +1 -1
- package/dist/poll/definePollType.d.ts +34 -0
- package/dist/poll/definePollType.js +6 -0
- package/dist/poll/definePollType.js.map +1 -0
- package/dist/poll/effectivePollOptions.d.ts +38 -0
- package/dist/poll/effectivePollOptions.js +64 -0
- package/dist/poll/effectivePollOptions.js.map +1 -0
- package/dist/poll/mostVoted.d.ts +21 -0
- package/dist/poll/mostVoted.js +32 -0
- package/dist/poll/mostVoted.js.map +1 -0
- package/dist/poll/outcomeBeforeChange.js +91 -0
- package/dist/poll/outcomeBeforeChange.js.map +1 -0
- package/dist/poll/outcomeFields.d.ts +38 -0
- package/dist/poll/outcomeFields.js +52 -0
- package/dist/poll/outcomeFields.js.map +1 -0
- package/dist/poll/pollTypeRegistry.d.ts +34 -0
- package/dist/poll/pollTypeRegistry.js +71 -0
- package/dist/poll/pollTypeRegistry.js.map +1 -0
- package/dist/poll/resolvePollCloseRequest.js +105 -0
- package/dist/poll/resolvePollCloseRequest.js.map +1 -0
- package/dist/poll/resolvePollOptions.d.ts +2 -1
- package/dist/poll/resolvePollOptions.js +5 -17
- package/dist/poll/resolvePollOptions.js.map +1 -1
- package/dist/poll/resolvePollOptionsRequest.js +51 -0
- package/dist/poll/resolvePollOptionsRequest.js.map +1 -0
- package/dist/poll/resolvePollOutcome.d.ts +22 -9
- package/dist/poll/resolvePollOutcome.js +54 -14
- package/dist/poll/resolvePollOutcome.js.map +1 -1
- package/dist/poll/resultsField.js +21 -0
- package/dist/poll/resultsField.js.map +1 -0
- package/dist/prefill/valuesFromSearchParams.js +2 -1
- package/dist/prefill/valuesFromSearchParams.js.map +1 -1
- package/dist/react/Form.d.ts +8 -8
- package/dist/react/Form.js +74 -62
- package/dist/react/Form.js.map +1 -1
- package/dist/react/FormContext.d.ts +6 -4
- package/dist/react/FormContext.js.map +1 -1
- package/dist/react/FormControls.d.ts +3 -3
- package/dist/react/FormControls.js +3 -3
- package/dist/react/FormControls.js.map +1 -1
- package/dist/react/FormResults.d.ts +5 -5
- package/dist/react/FormResults.js +6 -6
- package/dist/react/FormResults.js.map +1 -1
- package/dist/react/Poll.d.ts +2 -2
- package/dist/react/Poll.js +5 -5
- package/dist/react/Poll.js.map +1 -1
- package/dist/react/contract.d.ts +2 -3
- package/dist/react/contract.js.map +1 -1
- package/dist/react/primitives/Checkbox.d.ts +4 -2
- package/dist/react/primitives/Checkbox.js +2 -1
- package/dist/react/primitives/Checkbox.js.map +1 -1
- package/dist/react/primitives/FieldShell.d.ts +2 -4
- package/dist/react/primitives/FieldShell.js +12 -19
- package/dist/react/primitives/FieldShell.js.map +1 -1
- package/dist/react/renderers/calculation.js +1 -2
- package/dist/react/renderers/calculation.js.map +1 -1
- package/dist/react/renderers/checkbox.js +1 -2
- package/dist/react/renderers/checkbox.js.map +1 -1
- package/dist/react/renderers/consent.js +78 -34
- package/dist/react/renderers/consent.js.map +1 -1
- package/dist/react/renderers/date.js +1 -3
- package/dist/react/renderers/date.js.map +1 -1
- package/dist/react/renderers/email.js +1 -2
- package/dist/react/renderers/email.js.map +1 -1
- package/dist/react/renderers/file.js +1 -2
- package/dist/react/renderers/file.js.map +1 -1
- package/dist/react/renderers/index.js +3 -0
- package/dist/react/renderers/index.js.map +1 -1
- package/dist/react/renderers/number.js +1 -2
- package/dist/react/renderers/number.js.map +1 -1
- package/dist/react/renderers/region.js +45 -0
- package/dist/react/renderers/region.js.map +1 -0
- package/dist/react/renderers/repeater.js +7 -10
- package/dist/react/renderers/repeater.js.map +1 -1
- package/dist/react/renderers/select.js +1 -2
- package/dist/react/renderers/select.js.map +1 -1
- package/dist/react/renderers/text.js +1 -2
- package/dist/react/renderers/text.js.map +1 -1
- package/dist/react/renderers/textarea.js +1 -2
- package/dist/react/renderers/textarea.js.map +1 -1
- package/dist/react/state.d.ts +0 -3
- package/dist/react/state.js +7 -11
- package/dist/react/state.js.map +1 -1
- package/dist/react/useField.d.ts +0 -1
- package/dist/react/useField.js +0 -1
- package/dist/react/useField.js.map +1 -1
- package/dist/react/useFormState.d.ts +1 -1
- package/dist/react/useFormState.js +1 -1
- package/dist/react/useFormState.js.map +1 -1
- package/dist/react/validateField.js +3 -6
- package/dist/react/validateField.js.map +1 -1
- package/dist/recall/interpolate.d.ts +4 -3
- package/dist/recall/interpolate.js +5 -4
- package/dist/recall/interpolate.js.map +1 -1
- package/dist/recall/resolver.d.ts +1 -1
- package/dist/recall/resolver.js +14 -2
- package/dist/recall/resolver.js.map +1 -1
- package/dist/spam/captcha.d.ts +1 -1
- package/dist/spam/captcha.js +1 -1
- package/dist/spam/captcha.js.map +1 -1
- package/dist/submissions/SubmissionAnswers.js +6 -2
- package/dist/submissions/SubmissionAnswers.js.map +1 -1
- package/dist/submissions/SubmissionAnswersClient.js +91 -62
- package/dist/submissions/SubmissionAnswersClient.js.map +1 -1
- package/dist/submissions/createSubmission.d.ts +36 -0
- package/dist/submissions/createSubmission.js +26 -0
- package/dist/submissions/createSubmission.js.map +1 -0
- package/dist/submissions/runSubmission.d.ts +10 -0
- package/dist/submissions/runSubmission.js +29 -18
- package/dist/submissions/runSubmission.js.map +1 -1
- package/dist/submissions/types.d.ts +11 -4
- package/dist/submissions/validateSubmission.js +38 -23
- package/dist/submissions/validateSubmission.js.map +1 -1
- package/dist/submissions/votedCookie.js +3 -3
- package/dist/submissions/votedCookie.js.map +1 -1
- package/dist/translations/de.js +102 -26
- package/dist/translations/de.js.map +1 -1
- package/dist/translations/en.js +103 -27
- package/dist/translations/en.js.map +1 -1
- package/dist/translations/keys.d.ts +97 -21
- package/dist/translations/keys.js +98 -22
- package/dist/translations/keys.js.map +1 -1
- package/dist/validation/buildRuleBlocks.js +18 -17
- package/dist/validation/buildRuleBlocks.js.map +1 -1
- package/dist/validation/builtin/email.js +1 -0
- package/dist/validation/builtin/email.js.map +1 -1
- package/dist/validation/builtin/matchesField.js +3 -7
- package/dist/validation/builtin/matchesField.js.map +1 -1
- package/dist/validation/builtin/max.js +1 -0
- package/dist/validation/builtin/max.js.map +1 -1
- package/dist/validation/builtin/maxDate.js +1 -0
- package/dist/validation/builtin/maxDate.js.map +1 -1
- package/dist/validation/builtin/maxLength.js +1 -0
- package/dist/validation/builtin/maxLength.js.map +1 -1
- package/dist/validation/builtin/min.js +1 -0
- package/dist/validation/builtin/min.js.map +1 -1
- package/dist/validation/builtin/minDate.js +1 -0
- package/dist/validation/builtin/minDate.js.map +1 -1
- package/dist/validation/builtin/minLength.js +1 -0
- package/dist/validation/builtin/minLength.js.map +1 -1
- package/dist/validation/builtin/notAlreadySubmitted.js +1 -0
- package/dist/validation/builtin/notAlreadySubmitted.js.map +1 -1
- package/dist/validation/builtin/oneOf.js +1 -0
- package/dist/validation/builtin/oneOf.js.map +1 -1
- package/dist/validation/builtin/pattern.js +11 -2
- package/dist/validation/builtin/pattern.js.map +1 -1
- package/dist/validation/builtin/url.js +1 -0
- package/dist/validation/builtin/url.js.map +1 -1
- package/dist/validation/builtin/validateRegexParams.js +44 -0
- package/dist/validation/builtin/validateRegexParams.js.map +1 -0
- package/dist/validation/fieldTargetParam.d.ts +22 -0
- package/dist/validation/fieldTargetParam.js +38 -0
- package/dist/validation/fieldTargetParam.js.map +1 -0
- package/dist/validation/runValidation.js +8 -29
- package/dist/validation/runValidation.js.map +1 -1
- package/dist/validation/types.d.ts +5 -11
- package/package.json +6 -6
- package/dist/consent/buildConsentSourceConfig.js +0 -49
- package/dist/consent/buildConsentSourceConfig.js.map +0 -1
- package/dist/consent/builtin/index.d.ts +0 -17
- package/dist/consent/builtin/index.js +0 -21
- package/dist/consent/builtin/index.js.map +0 -1
- package/dist/consent/builtin/pageReference.js +0 -75
- package/dist/consent/builtin/pageReference.js.map +0 -1
- package/dist/consent/builtin/static.js +0 -48
- package/dist/consent/builtin/static.js.map +0 -1
- package/dist/consent/defineConsentSource.d.ts +0 -35
- package/dist/consent/defineConsentSource.js +0 -6
- package/dist/consent/defineConsentSource.js.map +0 -1
- package/dist/consent/registry.d.ts +0 -16
- package/dist/consent/registry.js +0 -16
- package/dist/consent/registry.js.map +0 -1
- package/dist/consent/resolveConsentLinks.d.ts +0 -19
- package/dist/consent/resolveConsentLinks.js +0 -26
- package/dist/consent/resolveConsentLinks.js.map +0 -1
|
@@ -3,19 +3,32 @@ import { Payload, PayloadRequest } from "payload";
|
|
|
3
3
|
//#region src/poll/resolvePollOutcome.d.ts
|
|
4
4
|
type ResolvePollOutcomeArgs = {
|
|
5
5
|
payload: Payload;
|
|
6
|
-
formId: number | string;
|
|
7
|
-
|
|
6
|
+
formId: number | string;
|
|
7
|
+
/**
|
|
8
|
+
* The winning set: stable option values, each matching one of the poll's choice values (the
|
|
9
|
+
* host's contract with `PollOption.value`). Pass more than one for a tie, an empty array to clear
|
|
10
|
+
* the outcome. Omit to auto-resolve via the poll's selected outcome strategy (`poll.type`).
|
|
11
|
+
*/
|
|
12
|
+
winningValues?: string[];
|
|
8
13
|
req?: PayloadRequest;
|
|
9
14
|
};
|
|
10
15
|
/**
|
|
11
|
-
* Record a poll's final outcome
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
16
|
+
* Record a poll's final outcome server-side, in one of two modes:
|
|
17
|
+
* - explicit: pass `winningValues` when host code already knows the winner(s); more than one is a
|
|
18
|
+
* tie, and an empty array clears the outcome;
|
|
19
|
+
* - auto: omit it and the poll's selected outcome strategy (`poll.type`, from the `poll.types`
|
|
20
|
+
* registry, defaulting to `manual`) resolves the winners. `manual` is a no-op; `mostVoted` reads
|
|
21
|
+
* the aggregated results field; `source` delegates to the option source. A strategy that is not
|
|
22
|
+
* yet decidable (or `manual`) writes nothing and this returns an empty set, so auto mode is safe
|
|
23
|
+
* to call repeatedly from the close job and the read fallback.
|
|
24
|
+
*
|
|
25
|
+
* Every write runs through `payload.update` with `overrideAccess`, so the forms collection hook
|
|
26
|
+
* validates each value against the poll's effective options and owns the `poll.outcome.resolvedAt`
|
|
27
|
+
* stamp in both modes (auto-resolved winners are validated exactly as hand-picked ones). Throws only
|
|
28
|
+
* when the form does not exist or is not poll-enabled. Returns the recorded winning set (empty when
|
|
29
|
+
* auto mode did not decide).
|
|
17
30
|
*/
|
|
18
|
-
declare const resolvePollOutcome: (args: ResolvePollOutcomeArgs) => Promise<
|
|
31
|
+
declare const resolvePollOutcome: (args: ResolvePollOutcomeArgs) => Promise<string[]>;
|
|
19
32
|
//#endregion
|
|
20
33
|
export { ResolvePollOutcomeArgs, resolvePollOutcome };
|
|
21
34
|
//# sourceMappingURL=resolvePollOutcome.d.ts.map
|
|
@@ -1,34 +1,74 @@
|
|
|
1
1
|
import { pollConfigOf } from "../form/pollState.js";
|
|
2
|
+
import { aggregateFieldResponses } from "../aggregation/aggregateResponses.js";
|
|
3
|
+
import { pollTypesOf } from "./pollTypeRegistry.js";
|
|
2
4
|
import { FORMS_SLUG } from "../collections/forms.js";
|
|
3
5
|
//#region src/poll/resolvePollOutcome.ts
|
|
6
|
+
/** A strategy result narrowed to a deduped set of non-empty strings. */
|
|
7
|
+
const cleanWinners = (value) => value === void 0 ? [] : [...new Set(value.filter((entry) => typeof entry === "string" && entry.length > 0))];
|
|
4
8
|
/**
|
|
5
|
-
* Record a poll's final outcome
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
9
|
+
* Record a poll's final outcome server-side, in one of two modes:
|
|
10
|
+
* - explicit: pass `winningValues` when host code already knows the winner(s); more than one is a
|
|
11
|
+
* tie, and an empty array clears the outcome;
|
|
12
|
+
* - auto: omit it and the poll's selected outcome strategy (`poll.type`, from the `poll.types`
|
|
13
|
+
* registry, defaulting to `manual`) resolves the winners. `manual` is a no-op; `mostVoted` reads
|
|
14
|
+
* the aggregated results field; `source` delegates to the option source. A strategy that is not
|
|
15
|
+
* yet decidable (or `manual`) writes nothing and this returns an empty set, so auto mode is safe
|
|
16
|
+
* to call repeatedly from the close job and the read fallback.
|
|
17
|
+
*
|
|
18
|
+
* Every write runs through `payload.update` with `overrideAccess`, so the forms collection hook
|
|
19
|
+
* validates each value against the poll's effective options and owns the `poll.outcome.resolvedAt`
|
|
20
|
+
* stamp in both modes (auto-resolved winners are validated exactly as hand-picked ones). Throws only
|
|
21
|
+
* when the form does not exist or is not poll-enabled. Returns the recorded winning set (empty when
|
|
22
|
+
* auto mode did not decide).
|
|
11
23
|
*/
|
|
12
24
|
const resolvePollOutcome = async (args) => {
|
|
13
|
-
const { payload, formId,
|
|
14
|
-
|
|
15
|
-
collection:
|
|
25
|
+
const { payload, formId, req } = args;
|
|
26
|
+
const form = await payload.findByID({
|
|
27
|
+
collection: FORMS_SLUG,
|
|
16
28
|
id: formId,
|
|
17
29
|
depth: 0,
|
|
18
30
|
overrideAccess: true,
|
|
19
31
|
req
|
|
20
|
-
})
|
|
32
|
+
});
|
|
33
|
+
const poll = pollConfigOf(form.poll);
|
|
34
|
+
if (form.pollEnabled !== true || !poll) throw new Error(`Form ${String(formId)} is not poll-enabled; cannot record an outcome.`);
|
|
35
|
+
let winningValues;
|
|
36
|
+
if (args.winningValues !== void 0) winningValues = args.winningValues;
|
|
37
|
+
else {
|
|
38
|
+
const strategyType = typeof poll.type === "string" && poll.type.length > 0 ? poll.type : "manual";
|
|
39
|
+
const strategy = pollTypesOf(payload).get(strategyType);
|
|
40
|
+
if (!strategy) return [];
|
|
41
|
+
let aggregated;
|
|
42
|
+
const aggregate = async () => {
|
|
43
|
+
if (aggregated === void 0) {
|
|
44
|
+
const resultsField = typeof poll.resultsField === "string" && poll.resultsField.length > 0 ? poll.resultsField : void 0;
|
|
45
|
+
aggregated = resultsField ? await aggregateFieldResponses({
|
|
46
|
+
payload,
|
|
47
|
+
formId,
|
|
48
|
+
field: resultsField,
|
|
49
|
+
req
|
|
50
|
+
}) : null;
|
|
51
|
+
}
|
|
52
|
+
return aggregated;
|
|
53
|
+
};
|
|
54
|
+
winningValues = cleanWinners(await strategy.resolveOutcome({
|
|
55
|
+
payload,
|
|
56
|
+
req,
|
|
57
|
+
form,
|
|
58
|
+
poll,
|
|
59
|
+
aggregate
|
|
60
|
+
}));
|
|
61
|
+
if (winningValues.length === 0) return [];
|
|
62
|
+
}
|
|
21
63
|
await payload.update({
|
|
22
64
|
collection: FORMS_SLUG,
|
|
23
65
|
id: formId,
|
|
24
|
-
data: { poll: { outcome: {
|
|
25
|
-
winningValue,
|
|
26
|
-
resolvedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
27
|
-
} } },
|
|
66
|
+
data: { poll: { outcome: { winningValues } } },
|
|
28
67
|
depth: 0,
|
|
29
68
|
overrideAccess: true,
|
|
30
69
|
req
|
|
31
70
|
});
|
|
71
|
+
return winningValues;
|
|
32
72
|
};
|
|
33
73
|
//#endregion
|
|
34
74
|
export { resolvePollOutcome };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolvePollOutcome.js","names":[],"sources":["../../src/poll/resolvePollOutcome.ts"],"sourcesContent":["import type { Payload, PayloadRequest } from 'payload'\nimport { FORMS_SLUG } from '../collections/forms'\nimport { pollConfigOf } from '../form/pollState'\n\nexport type ResolvePollOutcomeArgs = {\n\tpayload: Payload\n\tformId: number | string\n\t
|
|
1
|
+
{"version":3,"file":"resolvePollOutcome.js","names":[],"sources":["../../src/poll/resolvePollOutcome.ts"],"sourcesContent":["import type { Payload, PayloadRequest } from 'payload'\nimport { aggregateFieldResponses } from '../aggregation/aggregateResponses'\nimport type { FieldAggregation } from '../aggregation/types'\nimport { FORMS_SLUG } from '../collections/forms'\nimport { pollConfigOf } from '../form/pollState'\nimport type { PollOutcomeStrategyArgs } from './definePollType'\nimport { pollTypesOf } from './pollTypeRegistry'\n\nexport type ResolvePollOutcomeArgs = {\n\tpayload: Payload\n\tformId: number | string\n\t/**\n\t * The winning set: stable option values, each matching one of the poll's choice values (the\n\t * host's contract with `PollOption.value`). Pass more than one for a tie, an empty array to clear\n\t * the outcome. Omit to auto-resolve via the poll's selected outcome strategy (`poll.type`).\n\t */\n\twinningValues?: string[]\n\treq?: PayloadRequest\n}\n\n/** A strategy result narrowed to a deduped set of non-empty strings. */\nconst cleanWinners = (value: string[] | undefined): string[] =>\n\tvalue === undefined\n\t\t? []\n\t\t: [\n\t\t\t\t...new Set(\n\t\t\t\t\tvalue.filter((entry): entry is string => typeof entry === 'string' && entry.length > 0)\n\t\t\t\t),\n\t\t\t]\n\n/**\n * Record a poll's final outcome server-side, in one of two modes:\n * - explicit: pass `winningValues` when host code already knows the winner(s); more than one is a\n * tie, and an empty array clears the outcome;\n * - auto: omit it and the poll's selected outcome strategy (`poll.type`, from the `poll.types`\n * registry, defaulting to `manual`) resolves the winners. `manual` is a no-op; `mostVoted` reads\n * the aggregated results field; `source` delegates to the option source. A strategy that is not\n * yet decidable (or `manual`) writes nothing and this returns an empty set, so auto mode is safe\n * to call repeatedly from the close job and the read fallback.\n *\n * Every write runs through `payload.update` with `overrideAccess`, so the forms collection hook\n * validates each value against the poll's effective options and owns the `poll.outcome.resolvedAt`\n * stamp in both modes (auto-resolved winners are validated exactly as hand-picked ones). Throws only\n * when the form does not exist or is not poll-enabled. Returns the recorded winning set (empty when\n * auto mode did not decide).\n */\nexport const resolvePollOutcome = async (args: ResolvePollOutcomeArgs): Promise<string[]> => {\n\tconst { payload, formId, req } = args\n\tconst form = await payload.findByID({\n\t\tcollection: FORMS_SLUG,\n\t\tid: formId,\n\t\tdepth: 0,\n\t\toverrideAccess: true,\n\t\treq,\n\t})\n\tconst poll = pollConfigOf(form.poll)\n\tif (form.pollEnabled !== true || !poll) {\n\t\tthrow new Error(`Form ${String(formId)} is not poll-enabled; cannot record an outcome.`)\n\t}\n\n\tlet winningValues: string[]\n\tif (args.winningValues !== undefined) {\n\t\twinningValues = args.winningValues\n\t} else {\n\t\tconst strategyType =\n\t\t\ttypeof poll.type === 'string' && poll.type.length > 0 ? poll.type : 'manual'\n\t\tconst strategy = pollTypesOf(payload).get(strategyType)\n\t\tif (!strategy) {\n\t\t\treturn []\n\t\t}\n\t\tlet aggregated: FieldAggregation | null | undefined\n\t\tconst aggregate = async (): Promise<FieldAggregation | null> => {\n\t\t\tif (aggregated === undefined) {\n\t\t\t\tconst resultsField =\n\t\t\t\t\ttypeof poll.resultsField === 'string' && poll.resultsField.length > 0\n\t\t\t\t\t\t? poll.resultsField\n\t\t\t\t\t\t: undefined\n\t\t\t\taggregated = resultsField\n\t\t\t\t\t? await aggregateFieldResponses({ payload, formId, field: resultsField, req })\n\t\t\t\t\t: null\n\t\t\t}\n\t\t\treturn aggregated\n\t\t}\n\t\twinningValues = cleanWinners(\n\t\t\tawait strategy.resolveOutcome({\n\t\t\t\tpayload,\n\t\t\t\treq,\n\t\t\t\tform: form as unknown as PollOutcomeStrategyArgs['form'],\n\t\t\t\tpoll,\n\t\t\t\taggregate,\n\t\t\t})\n\t\t)\n\t\tif (winningValues.length === 0) {\n\t\t\treturn []\n\t\t}\n\t}\n\n\tawait payload.update({\n\t\tcollection: FORMS_SLUG,\n\t\tid: formId,\n\t\tdata: { poll: { outcome: { winningValues } } },\n\t\tdepth: 0,\n\t\toverrideAccess: true,\n\t\treq,\n\t})\n\treturn winningValues\n}\n"],"mappings":";;;;;;AAqBA,MAAM,gBAAgB,UACrB,UAAU,KAAA,IACP,CAAC,IACD,CACA,GAAG,IAAI,IACN,MAAM,QAAQ,UAA2B,OAAO,UAAU,YAAY,MAAM,SAAS,CAAC,CACvF,CACD;;;;;;;;;;;;;;;;;AAkBH,MAAa,qBAAqB,OAAO,SAAoD;CAC5F,MAAM,EAAE,SAAS,QAAQ,QAAQ;CACjC,MAAM,OAAO,MAAM,QAAQ,SAAS;EACnC,YAAY;EACZ,IAAI;EACJ,OAAO;EACP,gBAAgB;EAChB;CACD,CAAC;CACD,MAAM,OAAO,aAAa,KAAK,IAAI;CACnC,IAAI,KAAK,gBAAgB,QAAQ,CAAC,MACjC,MAAM,IAAI,MAAM,QAAQ,OAAO,MAAM,EAAE,gDAAgD;CAGxF,IAAI;CACJ,IAAI,KAAK,kBAAkB,KAAA,GAC1B,gBAAgB,KAAK;MACf;EACN,MAAM,eACL,OAAO,KAAK,SAAS,YAAY,KAAK,KAAK,SAAS,IAAI,KAAK,OAAO;EACrE,MAAM,WAAW,YAAY,OAAO,EAAE,IAAI,YAAY;EACtD,IAAI,CAAC,UACJ,OAAO,CAAC;EAET,IAAI;EACJ,MAAM,YAAY,YAA8C;GAC/D,IAAI,eAAe,KAAA,GAAW;IAC7B,MAAM,eACL,OAAO,KAAK,iBAAiB,YAAY,KAAK,aAAa,SAAS,IACjE,KAAK,eACL,KAAA;IACJ,aAAa,eACV,MAAM,wBAAwB;KAAE;KAAS;KAAQ,OAAO;KAAc;IAAI,CAAC,IAC3E;GACJ;GACA,OAAO;EACR;EACA,gBAAgB,aACf,MAAM,SAAS,eAAe;GAC7B;GACA;GACM;GACN;GACA;EACD,CAAC,CACF;EACA,IAAI,cAAc,WAAW,GAC5B,OAAO,CAAC;CAEV;CAEA,MAAM,QAAQ,OAAO;EACpB,YAAY;EACZ,IAAI;EACJ,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,cAAc,EAAE,EAAE;EAC7C,OAAO;EACP,gBAAgB;EAChB;CACD,CAAC;CACD,OAAO;AACR"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { fieldNamesOfType } from "../fields/fieldNamesOfType.js";
|
|
2
|
+
import { keys } from "../translations/keys.js";
|
|
3
|
+
import { asTranslate } from "../translations/server.js";
|
|
4
|
+
//#region src/poll/resultsField.ts
|
|
5
|
+
/** Slugs of registered field types choosable as a poll's results field (`pollEligible: true`). */
|
|
6
|
+
const pollEligibleTypes = (registry) => [...registry.values()].filter((definition) => definition.pollEligible === true).map((definition) => definition.type);
|
|
7
|
+
/**
|
|
8
|
+
* Validate for `poll.resultsField`, closed over the eligible type slugs derived from the registry
|
|
9
|
+
* at collection-build time (mirrors the confirmation action's `toField`): unset is fine, otherwise
|
|
10
|
+
* the value must name an existing, named field instance whose type is poll-eligible. Payload skips
|
|
11
|
+
* the validate while the poll is disabled (the field's `admin.condition`), so a stale reference on
|
|
12
|
+
* a disabled poll never blocks a save.
|
|
13
|
+
*/
|
|
14
|
+
const buildValidateResultsField = (eligibleTypes) => (value, { data, req }) => {
|
|
15
|
+
if (typeof value !== "string" || value.length === 0) return true;
|
|
16
|
+
return fieldNamesOfType(data && typeof data === "object" ? data.fields : void 0, eligibleTypes).includes(value) ? true : asTranslate(req.t)(keys.validationResultsFieldUnknown);
|
|
17
|
+
};
|
|
18
|
+
//#endregion
|
|
19
|
+
export { buildValidateResultsField, pollEligibleTypes };
|
|
20
|
+
|
|
21
|
+
//# sourceMappingURL=resultsField.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resultsField.js","names":[],"sources":["../../src/poll/resultsField.ts"],"sourcesContent":["import type { PayloadRequest } from 'payload'\nimport { fieldNamesOfType } from '../fields/fieldNamesOfType'\nimport type { FieldTypeRegistry } from '../fields/registry'\nimport { keys } from '../translations/keys'\nimport { asTranslate } from '../translations/server'\n\n/** Slugs of registered field types choosable as a poll's results field (`pollEligible: true`). */\nexport const pollEligibleTypes = (registry: FieldTypeRegistry): string[] =>\n\t[...registry.values()]\n\t\t.filter((definition) => definition.pollEligible === true)\n\t\t.map((definition) => definition.type)\n\n/**\n * Validate for `poll.resultsField`, closed over the eligible type slugs derived from the registry\n * at collection-build time (mirrors the confirmation action's `toField`): unset is fine, otherwise\n * the value must name an existing, named field instance whose type is poll-eligible. Payload skips\n * the validate while the poll is disabled (the field's `admin.condition`), so a stale reference on\n * a disabled poll never blocks a save.\n */\nexport const buildValidateResultsField =\n\t(eligibleTypes: readonly string[]) =>\n\t(value: unknown, { data, req }: { data?: unknown; req: PayloadRequest }): string | true => {\n\t\tif (typeof value !== 'string' || value.length === 0) {\n\t\t\treturn true\n\t\t}\n\t\tconst fields =\n\t\t\tdata && typeof data === 'object' ? (data as Record<string, unknown>).fields : undefined\n\t\treturn fieldNamesOfType(fields, eligibleTypes).includes(value)\n\t\t\t? true\n\t\t\t: asTranslate(req.t)(keys.validationResultsFieldUnknown)\n\t}\n"],"mappings":";;;;;AAOA,MAAa,qBAAqB,aACjC,CAAC,GAAG,SAAS,OAAO,CAAC,EACnB,QAAQ,eAAe,WAAW,iBAAiB,IAAI,EACvD,KAAK,eAAe,WAAW,IAAI;;;;;;;;AAStC,MAAa,6BACX,mBACA,OAAgB,EAAE,MAAM,UAAkE;CAC1F,IAAI,OAAO,UAAU,YAAY,MAAM,WAAW,GACjD,OAAO;CAIR,OAAO,iBADN,QAAQ,OAAO,SAAS,WAAY,KAAiC,SAAS,KAAA,GAC/C,aAAa,EAAE,SAAS,KAAK,IAC1D,OACA,YAAY,IAAI,CAAC,EAAE,KAAK,6BAA6B;AACzD"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isNamedField } from "../fields/fieldKey.js";
|
|
1
2
|
//#region src/prefill/valuesFromSearchParams.ts
|
|
2
3
|
const TRUTHY = new Set([
|
|
3
4
|
"true",
|
|
@@ -24,7 +25,7 @@ const coerce = (kind, raw, all) => {
|
|
|
24
25
|
const valuesFromSearchParams = (params, fields, registry, options = {}) => {
|
|
25
26
|
const isSearch = params instanceof URLSearchParams;
|
|
26
27
|
const paramKeys = isSearch ? [...new Set(params.keys())] : Object.keys(params);
|
|
27
|
-
const byName = new Map(fields.map((field) => [field.name, field]));
|
|
28
|
+
const byName = new Map(fields.filter(isNamedField).map((field) => [field.name, field]));
|
|
28
29
|
const result = {};
|
|
29
30
|
for (const param of paramKeys) {
|
|
30
31
|
const fieldName = options.map?.[param] ?? param;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"valuesFromSearchParams.js","names":[],"sources":["../../src/prefill/valuesFromSearchParams.ts"],"sourcesContent":["import type { FieldTypeRegistry } from '../fields/registry'\nimport type { FormFieldValueKind } from '../fields/types'\nimport type { FormFieldInstance } from '../submissions/types'\n\nexport type PrefillOptions = {\n\t/** Map a query-param name to a field name. Unmapped params use their own name. */\n\tmap?: Record<string, string>\n\t/** If set, only these field names may be prefilled. */\n\tallow?: string[]\n\t/** These field names may never be prefilled. */\n\tdeny?: string[]\n}\n\nconst TRUTHY = new Set(['true', '1', 'on', 'yes'])\n\nconst coerce = (kind: FormFieldValueKind, raw: string, all: string[]): unknown => {\n\tswitch (kind) {\n\t\tcase 'number': {\n\t\t\tconst n = Number(raw)\n\t\t\treturn Number.isNaN(n) ? undefined : n\n\t\t}\n\t\tcase 'boolean':\n\t\t\treturn TRUTHY.has(raw.toLowerCase())\n\t\tcase 'text[]':\n\t\t\treturn all\n\t\tdefault:\n\t\t\treturn raw\n\t}\n}\n\n/**\n * Map URL/query params to typed initial values for KNOWN fields only, coerced by each field's value\n * kind. Unknown, denied, or un-allowed params are ignored; invalid numbers are dropped. Prefilled\n * values are never trusted -- they still validate on submit. Pass the result to `<Form initialValues>`.\n */\n// biome-ignore lint/complexity/useMaxParams: four positional args are the minimal surface (params, fields, registry, options)\nexport const valuesFromSearchParams = (\n\tparams: URLSearchParams | Record<string, string>,\n\tfields: FormFieldInstance[],\n\tregistry: FieldTypeRegistry,\n\toptions: PrefillOptions = {}\n): Record<string, unknown> => {\n\tconst isSearch = params instanceof URLSearchParams\n\tconst paramKeys = isSearch ? [...new Set(params.keys())] : Object.keys(params)\n\tconst byName = new Map(fields.map((field) => [field.name, field]))\n\tconst result: Record<string, unknown> = {}\n\n\tfor (const param of paramKeys) {\n\t\tconst fieldName = options.map?.[param] ?? param\n\n\t\tif (options.allow && !options.allow.includes(fieldName)) {\n\t\t\tcontinue\n\t\t}\n\t\tif (options.deny?.includes(fieldName)) {\n\t\t\tcontinue\n\t\t}\n\n\t\tconst field = byName.get(fieldName)\n\t\tconst definition = field && registry.get(field.blockType)\n\t\t// 'none'-kind (display-only) fields carry no value, so a param under their name is ignored.\n\t\tif (!field || !definition || definition.value === 'none') {\n\t\t\tcontinue\n\t\t}\n\n\t\tconst all = isSearch ? params.getAll(param) : [params[param] as string]\n\t\tconst value = coerce(definition.value, all[0] ?? '', all)\n\t\tif (value !== undefined) {\n\t\t\tresult[fieldName] = value\n\t\t}\n\t}\n\n\treturn result\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"valuesFromSearchParams.js","names":[],"sources":["../../src/prefill/valuesFromSearchParams.ts"],"sourcesContent":["import { isNamedField } from '../fields/fieldKey'\nimport type { FieldTypeRegistry } from '../fields/registry'\nimport type { FormFieldValueKind } from '../fields/types'\nimport type { FormFieldInstance } from '../submissions/types'\n\nexport type PrefillOptions = {\n\t/** Map a query-param name to a field name. Unmapped params use their own name. */\n\tmap?: Record<string, string>\n\t/** If set, only these field names may be prefilled. */\n\tallow?: string[]\n\t/** These field names may never be prefilled. */\n\tdeny?: string[]\n}\n\nconst TRUTHY = new Set(['true', '1', 'on', 'yes'])\n\nconst coerce = (kind: FormFieldValueKind, raw: string, all: string[]): unknown => {\n\tswitch (kind) {\n\t\tcase 'number': {\n\t\t\tconst n = Number(raw)\n\t\t\treturn Number.isNaN(n) ? undefined : n\n\t\t}\n\t\tcase 'boolean':\n\t\t\treturn TRUTHY.has(raw.toLowerCase())\n\t\tcase 'text[]':\n\t\t\treturn all\n\t\tdefault:\n\t\t\treturn raw\n\t}\n}\n\n/**\n * Map URL/query params to typed initial values for KNOWN fields only, coerced by each field's value\n * kind. Unknown, denied, or un-allowed params are ignored; invalid numbers are dropped. Prefilled\n * values are never trusted -- they still validate on submit. Pass the result to `<Form initialValues>`.\n */\n// biome-ignore lint/complexity/useMaxParams: four positional args are the minimal surface (params, fields, registry, options)\nexport const valuesFromSearchParams = (\n\tparams: URLSearchParams | Record<string, string>,\n\tfields: FormFieldInstance[],\n\tregistry: FieldTypeRegistry,\n\toptions: PrefillOptions = {}\n): Record<string, unknown> => {\n\tconst isSearch = params instanceof URLSearchParams\n\tconst paramKeys = isSearch ? [...new Set(params.keys())] : Object.keys(params)\n\tconst byName = new Map(fields.filter(isNamedField).map((field) => [field.name, field]))\n\tconst result: Record<string, unknown> = {}\n\n\tfor (const param of paramKeys) {\n\t\tconst fieldName = options.map?.[param] ?? param\n\n\t\tif (options.allow && !options.allow.includes(fieldName)) {\n\t\t\tcontinue\n\t\t}\n\t\tif (options.deny?.includes(fieldName)) {\n\t\t\tcontinue\n\t\t}\n\n\t\tconst field = byName.get(fieldName)\n\t\tconst definition = field && registry.get(field.blockType)\n\t\t// 'none'-kind (display-only) fields carry no value, so a param under their name is ignored.\n\t\tif (!field || !definition || definition.value === 'none') {\n\t\t\tcontinue\n\t\t}\n\n\t\tconst all = isSearch ? params.getAll(param) : [params[param] as string]\n\t\tconst value = coerce(definition.value, all[0] ?? '', all)\n\t\tif (value !== undefined) {\n\t\t\tresult[fieldName] = value\n\t\t}\n\t}\n\n\treturn result\n}\n"],"mappings":";;AAcA,MAAM,SAAS,IAAI,IAAI;CAAC;CAAQ;CAAK;CAAM;AAAK,CAAC;AAEjD,MAAM,UAAU,MAA0B,KAAa,QAA2B;CACjF,QAAQ,MAAR;EACC,KAAK,UAAU;GACd,MAAM,IAAI,OAAO,GAAG;GACpB,OAAO,OAAO,MAAM,CAAC,IAAI,KAAA,IAAY;EACtC;EACA,KAAK,WACJ,OAAO,OAAO,IAAI,IAAI,YAAY,CAAC;EACpC,KAAK,UACJ,OAAO;EACR,SACC,OAAO;CACT;AACD;;;;;;AAQA,MAAa,0BACZ,QACA,QACA,UACA,UAA0B,CAAC,MACE;CAC7B,MAAM,WAAW,kBAAkB;CACnC,MAAM,YAAY,WAAW,CAAC,GAAG,IAAI,IAAI,OAAO,KAAK,CAAC,CAAC,IAAI,OAAO,KAAK,MAAM;CAC7E,MAAM,SAAS,IAAI,IAAI,OAAO,OAAO,YAAY,EAAE,KAAK,UAAU,CAAC,MAAM,MAAM,KAAK,CAAC,CAAC;CACtF,MAAM,SAAkC,CAAC;CAEzC,KAAK,MAAM,SAAS,WAAW;EAC9B,MAAM,YAAY,QAAQ,MAAM,UAAU;EAE1C,IAAI,QAAQ,SAAS,CAAC,QAAQ,MAAM,SAAS,SAAS,GACrD;EAED,IAAI,QAAQ,MAAM,SAAS,SAAS,GACnC;EAGD,MAAM,QAAQ,OAAO,IAAI,SAAS;EAClC,MAAM,aAAa,SAAS,SAAS,IAAI,MAAM,SAAS;EAExD,IAAI,CAAC,SAAS,CAAC,cAAc,WAAW,UAAU,QACjD;EAGD,MAAM,MAAM,WAAW,OAAO,OAAO,KAAK,IAAI,CAAC,OAAO,MAAgB;EACtE,MAAM,QAAQ,OAAO,WAAW,OAAO,IAAI,MAAM,IAAI,GAAG;EACxD,IAAI,UAAU,KAAA,GACb,OAAO,aAAa;CAEtB;CAEA,OAAO;AACR"}
|
package/dist/react/Form.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { AnyFormFieldDefinition } from "../fields/types.js";
|
|
2
|
-
import {
|
|
2
|
+
import { FormButtonSettings, FormDocument, FormPollSettings, FormResponseSettings } from "../form/types.js";
|
|
3
3
|
import { RendererTranslate } from "./contract.js";
|
|
4
4
|
import { FormEventSink } from "../events/types.js";
|
|
5
5
|
import { AnyValidationRuleDefinition } from "../validation/types.js";
|
|
@@ -23,10 +23,10 @@ type FormProps = {
|
|
|
23
23
|
events?: FormEventSink;
|
|
24
24
|
t?: RendererTranslate;
|
|
25
25
|
locale?: string;
|
|
26
|
-
layout?: boolean; /** Submit button label. Precedence: this prop, then the form's `
|
|
27
|
-
submitLabel?: string; /** "Next" button label for multi-step forms.
|
|
28
|
-
nextLabel?: string; /** "Back" button label for multi-step forms.
|
|
29
|
-
|
|
26
|
+
layout?: boolean; /** Submit button label. Precedence: this prop, then the form's `buttons.submitLabel`, then the translated default. */
|
|
27
|
+
submitLabel?: string; /** "Next" button label for multi-step forms. Precedence: this prop, then the form's `buttons.nextLabel`, then the translated default. */
|
|
28
|
+
nextLabel?: string; /** "Back" button label for multi-step forms. Precedence: this prop, then the form's `buttons.prevLabel`, then the translated default. */
|
|
29
|
+
prevLabel?: string; /** Label for the overlay close control (modal/drawer). */
|
|
30
30
|
closeLabel?: string;
|
|
31
31
|
successMessage?: string; /** Active presentation: a name into the registry or an inline presentation. Defaults to `'page'` when omitted. */
|
|
32
32
|
presentation?: string | FormPresentation; /** Per-render presentation overrides merged onto the defaults (add, replace, or `false` to remove). */
|
|
@@ -34,8 +34,8 @@ type FormProps = {
|
|
|
34
34
|
onClose?: () => void;
|
|
35
35
|
/**
|
|
36
36
|
* Accessible name for an overlay surface (modal/drawer). Hosts choosing between a trigger
|
|
37
|
-
* label and the form's own
|
|
38
|
-
*
|
|
37
|
+
* label and the form's own admin title should prefer `form.title` when set, falling back to
|
|
38
|
+
* their own label otherwise.
|
|
39
39
|
*/
|
|
40
40
|
title?: string; /** Seed initial field values (e.g. from `valuesFromSearchParams`). Still validated on submit. */
|
|
41
41
|
initialValues?: Record<string, unknown>; /** Honeypot decoy (on by default). `false` removes it; `{ name }` matches a customized server `spam.honeypot.fieldName`. */
|
|
@@ -68,7 +68,7 @@ declare const Form: ({
|
|
|
68
68
|
layout,
|
|
69
69
|
submitLabel,
|
|
70
70
|
nextLabel,
|
|
71
|
-
|
|
71
|
+
prevLabel,
|
|
72
72
|
closeLabel,
|
|
73
73
|
successMessage,
|
|
74
74
|
presentation,
|
package/dist/react/Form.js
CHANGED
|
@@ -4,11 +4,12 @@ import { keys } from "../translations/keys.js";
|
|
|
4
4
|
import { serializeBody } from "../actions/body/serializeBody.js";
|
|
5
5
|
import { noopEventSink } from "../events/noopSink.js";
|
|
6
6
|
import { CAPTCHA_TOKEN_KEY } from "../spam/constants.js";
|
|
7
|
+
import { fieldKey, isNamedField } from "../fields/fieldKey.js";
|
|
7
8
|
import { calcExpressionOf, computeCalcFields } from "../calc/computeCalcFields.js";
|
|
8
9
|
import { evaluateCondition } from "../conditions/evaluate.js";
|
|
9
10
|
import { en } from "../translations/en.js";
|
|
10
11
|
import { defaultPresentationDescriptors } from "../presentations/defaults.js";
|
|
11
|
-
import { buildRecallResolver } from "../recall/resolver.js";
|
|
12
|
+
import { buildRecallResolver, descriptorsFor } from "../recall/resolver.js";
|
|
12
13
|
import { firstStepId, isTerminalStepId, resolveNextStepId, stepFieldNames } from "../flow/engine.js";
|
|
13
14
|
import { cn } from "./cn.js";
|
|
14
15
|
import { makeTranslate } from "../translations/makeTranslate.js";
|
|
@@ -31,6 +32,8 @@ import { jsx, jsxs } from "react/jsx-runtime";
|
|
|
31
32
|
import { createElement, useCallback, useEffect, useId, useMemo, useReducer, useRef, useState } from "react";
|
|
32
33
|
//#region src/react/Form.tsx
|
|
33
34
|
const isEmpty = (value) => value == null || value === "" || Array.isArray(value) && value.length === 0;
|
|
35
|
+
/** A stored button label counts only when it is a non-empty string; anything else falls through. */
|
|
36
|
+
const storedLabel = (value) => typeof value === "string" && value.length > 0 ? value : void 0;
|
|
34
37
|
const FIELD_WIDTHS = new Set([
|
|
35
38
|
"full",
|
|
36
39
|
"half",
|
|
@@ -39,7 +42,7 @@ const FIELD_WIDTHS = new Set([
|
|
|
39
42
|
]);
|
|
40
43
|
const FieldHost = ({ field, renderer, locale, t }) => {
|
|
41
44
|
const id = useId();
|
|
42
|
-
const { value, errors,
|
|
45
|
+
const { value, errors, setValue, onBlur } = useField(field.name);
|
|
43
46
|
return createElement(renderer, {
|
|
44
47
|
field,
|
|
45
48
|
id,
|
|
@@ -48,7 +51,6 @@ const FieldHost = ({ field, renderer, locale, t }) => {
|
|
|
48
51
|
onChange: setValue,
|
|
49
52
|
onBlur,
|
|
50
53
|
errors,
|
|
51
|
-
warnings,
|
|
52
54
|
required: Boolean(field.required),
|
|
53
55
|
locale,
|
|
54
56
|
t
|
|
@@ -64,15 +66,32 @@ const CalcFieldHost = ({ field, renderer, value, locale, t }) => {
|
|
|
64
66
|
onChange: () => {},
|
|
65
67
|
onBlur: () => {},
|
|
66
68
|
errors: [],
|
|
67
|
-
warnings: [],
|
|
68
69
|
required: false,
|
|
69
70
|
disabled: true,
|
|
70
71
|
locale,
|
|
71
72
|
t
|
|
72
73
|
});
|
|
73
74
|
};
|
|
75
|
+
/**
|
|
76
|
+
* Hosts a nameless (bare) display block, e.g. a message: no `useField` binding at all. The
|
|
77
|
+
* renderer reads only the instance and the form context; `name` is the row key for consistency.
|
|
78
|
+
*/
|
|
79
|
+
const StaticFieldHost = ({ field, renderer, locale, t }) => {
|
|
80
|
+
return createElement(renderer, {
|
|
81
|
+
field,
|
|
82
|
+
id: useId(),
|
|
83
|
+
name: fieldKey(field),
|
|
84
|
+
value: void 0,
|
|
85
|
+
onChange: () => {},
|
|
86
|
+
onBlur: () => {},
|
|
87
|
+
errors: [],
|
|
88
|
+
required: false,
|
|
89
|
+
locale,
|
|
90
|
+
t
|
|
91
|
+
});
|
|
92
|
+
};
|
|
74
93
|
/** The headless form controller: state, progressive client validation, conditional visibility, submission, events. */
|
|
75
|
-
const Form = ({ form, fieldTypes, rules, renderers, apiRoute, onSubmit, onSuccess, onError, events, t, locale = "en", layout, submitLabel, nextLabel,
|
|
94
|
+
const Form = ({ form, fieldTypes, rules, renderers, apiRoute, onSubmit, onSuccess, onError, events, t, locale = "en", layout, submitLabel, nextLabel, prevLabel, closeLabel = "Close", successMessage = "Thank you.", presentation, presentations, onClose, title, initialValues, honeypot, captchaToken, children, className, renderSubmit, renderNext, renderBack, submitButtonClassName, nextButtonClassName, backButtonClassName }) => {
|
|
76
95
|
const honeypotName = honeypot === false ? null : honeypot?.name ?? "website";
|
|
77
96
|
const honeypotRef = useRef(null);
|
|
78
97
|
const registry = useMemo(() => buildFieldTypeRegistry(fieldTypes), [fieldTypes]);
|
|
@@ -80,18 +99,18 @@ const Form = ({ form, fieldTypes, rules, renderers, apiRoute, onSubmit, onSucces
|
|
|
80
99
|
const rendererRegistry = useMemo(() => resolveRenderers(defaultRenderers, renderers), [renderers]);
|
|
81
100
|
const presentationRegistry = useMemo(() => resolvePresentations(defaultPresentations, presentations), [presentations]);
|
|
82
101
|
const activePresentation = typeof presentation === "object" ? presentation : presentationRegistry.get(presentation ?? "page") ?? presentationRegistry.get("page") ?? defaultPresentationDescriptors.page;
|
|
83
|
-
const fieldsByName = useMemo(() => new Map(form.fields.map((field) => [field.name, field])), [form.fields]);
|
|
102
|
+
const fieldsByName = useMemo(() => new Map(form.fields.filter(isNamedField).map((field) => [field.name, field])), [form.fields]);
|
|
84
103
|
const translate = useMemo(() => t ?? makeTranslate(en), [t]);
|
|
85
|
-
const
|
|
104
|
+
const docButtons = form.buttons;
|
|
86
105
|
const labels = useMemo(() => ({
|
|
87
|
-
|
|
88
|
-
next: nextLabel ?? translate(keys.formNext),
|
|
89
|
-
submit: submitLabel ??
|
|
106
|
+
prev: prevLabel ?? storedLabel(docButtons?.prevLabel) ?? translate(keys.formBack),
|
|
107
|
+
next: nextLabel ?? storedLabel(docButtons?.nextLabel) ?? translate(keys.formNext),
|
|
108
|
+
submit: submitLabel ?? storedLabel(docButtons?.submitLabel) ?? translate(keys.formSubmit)
|
|
90
109
|
}), [
|
|
91
|
-
|
|
110
|
+
prevLabel,
|
|
92
111
|
nextLabel,
|
|
93
112
|
submitLabel,
|
|
94
|
-
|
|
113
|
+
docButtons,
|
|
95
114
|
translate
|
|
96
115
|
]);
|
|
97
116
|
const sinkRef = useRef(noopEventSink);
|
|
@@ -116,7 +135,7 @@ const Form = ({ form, fieldTypes, rules, renderers, apiRoute, onSubmit, onSucces
|
|
|
116
135
|
locale,
|
|
117
136
|
translate
|
|
118
137
|
]);
|
|
119
|
-
const flow = form.flow && form.flow.steps.length >= 2 ? form.flow : void 0;
|
|
138
|
+
const flow = form.multistep === true && form.flow && form.flow.steps.length >= 2 ? form.flow : void 0;
|
|
120
139
|
const [currentStepId, setCurrentStepId] = useState(() => flow ? firstStepId(flow) : void 0);
|
|
121
140
|
const [history, setHistory] = useState([]);
|
|
122
141
|
const startedRef = useRef(false);
|
|
@@ -142,8 +161,7 @@ const Form = ({ form, fieldTypes, rules, renderers, apiRoute, onSubmit, onSucces
|
|
|
142
161
|
rawDispatch({
|
|
143
162
|
type: "SET_FIELD_ISSUES",
|
|
144
163
|
name,
|
|
145
|
-
errors: []
|
|
146
|
-
warnings: []
|
|
164
|
+
errors: []
|
|
147
165
|
});
|
|
148
166
|
return;
|
|
149
167
|
}
|
|
@@ -155,12 +173,11 @@ const Form = ({ form, fieldTypes, rules, renderers, apiRoute, onSubmit, onSucces
|
|
|
155
173
|
answers,
|
|
156
174
|
locale,
|
|
157
175
|
t: translate
|
|
158
|
-
}).then(({ errors
|
|
176
|
+
}).then(({ errors }) => {
|
|
159
177
|
rawDispatch({
|
|
160
178
|
type: "SET_FIELD_ISSUES",
|
|
161
179
|
name,
|
|
162
|
-
errors
|
|
163
|
-
warnings
|
|
180
|
+
errors
|
|
164
181
|
});
|
|
165
182
|
const [firstError] = errors;
|
|
166
183
|
if (firstError !== void 0) emitFormEvent(sinkRef.current, formIdRef.current, {
|
|
@@ -178,15 +195,25 @@ const Form = ({ form, fieldTypes, rules, renderers, apiRoute, onSubmit, onSucces
|
|
|
178
195
|
translate
|
|
179
196
|
]);
|
|
180
197
|
const visible = visibleFields(form.fields, effectiveValues);
|
|
181
|
-
/**
|
|
182
|
-
const
|
|
198
|
+
/** Visible, answered named fields. Display-only ('none' kind) and nameless (bare) fields never contribute. */
|
|
199
|
+
const answerableFields = () => visibleFields(form.fields, effectiveValues).filter((field) => registry.get(field.blockType)?.value !== "none").filter(isNamedField).filter((field) => !isEmpty(effectiveValues[field.name]));
|
|
200
|
+
/** Answered visible fields as raw submission values, sent to the server on submit. */
|
|
201
|
+
const answeredValues = () => answerableFields().map((field) => ({
|
|
183
202
|
field: field.name,
|
|
184
203
|
value: effectiveValues[field.name]
|
|
185
204
|
}));
|
|
186
|
-
|
|
205
|
+
/**
|
|
206
|
+
* Same fields, formatted via `recall` (option labels, Yes/No, localized dates): recall-fidelity
|
|
207
|
+
* values for client-rendered templates, matching what the server gives email-team's body.
|
|
208
|
+
*/
|
|
209
|
+
const formattedValues = () => answerableFields().map((field) => ({
|
|
210
|
+
field: field.name,
|
|
211
|
+
value: recall(field.name)
|
|
212
|
+
}));
|
|
213
|
+
const stepVisible = (flow && currentStepId ? stepFieldNames(flow, currentStepId) : []).map((key) => visible.find((field) => fieldKey(field) === key)).filter((field) => Boolean(field));
|
|
187
214
|
const goNext = async () => {
|
|
188
215
|
if (!flow || !currentStepId) return;
|
|
189
|
-
const results = await Promise.all(stepVisible.filter((field) => !calcExpressionOf(field)).filter((field) => registry.get(field.blockType)?.value !== "none").filter((field) => evaluateCondition(field.validateWhen, effectiveValues)).map(async (field) => ({
|
|
216
|
+
const results = await Promise.all(stepVisible.filter((field) => !calcExpressionOf(field)).filter((field) => registry.get(field.blockType)?.value !== "none").filter(isNamedField).filter((field) => evaluateCondition(field.validateWhen, effectiveValues)).map(async (field) => ({
|
|
190
217
|
field,
|
|
191
218
|
...await validateFieldValue({
|
|
192
219
|
field,
|
|
@@ -207,8 +234,7 @@ const Form = ({ form, fieldTypes, rules, renderers, apiRoute, onSubmit, onSucces
|
|
|
207
234
|
rawDispatch({
|
|
208
235
|
type: "SET_FIELD_ISSUES",
|
|
209
236
|
name: result.field.name,
|
|
210
|
-
errors: result.errors
|
|
211
|
-
warnings: result.warnings
|
|
237
|
+
errors: result.errors
|
|
212
238
|
});
|
|
213
239
|
if (result.errors.length > 0) hasError = true;
|
|
214
240
|
}
|
|
@@ -258,7 +284,7 @@ const Form = ({ form, fieldTypes, rules, renderers, apiRoute, onSubmit, onSucces
|
|
|
258
284
|
if (submittingRef.current) return;
|
|
259
285
|
submittingRef.current = true;
|
|
260
286
|
const visible = visibleFields(form.fields, effectiveValues);
|
|
261
|
-
const results = await Promise.all(visible.filter((field) => !calcExpressionOf(field)).filter((field) => registry.get(field.blockType)?.value !== "none").filter((field) => evaluateCondition(field.validateWhen, effectiveValues)).map(async (field) => ({
|
|
287
|
+
const results = await Promise.all(visible.filter((field) => !calcExpressionOf(field)).filter((field) => registry.get(field.blockType)?.value !== "none").filter(isNamedField).filter((field) => evaluateCondition(field.validateWhen, effectiveValues)).map(async (field) => ({
|
|
262
288
|
field,
|
|
263
289
|
...await validateFieldValue({
|
|
264
290
|
field,
|
|
@@ -271,22 +297,18 @@ const Form = ({ form, fieldTypes, rules, renderers, apiRoute, onSubmit, onSucces
|
|
|
271
297
|
})
|
|
272
298
|
})));
|
|
273
299
|
const errors = {};
|
|
274
|
-
const
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
message: firstError
|
|
283
|
-
});
|
|
284
|
-
}
|
|
285
|
-
if (result.warnings.length > 0) warnings[result.field.name] = result.warnings;
|
|
300
|
+
for (const result of results) if (result.errors.length > 0) {
|
|
301
|
+
errors[result.field.name] = result.errors;
|
|
302
|
+
const [firstError] = result.errors;
|
|
303
|
+
if (firstError !== void 0) emitFormEvent(sinkRef.current, formIdRef.current, {
|
|
304
|
+
type: "field.errored",
|
|
305
|
+
field: result.field.name,
|
|
306
|
+
message: firstError
|
|
307
|
+
});
|
|
286
308
|
}
|
|
287
|
-
for (const field of visible.filter((f) => f.blockType === "repeater")) {
|
|
309
|
+
for (const field of visible.filter((f) => f.blockType === "repeater" && isNamedField(f))) {
|
|
288
310
|
const rows = Array.isArray(effectiveValues[field.name]) ? effectiveValues[field.name] : [];
|
|
289
|
-
const subFields = Array.isArray(field.subFields) ? field.subFields : [];
|
|
311
|
+
const subFields = (Array.isArray(field.subFields) ? field.subFields : []).filter(isNamedField);
|
|
290
312
|
for (let rowIndex = 0; rowIndex < rows.length; rowIndex++) {
|
|
291
313
|
const row = rows[rowIndex] ?? {};
|
|
292
314
|
for (const subField of subFields) {
|
|
@@ -303,14 +325,12 @@ const Form = ({ form, fieldTypes, rules, renderers, apiRoute, onSubmit, onSucces
|
|
|
303
325
|
});
|
|
304
326
|
const compositeKey = `${field.name}[${rowIndex}].${subField.name}`;
|
|
305
327
|
if (subResult.errors.length > 0) errors[compositeKey] = subResult.errors;
|
|
306
|
-
if (subResult.warnings.length > 0) warnings[compositeKey] = subResult.warnings;
|
|
307
328
|
}
|
|
308
329
|
}
|
|
309
330
|
}
|
|
310
331
|
rawDispatch({
|
|
311
332
|
type: "SET_ALL_ISSUES",
|
|
312
|
-
errors
|
|
313
|
-
warnings
|
|
333
|
+
errors
|
|
314
334
|
});
|
|
315
335
|
if (Object.keys(errors).length > 0) {
|
|
316
336
|
submittingRef.current = false;
|
|
@@ -352,8 +372,7 @@ const Form = ({ form, fieldTypes, rules, renderers, apiRoute, onSubmit, onSucces
|
|
|
352
372
|
} else {
|
|
353
373
|
if (result.fieldErrors) rawDispatch({
|
|
354
374
|
type: "SET_ALL_ISSUES",
|
|
355
|
-
errors: result.fieldErrors
|
|
356
|
-
warnings: {}
|
|
375
|
+
errors: result.fieldErrors
|
|
357
376
|
});
|
|
358
377
|
const message = result.message ?? "Submission failed";
|
|
359
378
|
rawDispatch({
|
|
@@ -364,6 +383,7 @@ const Form = ({ form, fieldTypes, rules, renderers, apiRoute, onSubmit, onSucces
|
|
|
364
383
|
}
|
|
365
384
|
};
|
|
366
385
|
const contextValue = {
|
|
386
|
+
form,
|
|
367
387
|
state,
|
|
368
388
|
dispatch,
|
|
369
389
|
validateField,
|
|
@@ -418,8 +438,8 @@ const Form = ({ form, fieldTypes, rules, renderers, apiRoute, onSubmit, onSucces
|
|
|
418
438
|
if (state.submitted) {
|
|
419
439
|
const responseMessage = form.response?.type === "message" || form.response?.type == null ? form.response?.message : void 0;
|
|
420
440
|
const responseHtml = responseMessage ? serializeBody(responseMessage, {
|
|
421
|
-
values:
|
|
422
|
-
descriptors:
|
|
441
|
+
values: formattedValues(),
|
|
442
|
+
descriptors: descriptorsFor(answerableFields())
|
|
423
443
|
}) : void 0;
|
|
424
444
|
return /* @__PURE__ */ jsx(FormContext.Provider, {
|
|
425
445
|
value: contextValue,
|
|
@@ -439,11 +459,6 @@ const Form = ({ form, fieldTypes, rules, renderers, apiRoute, onSubmit, onSucces
|
|
|
439
459
|
});
|
|
440
460
|
}
|
|
441
461
|
const rendered = (flow ? stepVisible : visible).filter((field) => field.hidden !== true && field.calcDisplay !== false);
|
|
442
|
-
const displayTitleText = form.display?.showTitle && typeof form.display.title === "string" && form.display.title.length > 0 ? interpolate(form.display.title, recall) : void 0;
|
|
443
|
-
const displayIntroHtml = form.display?.intro ? serializeBody(form.display.intro, {
|
|
444
|
-
values: answeredValues(),
|
|
445
|
-
descriptors: []
|
|
446
|
-
}) : "";
|
|
447
462
|
return /* @__PURE__ */ jsx(FormContext.Provider, {
|
|
448
463
|
value: contextValue,
|
|
449
464
|
children: wrap(/* @__PURE__ */ jsxs("form", {
|
|
@@ -457,14 +472,6 @@ const Form = ({ form, fieldTypes, rules, renderers, apiRoute, onSubmit, onSucces
|
|
|
457
472
|
name: honeypotName,
|
|
458
473
|
inputRef: honeypotRef
|
|
459
474
|
}) : null,
|
|
460
|
-
displayTitleText ? /* @__PURE__ */ jsx("h2", {
|
|
461
|
-
className: "fb-form__title",
|
|
462
|
-
children: displayTitleText
|
|
463
|
-
}) : null,
|
|
464
|
-
displayIntroHtml ? /* @__PURE__ */ jsx("div", {
|
|
465
|
-
className: "fb-form__intro",
|
|
466
|
-
dangerouslySetInnerHTML: { __html: displayIntroHtml }
|
|
467
|
-
}) : null,
|
|
468
475
|
/* @__PURE__ */ jsx(FormLayout, {
|
|
469
476
|
enabled: layout !== false,
|
|
470
477
|
children: rendered.map((field) => {
|
|
@@ -474,10 +481,15 @@ const Form = ({ form, fieldTypes, rules, renderers, apiRoute, onSubmit, onSucces
|
|
|
474
481
|
const recalledField = applyRecall(field, recall);
|
|
475
482
|
return /* @__PURE__ */ jsx("div", {
|
|
476
483
|
...widthProps(width),
|
|
477
|
-
children:
|
|
484
|
+
children: !isNamedField(recalledField) ? /* @__PURE__ */ jsx(StaticFieldHost, {
|
|
485
|
+
field: recalledField,
|
|
486
|
+
renderer,
|
|
487
|
+
locale,
|
|
488
|
+
t: translate
|
|
489
|
+
}) : calcExpressionOf(recalledField) ? /* @__PURE__ */ jsx(CalcFieldHost, {
|
|
478
490
|
field: recalledField,
|
|
479
491
|
renderer,
|
|
480
|
-
value: effectiveValues[
|
|
492
|
+
value: effectiveValues[recalledField.name],
|
|
481
493
|
locale,
|
|
482
494
|
t: translate
|
|
483
495
|
}) : /* @__PURE__ */ jsx(FieldHost, {
|
|
@@ -486,7 +498,7 @@ const Form = ({ form, fieldTypes, rules, renderers, apiRoute, onSubmit, onSucces
|
|
|
486
498
|
locale,
|
|
487
499
|
t: translate
|
|
488
500
|
})
|
|
489
|
-
}, field
|
|
501
|
+
}, fieldKey(field));
|
|
490
502
|
})
|
|
491
503
|
}),
|
|
492
504
|
state.submitError ? /* @__PURE__ */ jsx("p", {
|