@10x-media/form-builder 0.1.0-beta.2 → 0.1.0-beta.21
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 +360 -0
- package/README.md +7 -5
- package/dist/actions/assertNoBlockCollision.js +18 -0
- package/dist/actions/assertNoBlockCollision.js.map +1 -0
- package/dist/actions/body/converters.d.ts +20 -0
- package/dist/actions/body/converters.js +57 -0
- package/dist/actions/body/converters.js.map +1 -0
- package/dist/actions/body/escapeHtml.d.ts +6 -0
- package/dist/actions/body/escapeHtml.js +14 -0
- package/dist/actions/body/escapeHtml.js.map +1 -0
- package/dist/actions/body/serializeBody.d.ts +55 -0
- package/dist/actions/body/serializeBody.js +78 -0
- package/dist/actions/body/serializeBody.js.map +1 -0
- package/dist/actions/body/serializeSlate.js +31 -0
- package/dist/actions/body/serializeSlate.js.map +1 -0
- 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/body/wildcards.d.ts +10 -0
- package/dist/actions/body/wildcards.js +33 -0
- package/dist/actions/body/wildcards.js.map +1 -0
- package/dist/actions/buildActionBlocks.js +12 -9
- package/dist/actions/buildActionBlocks.js.map +1 -1
- package/dist/actions/builtin/confirmation.js +47 -43
- package/dist/actions/builtin/confirmation.js.map +1 -1
- package/dist/actions/builtin/emailAction.d.ts +20 -0
- package/dist/actions/builtin/emailAction.js +120 -0
- package/dist/actions/builtin/emailAction.js.map +1 -0
- package/dist/actions/builtin/emailTeam.js +20 -38
- package/dist/actions/builtin/emailTeam.js.map +1 -1
- package/dist/actions/builtin/index.d.ts +16 -1
- package/dist/actions/builtin/index.js +21 -7
- package/dist/actions/builtin/index.js.map +1 -1
- package/dist/actions/builtin/signedWebhook.js +6 -2
- package/dist/actions/builtin/signedWebhook.js.map +1 -1
- package/dist/actions/defineAction.d.ts +17 -5
- package/dist/actions/defineAction.js.map +1 -1
- package/dist/actions/dispatch.js +51 -6
- package/dist/actions/dispatch.js.map +1 -1
- package/dist/actions/dispatchContext.js +13 -0
- package/dist/actions/dispatchContext.js.map +1 -0
- package/dist/actions/emailRecipients.d.ts +12 -0
- package/dist/actions/emailRecipients.js +146 -0
- package/dist/actions/emailRecipients.js.map +1 -0
- package/dist/actions/fromAddresses.d.ts +37 -0
- package/dist/actions/fromAddresses.js +131 -0
- package/dist/actions/fromAddresses.js.map +1 -0
- 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/registry.d.ts +2 -1
- package/dist/actions/registry.js +5 -7
- package/dist/actions/registry.js.map +1 -1
- package/dist/actions/runActions.js +10 -1
- package/dist/actions/runActions.js.map +1 -1
- package/dist/actions/task.js +47 -16
- 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 +41 -6
- package/dist/aggregation/resolveResultsRequest.js +97 -11
- package/dist/aggregation/resolveResultsRequest.js.map +1 -1
- package/dist/calc/computeCalcFields.d.ts +5 -3
- package/dist/calc/computeCalcFields.js +6 -4
- package/dist/calc/computeCalcFields.js.map +1 -1
- package/dist/calc/evaluate.d.ts +26 -3
- package/dist/calc/evaluate.js +34 -13
- package/dist/calc/evaluate.js.map +1 -1
- package/dist/calc/formatCalc.d.ts +11 -0
- package/dist/calc/formatCalc.js +35 -0
- package/dist/calc/formatCalc.js.map +1 -0
- package/dist/calc/formatCalcValue.d.ts +17 -0
- package/dist/calc/formatCalcValue.js +17 -0
- package/dist/calc/formatCalcValue.js.map +1 -0
- package/dist/calc/normalizeCalc.d.ts +17 -3
- package/dist/calc/normalizeCalc.js +42 -33
- package/dist/calc/normalizeCalc.js.map +1 -1
- package/dist/calc/registry.d.ts +43 -0
- package/dist/calc/registry.js +27 -0
- package/dist/calc/registry.js.map +1 -0
- package/dist/calc/resolveCalcContext.d.ts +36 -0
- package/dist/calc/resolveCalcContext.js +87 -0
- package/dist/calc/resolveCalcContext.js.map +1 -0
- package/dist/calc/types.d.ts +25 -4
- package/dist/calc/types.js +23 -0
- package/dist/calc/types.js.map +1 -0
- package/dist/client/ByteSizeField.d.ts +29 -0
- package/dist/client/ByteSizeField.js +58 -0
- package/dist/client/ByteSizeField.js.map +1 -0
- package/dist/client/CalcExpressionBuilder.d.ts +20 -0
- package/dist/client/CalcExpressionBuilder.js +890 -0
- package/dist/client/CalcExpressionBuilder.js.map +1 -0
- 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/ConditionBuilder.js +2 -1
- package/dist/client/ConditionBuilder.js.map +1 -1
- package/dist/client/ConsentBlockLabel.d.ts +15 -0
- package/dist/client/ConsentBlockLabel.js +71 -0
- package/dist/client/ConsentBlockLabel.js.map +1 -0
- package/dist/client/ConsentSourceRowLabel.d.ts +9 -0
- package/dist/client/ConsentSourceRowLabel.js +21 -0
- package/dist/client/ConsentSourceRowLabel.js.map +1 -0
- package/dist/client/EndpointOptionsSelect.d.ts +55 -0
- package/dist/client/EndpointOptionsSelect.js +112 -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 +37 -0
- package/dist/client/FieldNameSelect.js +72 -0
- package/dist/client/FieldNameSelect.js.map +1 -0
- package/dist/client/FlowBuilder.d.ts +2 -2
- package/dist/client/FlowBuilder.js +137 -88
- package/dist/client/FlowBuilder.js.map +1 -1
- package/dist/client/FormConditionField.js +1 -4
- package/dist/client/FormConditionField.js.map +1 -1
- package/dist/client/RecipientsSelect.d.ts +37 -0
- package/dist/client/RecipientsSelect.js +197 -0
- package/dist/client/RecipientsSelect.js.map +1 -0
- 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 +557 -0
- package/dist/client/endpointOptions.d.ts +11 -0
- package/dist/client/endpointOptions.js +38 -0
- package/dist/client/endpointOptions.js.map +1 -0
- package/dist/client/flowAuthoring.js +142 -0
- package/dist/client/flowAuthoring.js.map +1 -0
- package/dist/client/synthesizeClientField.js +21 -10
- package/dist/client/synthesizeClientField.js.map +1 -1
- package/dist/client/toStaticLabel.js +13 -0
- package/dist/client/toStaticLabel.js.map +1 -0
- 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 +114 -28
- package/dist/collections/formSubmissions.js.map +1 -1
- package/dist/collections/forms.js +449 -112
- package/dist/collections/forms.js.map +1 -1
- package/dist/collections/formsEndpoints.js +106 -0
- package/dist/collections/formsEndpoints.js.map +1 -0
- package/dist/collections/redirectFields.d.ts +29 -0
- package/dist/collections/settingsFields.d.ts +31 -0
- package/dist/collections/settingsFields.js +45 -0
- package/dist/collections/settingsFields.js.map +1 -0
- package/dist/conditions/conditionType.js +9 -2
- package/dist/conditions/conditionType.js.map +1 -1
- package/dist/conditions/evaluate.js +1 -1
- package/dist/conditions/evaluate.js.map +1 -1
- package/dist/conditions/fieldTypes.d.ts +3 -1
- package/dist/conditions/fieldTypes.js +4 -1
- package/dist/conditions/fieldTypes.js.map +1 -1
- package/dist/conditions/normalizeConditions.js +20 -6
- package/dist/conditions/normalizeConditions.js.map +1 -1
- 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 +39 -11
- package/dist/consent/captureConsent.js +63 -13
- package/dist/consent/captureConsent.js.map +1 -1
- package/dist/consent/consentSourcesField.d.ts +66 -0
- package/dist/consent/consentSourcesField.js +98 -0
- package/dist/consent/consentSourcesField.js.map +1 -0
- package/dist/consent/effectiveStatement.js +16 -0
- package/dist/consent/effectiveStatement.js.map +1 -0
- package/dist/consent/resolveConsentEntries.d.ts +24 -0
- package/dist/consent/resolveConsentEntries.js +40 -0
- package/dist/consent/resolveConsentEntries.js.map +1 -0
- package/dist/consent/resolveConsentSourcesRequest.d.ts +37 -0
- package/dist/consent/resolveConsentSourcesRequest.js +54 -0
- package/dist/consent/resolveConsentSourcesRequest.js.map +1 -0
- package/dist/consent/resolveConsentStatements.d.ts +45 -0
- package/dist/consent/resolveConsentStatements.js +46 -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 +69 -0
- 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/email/departments.d.ts +59 -0
- package/dist/email/departments.js +87 -0
- package/dist/email/departments.js.map +1 -0
- package/dist/email/departmentsField.d.ts +53 -0
- package/dist/email/departmentsField.js +73 -0
- package/dist/email/departmentsField.js.map +1 -0
- package/dist/exports/client.d.ts +14 -1
- package/dist/exports/client.js +14 -1
- package/dist/exports/i18n.d.ts +5 -2
- package/dist/exports/i18n.js +5 -2
- package/dist/exports/react.d.ts +34 -10
- package/dist/exports/react.js +24 -4
- package/dist/exports/rsc.d.ts +10 -1
- package/dist/exports/rsc.js +10 -1
- package/dist/exports/types.d.ts +20 -12
- package/dist/fields/buildFieldBlocks.js +46 -25
- package/dist/fields/buildFieldBlocks.js.map +1 -1
- package/dist/fields/builtin/calculation.d.ts +17 -0
- package/dist/fields/builtin/calculation.js +193 -18
- package/dist/fields/builtin/calculation.js.map +1 -1
- package/dist/fields/builtin/checkbox.js +23 -0
- package/dist/fields/builtin/checkbox.js.map +1 -1
- package/dist/fields/builtin/consent.js +49 -14
- 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 +31 -0
- package/dist/fields/builtin/date.js.map +1 -0
- package/dist/fields/builtin/email.js +8 -1
- package/dist/fields/builtin/email.js.map +1 -1
- package/dist/fields/builtin/file.d.ts +15 -0
- package/dist/fields/builtin/file.js +95 -8
- package/dist/fields/builtin/file.js.map +1 -1
- package/dist/fields/builtin/index.d.ts +30 -0
- package/dist/fields/builtin/index.js +37 -10
- package/dist/fields/builtin/index.js.map +1 -1
- package/dist/fields/builtin/message.js +30 -0
- package/dist/fields/builtin/message.js.map +1 -0
- package/dist/fields/builtin/repeater.js +8 -3
- package/dist/fields/builtin/repeater.js.map +1 -1
- package/dist/fields/builtin/select.js +28 -4
- 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/builtin/text.js +7 -0
- package/dist/fields/builtin/text.js.map +1 -1
- 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 +30 -0
- package/dist/fields/fieldNamesOfType.js.map +1 -0
- package/dist/fields/instanceOptions.js +20 -0
- package/dist/fields/instanceOptions.js.map +1 -0
- package/dist/fields/localizedIf.d.ts +13 -0
- package/dist/fields/localizedIf.js +12 -0
- package/dist/fields/localizedIf.js.map +1 -0
- package/dist/fields/registry.d.ts +3 -1
- package/dist/fields/registry.js +23 -8
- package/dist/fields/registry.js.map +1 -1
- package/dist/fields/sharedConfig.js +125 -59
- package/dist/fields/sharedConfig.js.map +1 -1
- package/dist/fields/types.d.ts +78 -9
- 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 +28 -9
- package/dist/flow/normalizeFlow.js.map +1 -1
- package/dist/flow/stepLabel.js +15 -0
- package/dist/flow/stepLabel.js.map +1 -0
- 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 +23 -0
- package/dist/form/pollState.js +17 -0
- package/dist/form/pollState.js.map +1 -0
- package/dist/form/toFormDocument.d.ts +110 -0
- package/dist/form/toFormDocument.js +89 -0
- package/dist/form/toFormDocument.js.map +1 -0
- package/dist/form/types.d.ts +73 -0
- package/dist/index.d.ts +67 -61
- package/dist/index.js +120 -25
- package/dist/index.js.map +1 -1
- package/dist/options.d.ts +281 -0
- package/dist/plugin/applyRegistryConfig.d.ts +11 -0
- package/dist/plugin/applyRegistryConfig.js +20 -0
- package/dist/plugin/applyRegistryConfig.js.map +1 -0
- package/dist/plugin/customState.js +26 -0
- package/dist/plugin/customState.js.map +1 -0
- package/dist/plugin/registerCollections.js +43 -40
- package/dist/plugin/registerCollections.js.map +1 -1
- package/dist/plugin/uploadsCollection.d.ts +16 -0
- package/dist/plugin/uploadsCollection.js +53 -0
- package/dist/plugin/uploadsCollection.js.map +1 -0
- package/dist/poll/applyPollOptions.js +18 -0
- package/dist/poll/applyPollOptions.js.map +1 -0
- package/dist/poll/buildPollOptionSourceFields.js +50 -0
- package/dist/poll/buildPollOptionSourceFields.js.map +1 -0
- package/dist/poll/closeJob.d.ts +53 -0
- package/dist/poll/closeJob.js +121 -0
- package/dist/poll/closeJob.js.map +1 -0
- package/dist/poll/definePollOptionSource.d.ts +44 -0
- package/dist/poll/definePollOptionSource.js +6 -0
- package/dist/poll/definePollOptionSource.js.map +1 -0
- 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 +69 -0
- package/dist/poll/pollTypeRegistry.js.map +1 -0
- package/dist/poll/registry.d.ts +17 -0
- package/dist/poll/registry.js +12 -0
- package/dist/poll/registry.js.map +1 -0
- package/dist/poll/resolvePollCloseRequest.js +106 -0
- package/dist/poll/resolvePollCloseRequest.js.map +1 -0
- package/dist/poll/resolvePollOptions.d.ts +29 -0
- package/dist/poll/resolvePollOptions.js +52 -0
- package/dist/poll/resolvePollOptions.js.map +1 -0
- package/dist/poll/resolvePollOptionsRequest.js +50 -0
- package/dist/poll/resolvePollOptionsRequest.js.map +1 -0
- package/dist/poll/resolvePollOutcome.d.ts +40 -0
- package/dist/poll/resolvePollOutcome.js +90 -0
- package/dist/poll/resolvePollOutcome.js.map +1 -0
- package/dist/poll/resultsField.js +21 -0
- package/dist/poll/resultsField.js.map +1 -0
- package/dist/poll/votes/aggregateFromVotes.d.ts +27 -0
- package/dist/poll/votes/aggregateFromVotes.js +54 -0
- package/dist/poll/votes/aggregateFromVotes.js.map +1 -0
- package/dist/poll/votes/answerValues.js +16 -0
- package/dist/poll/votes/answerValues.js.map +1 -0
- package/dist/poll/votes/bumpPollVote.js +88 -0
- package/dist/poll/votes/bumpPollVote.js.map +1 -0
- package/dist/poll/votes/recountPollVotes.d.ts +20 -0
- package/dist/poll/votes/recountPollVotes.js +63 -0
- package/dist/poll/votes/recountPollVotes.js.map +1 -0
- package/dist/poll/votes/voteTallyHook.js +76 -0
- package/dist/poll/votes/voteTallyHook.js.map +1 -0
- package/dist/poll/votes/votesCollection.d.ts +19 -0
- package/dist/poll/votes/votesCollection.js +89 -0
- package/dist/poll/votes/votesCollection.js.map +1 -0
- package/dist/prefill/valuesFromSearchParams.js +5 -9
- package/dist/prefill/valuesFromSearchParams.js.map +1 -1
- package/dist/presentations/types.d.ts +3 -2
- package/dist/react/Form.d.ts +77 -35
- package/dist/react/Form.js +368 -222
- package/dist/react/Form.js.map +1 -1
- package/dist/react/FormContext.d.ts +51 -1
- package/dist/react/FormContext.js.map +1 -1
- package/dist/react/FormControls.d.ts +55 -0
- package/dist/react/FormControls.js +56 -0
- package/dist/react/FormControls.js.map +1 -0
- package/dist/react/FormFields.d.ts +18 -0
- package/dist/react/FormFields.js +114 -0
- package/dist/react/FormFields.js.map +1 -0
- package/dist/react/FormLayout.d.ts +4 -2
- package/dist/react/FormLayout.js +3 -2
- package/dist/react/FormLayout.js.map +1 -1
- package/dist/react/FormResults.d.ts +8 -3
- package/dist/react/FormResults.js +50 -29
- package/dist/react/FormResults.js.map +1 -1
- package/dist/react/FormSteps.d.ts +17 -0
- package/dist/react/FormSteps.js +35 -0
- package/dist/react/FormSteps.js.map +1 -0
- package/dist/react/Poll.d.ts +40 -6
- package/dist/react/Poll.js +137 -33
- package/dist/react/Poll.js.map +1 -1
- package/dist/react/adapters.d.ts +35 -0
- package/dist/react/adapters.js +11 -0
- package/dist/react/adapters.js.map +1 -0
- package/dist/react/captcha/HcaptchaCaptcha.d.ts +31 -0
- package/dist/react/captcha/HcaptchaCaptcha.js +53 -0
- package/dist/react/captcha/HcaptchaCaptcha.js.map +1 -0
- package/dist/react/captcha/RecaptchaCaptcha.d.ts +44 -0
- package/dist/react/captcha/RecaptchaCaptcha.js +93 -0
- package/dist/react/captcha/RecaptchaCaptcha.js.map +1 -0
- package/dist/react/captcha/TurnstileCaptcha.d.ts +31 -0
- package/dist/react/captcha/TurnstileCaptcha.js +53 -0
- package/dist/react/captcha/TurnstileCaptcha.js.map +1 -0
- package/dist/react/captcha/types.d.ts +8 -0
- package/dist/react/captcha/useCaptchaScript.js +63 -0
- package/dist/react/captcha/useCaptchaScript.js.map +1 -0
- package/dist/react/captcha/vendors.js +8 -0
- package/dist/react/captcha/vendors.js.map +1 -0
- package/dist/react/contract.d.ts +2 -3
- package/dist/react/contract.js.map +1 -1
- package/dist/react/fetchResults.d.ts +1 -1
- package/dist/react/fetchResults.js +1 -1
- package/dist/react/fetchResults.js.map +1 -1
- package/dist/react/presentation/DialogSurface.js +1 -4
- package/dist/react/presentation/DialogSurface.js.map +1 -1
- package/dist/react/primitives/Checkbox.d.ts +6 -2
- package/dist/react/primitives/Checkbox.js +4 -2
- package/dist/react/primitives/Checkbox.js.map +1 -1
- package/dist/react/primitives/ChoiceGroup.d.ts +40 -0
- package/dist/react/primitives/ChoiceGroup.js +33 -0
- package/dist/react/primitives/ChoiceGroup.js.map +1 -0
- package/dist/react/primitives/FieldShell.d.ts +13 -5
- package/dist/react/primitives/FieldShell.js +35 -32
- package/dist/react/primitives/FieldShell.js.map +1 -1
- package/dist/react/primitives/Input.d.ts +4 -2
- package/dist/react/primitives/Input.js +2 -1
- package/dist/react/primitives/Input.js.map +1 -1
- package/dist/react/renderers/calculation.js +7 -5
- package/dist/react/renderers/calculation.js.map +1 -1
- package/dist/react/renderers/checkbox.js +3 -5
- package/dist/react/renderers/checkbox.js.map +1 -1
- package/dist/react/renderers/consent.js +84 -36
- package/dist/react/renderers/consent.js.map +1 -1
- package/dist/react/renderers/date.js +33 -0
- package/dist/react/renderers/date.js.map +1 -0
- package/dist/react/renderers/email.js +4 -5
- package/dist/react/renderers/email.js.map +1 -1
- package/dist/react/renderers/file.js +29 -14
- package/dist/react/renderers/file.js.map +1 -1
- package/dist/react/renderers/index.js +7 -0
- package/dist/react/renderers/index.js.map +1 -1
- package/dist/react/renderers/message.js +41 -0
- package/dist/react/renderers/message.js.map +1 -0
- package/dist/react/renderers/number.js +1 -4
- package/dist/react/renderers/number.js.map +1 -1
- package/dist/react/renderers/region.js +43 -0
- package/dist/react/renderers/region.js.map +1 -0
- package/dist/react/renderers/repeater.js +32 -14
- package/dist/react/renderers/repeater.js.map +1 -1
- package/dist/react/renderers/select.js +21 -6
- package/dist/react/renderers/select.js.map +1 -1
- package/dist/react/renderers/text.js +4 -5
- package/dist/react/renderers/text.js.map +1 -1
- package/dist/react/renderers/textarea.js +1 -4
- package/dist/react/renderers/textarea.js.map +1 -1
- package/dist/react/state.d.ts +46 -3
- package/dist/react/state.js +73 -10
- package/dist/react/state.js.map +1 -1
- package/dist/react/submitForm.js +1 -1
- package/dist/react/submitForm.js.map +1 -1
- package/dist/react/uploadFile.d.ts +2 -2
- package/dist/react/uploadFile.js +1 -1
- package/dist/react/uploadFile.js.map +1 -1
- package/dist/react/useCalcValues.d.ts +10 -0
- package/dist/react/useCalcValues.js +13 -0
- package/dist/react/useCalcValues.js.map +1 -0
- package/dist/react/useField.d.ts +0 -1
- package/dist/react/useField.js +7 -6
- 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 +15 -3
- package/dist/recall/resolver.js.map +1 -1
- package/dist/spam/captcha.d.ts +4 -3
- package/dist/spam/captcha.js +4 -3
- package/dist/spam/captcha.js.map +1 -1
- package/dist/spam/clientIp.js +9 -0
- package/dist/spam/clientIp.js.map +1 -0
- package/dist/spam/constants.js +13 -1
- package/dist/spam/constants.js.map +1 -1
- package/dist/spam/identify.js +3 -6
- package/dist/spam/identify.js.map +1 -1
- package/dist/spam/providers/hcaptcha.d.ts +17 -0
- package/dist/spam/providers/hcaptcha.js +18 -0
- package/dist/spam/providers/hcaptcha.js.map +1 -0
- package/dist/spam/providers/recaptcha.d.ts +23 -0
- package/dist/spam/providers/recaptcha.js +23 -0
- package/dist/spam/providers/recaptcha.js.map +1 -0
- package/dist/spam/providers/siteverify.js +34 -0
- package/dist/spam/providers/siteverify.js.map +1 -0
- package/dist/spam/providers/turnstile.d.ts +17 -0
- package/dist/spam/providers/turnstile.js +18 -0
- package/dist/spam/providers/turnstile.js.map +1 -0
- package/dist/spam/resolveSpam.js +2 -1
- package/dist/spam/resolveSpam.js.map +1 -1
- package/dist/spam/spamGuard.js +25 -11
- package/dist/spam/spamGuard.js.map +1 -1
- package/dist/spam/types.d.ts +19 -4
- package/dist/submissions/SubmissionAnswers.js +6 -2
- package/dist/submissions/SubmissionAnswers.js.map +1 -1
- package/dist/submissions/SubmissionAnswersClient.js +100 -64
- package/dist/submissions/SubmissionAnswersClient.js.map +1 -1
- package/dist/submissions/coerceBoolean.js +14 -0
- package/dist/submissions/coerceBoolean.js.map +1 -0
- 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/formIdOf.js +13 -0
- package/dist/submissions/formIdOf.js.map +1 -0
- package/dist/submissions/resolveVotedSubmission.d.ts +27 -0
- package/dist/submissions/resolveVotedSubmission.js +51 -0
- package/dist/submissions/resolveVotedSubmission.js.map +1 -0
- package/dist/submissions/runSubmission.d.ts +10 -0
- package/dist/submissions/runSubmission.js +104 -54
- package/dist/submissions/runSubmission.js.map +1 -1
- package/dist/submissions/types.d.ts +11 -4
- package/dist/submissions/validateSubmission.js +99 -13
- package/dist/submissions/validateSubmission.js.map +1 -1
- package/dist/submissions/verifyContext.js +35 -0
- package/dist/submissions/verifyContext.js.map +1 -0
- package/dist/submissions/voteChangeEndpoint.js +105 -0
- package/dist/submissions/voteChangeEndpoint.js.map +1 -0
- package/dist/submissions/votedCookie.d.ts +15 -0
- package/dist/submissions/votedCookie.js +74 -0
- package/dist/submissions/votedCookie.js.map +1 -0
- package/dist/translations/clientRuntimeKeys.d.ts +17 -0
- package/dist/translations/clientRuntimeKeys.js +48 -0
- package/dist/translations/clientRuntimeKeys.js.map +1 -0
- package/dist/translations/de.d.ts +12 -0
- package/dist/translations/de.js +380 -0
- package/dist/translations/de.js.map +1 -0
- package/dist/translations/en.js +250 -28
- package/dist/translations/en.js.map +1 -1
- package/dist/translations/index.d.ts +14 -5
- package/dist/translations/index.js +14 -3
- package/dist/translations/index.js.map +1 -1
- package/dist/translations/keys.d.ts +245 -23
- package/dist/translations/keys.js +246 -24
- package/dist/translations/keys.js.map +1 -1
- package/dist/translations/makeTranslate.d.ts +7 -3
- package/dist/translations/makeTranslate.js +12 -3
- package/dist/translations/makeTranslate.js.map +1 -1
- package/dist/translations/server.js +8 -1
- package/dist/translations/server.js.map +1 -1
- package/dist/uploads/captureFileRef.d.ts +10 -3
- package/dist/uploads/captureFileRef.js +18 -9
- package/dist/uploads/captureFileRef.js.map +1 -1
- package/dist/uploads/formatBytes.d.ts +9 -0
- package/dist/uploads/formatBytes.js +25 -0
- package/dist/uploads/formatBytes.js.map +1 -0
- package/dist/uploads/resolveFileRef.js +3 -2
- package/dist/uploads/resolveFileRef.js.map +1 -1
- package/dist/uploads/types.d.ts +1 -2
- package/dist/validation/buildRuleBlocks.js +18 -17
- package/dist/validation/buildRuleBlocks.js.map +1 -1
- package/dist/validation/builtin/email.js +2 -1
- package/dist/validation/builtin/email.js.map +1 -1
- package/dist/validation/builtin/index.d.ts +14 -0
- package/dist/validation/builtin/index.js +14 -1
- package/dist/validation/builtin/index.js.map +1 -1
- package/dist/validation/builtin/integer.js +15 -0
- package/dist/validation/builtin/integer.js.map +1 -0
- 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 +24 -0
- package/dist/validation/builtin/maxDate.js.map +1 -0
- 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 +24 -0
- package/dist/validation/builtin/minDate.js.map +1 -0
- package/dist/validation/builtin/minLength.js +1 -0
- package/dist/validation/builtin/minLength.js.map +1 -1
- package/dist/validation/builtin/notAlreadySubmitted.js +5 -1
- 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/validateDateBound.js +18 -0
- package/dist/validation/builtin/validateDateBound.js.map +1 -0
- package/dist/validation/builtin/validateRegexParams.js +44 -0
- package/dist/validation/builtin/validateRegexParams.js.map +1 -0
- package/dist/validation/emailPattern.js +10 -0
- package/dist/validation/emailPattern.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/registry.d.ts +2 -1
- package/dist/validation/registry.js +2 -9
- package/dist/validation/registry.js.map +1 -1
- package/dist/validation/runValidation.js +8 -29
- package/dist/validation/runValidation.js.map +1 -1
- package/dist/validation/types.d.ts +5 -11
- package/dist/validation/validateUrl.js +22 -0
- package/dist/validation/validateUrl.js.map +1 -0
- package/package.json +14 -6
- package/styles/form-builder.css +94 -190
- package/dist/collections/uploads.d.ts +0 -30
- package/dist/collections/uploads.js +0 -55
- package/dist/collections/uploads.js.map +0 -1
- package/dist/consent/buildConsentSourceConfig.js +0 -49
- package/dist/consent/buildConsentSourceConfig.js.map +0 -1
- package/dist/consent/builtin/index.d.ts +0 -7
- package/dist/consent/builtin/index.js +0 -11
- 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 -44
- 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
- package/dist/presentations/registry.d.ts +0 -15
- package/dist/presentations/registry.js +0 -15
- package/dist/presentations/registry.js.map +0 -1
- package/dist/react/toFormDocument.d.ts +0 -24
- package/dist/react/toFormDocument.js +0 -22
- package/dist/react/toFormDocument.js.map +0 -1
package/dist/react/state.d.ts
CHANGED
|
@@ -3,13 +3,56 @@ type FieldErrors = Record<string, string[]>;
|
|
|
3
3
|
type FormState = {
|
|
4
4
|
values: Record<string, unknown>;
|
|
5
5
|
errors: FieldErrors;
|
|
6
|
-
warnings: FieldErrors;
|
|
7
6
|
touched: Record<string, boolean>;
|
|
7
|
+
/**
|
|
8
|
+
* Fields whose value changed since mount or the last reset. Blur reveals a field's error only
|
|
9
|
+
* once it is dirty (or its step was attempted), so focusing and leaving a pristine field says
|
|
10
|
+
* nothing, and a reset makes every field pristine again.
|
|
11
|
+
*/
|
|
12
|
+
dirty: Record<string, boolean>;
|
|
8
13
|
submitting: boolean;
|
|
9
14
|
submitted: boolean;
|
|
10
|
-
|
|
15
|
+
/**
|
|
16
|
+
* The step ids whose validation the user has attempted (a blocked advance, or a submit). A field
|
|
17
|
+
* reveals its error when it is touched or its own step is in this set, never via a single global flag,
|
|
18
|
+
* so a submit attempt cannot pre-reveal errors on a step the visitor has not reached.
|
|
19
|
+
*/
|
|
20
|
+
attemptedSteps: Set<string>;
|
|
11
21
|
submitError?: string;
|
|
12
22
|
};
|
|
23
|
+
type FormAction = {
|
|
24
|
+
type: 'SET_VALUE';
|
|
25
|
+
name: string;
|
|
26
|
+
value: unknown;
|
|
27
|
+
} | {
|
|
28
|
+
type: 'TOUCH';
|
|
29
|
+
name: string;
|
|
30
|
+
} | {
|
|
31
|
+
type: 'SET_FIELD_ISSUES';
|
|
32
|
+
name: string;
|
|
33
|
+
errors: string[];
|
|
34
|
+
} | {
|
|
35
|
+
type: 'SET_ALL_ISSUES';
|
|
36
|
+
errors: FieldErrors;
|
|
37
|
+
steps: string[];
|
|
38
|
+
} | {
|
|
39
|
+
type: 'MARK_STEP_ATTEMPTED';
|
|
40
|
+
stepId: string;
|
|
41
|
+
} | {
|
|
42
|
+
type: 'REMOVE_REPEATER_ROW';
|
|
43
|
+
name: string;
|
|
44
|
+
index: number;
|
|
45
|
+
} | {
|
|
46
|
+
type: 'SUBMIT_START';
|
|
47
|
+
} | {
|
|
48
|
+
type: 'SUBMIT_SUCCESS';
|
|
49
|
+
} | {
|
|
50
|
+
type: 'SUBMIT_ERROR';
|
|
51
|
+
message: string;
|
|
52
|
+
} | {
|
|
53
|
+
type: 'RESET';
|
|
54
|
+
values: Record<string, unknown>;
|
|
55
|
+
};
|
|
13
56
|
//#endregion
|
|
14
|
-
export { FormState };
|
|
57
|
+
export { FieldErrors, FormAction, FormState };
|
|
15
58
|
//# sourceMappingURL=state.d.ts.map
|
package/dist/react/state.js
CHANGED
|
@@ -1,13 +1,66 @@
|
|
|
1
|
+
import { isNamedField } from "../fields/fieldKey.js";
|
|
2
|
+
import { consentDisplayOf } from "../consent/effectiveStatement.js";
|
|
1
3
|
//#region src/react/state.ts
|
|
4
|
+
/**
|
|
5
|
+
* The step a field's error reveal is keyed to when the form has no flow, or the field belongs to no
|
|
6
|
+
* step. A single-step form has exactly this one step, so its reveal collapses to the old global one.
|
|
7
|
+
*/
|
|
8
|
+
const DEFAULT_STEP_ID = "__form__";
|
|
9
|
+
/**
|
|
10
|
+
* Per-field defaults for the reducer's initial state. Nameless (bare) blocks carry no value and
|
|
11
|
+
* are skipped. A repeater with a positive `minRows` starts pre-seeded with that many empty rows,
|
|
12
|
+
* matching the schema's own floor. Computed once, ahead of the reducer, so seeding is never an
|
|
13
|
+
* action: it can't touch a field, trigger validation, or (via `Form`'s dispatch wrapper) be
|
|
14
|
+
* mistaken for the user's first edit and fire `form.started`.
|
|
15
|
+
*/
|
|
16
|
+
const seedFieldValues = (fields) => Object.fromEntries(fields.filter(isNamedField).map((field) => {
|
|
17
|
+
if (field.blockType === "repeater") {
|
|
18
|
+
const minRows = typeof field.minRows === "number" ? field.minRows : 0;
|
|
19
|
+
if (minRows > 0) return [field.name, Array.from({ length: minRows }, () => ({}))];
|
|
20
|
+
}
|
|
21
|
+
if (field.blockType === "consent" && consentDisplayOf(field) === "notice") return [field.name, true];
|
|
22
|
+
return [field.name, void 0];
|
|
23
|
+
}));
|
|
2
24
|
const initialFormState = (values) => ({
|
|
3
25
|
values,
|
|
4
26
|
errors: {},
|
|
5
|
-
warnings: {},
|
|
6
27
|
touched: {},
|
|
28
|
+
dirty: {},
|
|
7
29
|
submitting: false,
|
|
8
30
|
submitted: false,
|
|
9
|
-
|
|
31
|
+
attemptedSteps: /* @__PURE__ */ new Set()
|
|
10
32
|
});
|
|
33
|
+
/**
|
|
34
|
+
* Re-key composite entries (`name[i].sub`) after repeater row `removed` is deleted: drop the removed
|
|
35
|
+
* index and shift every higher index down by one, so surviving rows keep their own errors/touched
|
|
36
|
+
* flags instead of inheriting a deleted or shifted neighbour's. Matches on the `name[<int>]` prefix,
|
|
37
|
+
* so it is agnostic to the sub-key shape after `]` and needs no sub-field list. Returns the same
|
|
38
|
+
* reference when nothing changed, so an unrelated dispatch does not churn state identity.
|
|
39
|
+
*/
|
|
40
|
+
const reindexRepeaterKeys = (map, name, removed) => {
|
|
41
|
+
const prefix = `${name}[`;
|
|
42
|
+
let changed = false;
|
|
43
|
+
const next = {};
|
|
44
|
+
for (const [key, value] of Object.entries(map)) {
|
|
45
|
+
if (!key.startsWith(prefix)) {
|
|
46
|
+
next[key] = value;
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
const close = key.indexOf("]", prefix.length);
|
|
50
|
+
const idx = close === -1 ? NaN : Number(key.slice(prefix.length, close));
|
|
51
|
+
if (!Number.isInteger(idx) || idx < removed) {
|
|
52
|
+
next[key] = value;
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
if (idx === removed) {
|
|
56
|
+
changed = true;
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
next[`${name}[${idx - 1}]${key.slice(close + 1)}`] = value;
|
|
60
|
+
changed = true;
|
|
61
|
+
}
|
|
62
|
+
return changed ? next : map;
|
|
63
|
+
};
|
|
11
64
|
/** Changing a value clears that field's prior errors (re-validated by the caller). */
|
|
12
65
|
const formReducer = (state, action) => {
|
|
13
66
|
switch (action.type) {
|
|
@@ -19,7 +72,11 @@ const formReducer = (state, action) => {
|
|
|
19
72
|
...state.values,
|
|
20
73
|
[action.name]: action.value
|
|
21
74
|
},
|
|
22
|
-
errors: restErrors
|
|
75
|
+
errors: restErrors,
|
|
76
|
+
dirty: state.dirty[action.name] ? state.dirty : {
|
|
77
|
+
...state.dirty,
|
|
78
|
+
[action.name]: true
|
|
79
|
+
}
|
|
23
80
|
};
|
|
24
81
|
}
|
|
25
82
|
case "TOUCH": return state.touched[action.name] ? state : {
|
|
@@ -34,17 +91,22 @@ const formReducer = (state, action) => {
|
|
|
34
91
|
errors: {
|
|
35
92
|
...state.errors,
|
|
36
93
|
[action.name]: action.errors
|
|
37
|
-
},
|
|
38
|
-
warnings: {
|
|
39
|
-
...state.warnings,
|
|
40
|
-
[action.name]: action.warnings
|
|
41
94
|
}
|
|
42
95
|
};
|
|
43
96
|
case "SET_ALL_ISSUES": return {
|
|
44
97
|
...state,
|
|
45
98
|
errors: action.errors,
|
|
46
|
-
|
|
47
|
-
|
|
99
|
+
attemptedSteps: new Set([...state.attemptedSteps, ...action.steps])
|
|
100
|
+
};
|
|
101
|
+
case "MARK_STEP_ATTEMPTED": return state.attemptedSteps.has(action.stepId) ? state : {
|
|
102
|
+
...state,
|
|
103
|
+
attemptedSteps: new Set([...state.attemptedSteps, action.stepId])
|
|
104
|
+
};
|
|
105
|
+
case "REMOVE_REPEATER_ROW": return {
|
|
106
|
+
...state,
|
|
107
|
+
errors: reindexRepeaterKeys(state.errors, action.name, action.index),
|
|
108
|
+
touched: reindexRepeaterKeys(state.touched, action.name, action.index),
|
|
109
|
+
dirty: reindexRepeaterKeys(state.dirty, action.name, action.index)
|
|
48
110
|
};
|
|
49
111
|
case "SUBMIT_START": return {
|
|
50
112
|
...state,
|
|
@@ -61,10 +123,11 @@ const formReducer = (state, action) => {
|
|
|
61
123
|
submitting: false,
|
|
62
124
|
submitError: action.message
|
|
63
125
|
};
|
|
126
|
+
case "RESET": return initialFormState(action.values);
|
|
64
127
|
default: return state;
|
|
65
128
|
}
|
|
66
129
|
};
|
|
67
130
|
//#endregion
|
|
68
|
-
export { formReducer, initialFormState };
|
|
131
|
+
export { DEFAULT_STEP_ID, formReducer, initialFormState, seedFieldValues };
|
|
69
132
|
|
|
70
133
|
//# sourceMappingURL=state.js.map
|
package/dist/react/state.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"state.js","names":[],"sources":["../../src/react/state.ts"],"sourcesContent":["
|
|
1
|
+
{"version":3,"file":"state.js","names":[],"sources":["../../src/react/state.ts"],"sourcesContent":["import { consentDisplayOf } from '../consent/effectiveStatement'\nimport { isNamedField } from '../fields/fieldKey'\nimport type { FormFieldInstance } from '../submissions/types'\n\nexport type FieldErrors = Record<string, string[]>\n\n/**\n * The step a field's error reveal is keyed to when the form has no flow, or the field belongs to no\n * step. A single-step form has exactly this one step, so its reveal collapses to the old global one.\n */\nexport const DEFAULT_STEP_ID = '__form__'\n\nexport type FormState = {\n\tvalues: Record<string, unknown>\n\terrors: FieldErrors\n\ttouched: Record<string, boolean>\n\t/**\n\t * Fields whose value changed since mount or the last reset. Blur reveals a field's error only\n\t * once it is dirty (or its step was attempted), so focusing and leaving a pristine field says\n\t * nothing, and a reset makes every field pristine again.\n\t */\n\tdirty: Record<string, boolean>\n\tsubmitting: boolean\n\tsubmitted: boolean\n\t/**\n\t * The step ids whose validation the user has attempted (a blocked advance, or a submit). A field\n\t * reveals its error when it is touched or its own step is in this set, never via a single global flag,\n\t * so a submit attempt cannot pre-reveal errors on a step the visitor has not reached.\n\t */\n\tattemptedSteps: Set<string>\n\tsubmitError?: string\n}\n\nexport type FormAction =\n\t| { type: 'SET_VALUE'; name: string; value: unknown }\n\t| { type: 'TOUCH'; name: string }\n\t| { type: 'SET_FIELD_ISSUES'; name: string; errors: string[] }\n\t| { type: 'SET_ALL_ISSUES'; errors: FieldErrors; steps: string[] }\n\t| { type: 'MARK_STEP_ATTEMPTED'; stepId: string }\n\t| { type: 'REMOVE_REPEATER_ROW'; name: string; index: number }\n\t| { type: 'SUBMIT_START' }\n\t| { type: 'SUBMIT_SUCCESS' }\n\t| { type: 'SUBMIT_ERROR'; message: string }\n\t| { type: 'RESET'; values: Record<string, unknown> }\n\n/**\n * Per-field defaults for the reducer's initial state. Nameless (bare) blocks carry no value and\n * are skipped. A repeater with a positive `minRows` starts pre-seeded with that many empty rows,\n * matching the schema's own floor. Computed once, ahead of the reducer, so seeding is never an\n * action: it can't touch a field, trigger validation, or (via `Form`'s dispatch wrapper) be\n * mistaken for the user's first edit and fire `form.started`.\n */\nexport const seedFieldValues = (fields: FormFieldInstance[]): Record<string, unknown> =>\n\tObject.fromEntries(\n\t\tfields.filter(isNamedField).map((field) => {\n\t\t\tif (field.blockType === 'repeater') {\n\t\t\t\tconst minRows = typeof field.minRows === 'number' ? field.minRows : 0\n\t\t\t\tif (minRows > 0) {\n\t\t\t\t\treturn [field.name, Array.from({ length: minRows }, () => ({}))]\n\t\t\t\t}\n\t\t\t}\n\t\t\t// A notice-display consent has no control and the submit is the agreement, so its value\n\t\t\t// is true from the start; the server coerces the same, keeping dependent conditions and\n\t\t\t// calc in agreement across both engines.\n\t\t\tif (field.blockType === 'consent' && consentDisplayOf(field) === 'notice') {\n\t\t\t\treturn [field.name, true]\n\t\t\t}\n\t\t\treturn [field.name, undefined]\n\t\t})\n\t)\n\nexport const initialFormState = (values: Record<string, unknown>): FormState => ({\n\tvalues,\n\terrors: {},\n\ttouched: {},\n\tdirty: {},\n\tsubmitting: false,\n\tsubmitted: false,\n\tattemptedSteps: new Set(),\n})\n\n/**\n * Re-key composite entries (`name[i].sub`) after repeater row `removed` is deleted: drop the removed\n * index and shift every higher index down by one, so surviving rows keep their own errors/touched\n * flags instead of inheriting a deleted or shifted neighbour's. Matches on the `name[<int>]` prefix,\n * so it is agnostic to the sub-key shape after `]` and needs no sub-field list. Returns the same\n * reference when nothing changed, so an unrelated dispatch does not churn state identity.\n */\nconst reindexRepeaterKeys = <T>(\n\tmap: Record<string, T>,\n\tname: string,\n\tremoved: number\n): Record<string, T> => {\n\tconst prefix = `${name}[`\n\tlet changed = false\n\tconst next: Record<string, T> = {}\n\tfor (const [key, value] of Object.entries(map)) {\n\t\tif (!key.startsWith(prefix)) {\n\t\t\tnext[key] = value\n\t\t\tcontinue\n\t\t}\n\t\tconst close = key.indexOf(']', prefix.length)\n\t\tconst idx = close === -1 ? Number.NaN : Number(key.slice(prefix.length, close))\n\t\tif (!Number.isInteger(idx) || idx < removed) {\n\t\t\tnext[key] = value\n\t\t\tcontinue\n\t\t}\n\t\tif (idx === removed) {\n\t\t\tchanged = true\n\t\t\tcontinue\n\t\t}\n\t\tnext[`${name}[${idx - 1}]${key.slice(close + 1)}`] = value\n\t\tchanged = true\n\t}\n\treturn changed ? next : map\n}\n\n/** Changing a value clears that field's prior errors (re-validated by the caller). */\nexport const formReducer = (state: FormState, action: FormAction): FormState => {\n\tswitch (action.type) {\n\t\tcase 'SET_VALUE': {\n\t\t\tconst { [action.name]: _removed, ...restErrors } = state.errors\n\t\t\treturn {\n\t\t\t\t...state,\n\t\t\t\tvalues: { ...state.values, [action.name]: action.value },\n\t\t\t\terrors: restErrors,\n\t\t\t\tdirty: state.dirty[action.name] ? state.dirty : { ...state.dirty, [action.name]: true },\n\t\t\t}\n\t\t}\n\t\tcase 'TOUCH':\n\t\t\treturn state.touched[action.name]\n\t\t\t\t? state\n\t\t\t\t: { ...state, touched: { ...state.touched, [action.name]: true } }\n\t\tcase 'SET_FIELD_ISSUES':\n\t\t\treturn {\n\t\t\t\t...state,\n\t\t\t\terrors: { ...state.errors, [action.name]: action.errors },\n\t\t\t}\n\t\tcase 'SET_ALL_ISSUES':\n\t\t\treturn {\n\t\t\t\t...state,\n\t\t\t\terrors: action.errors,\n\t\t\t\tattemptedSteps: new Set([...state.attemptedSteps, ...action.steps]),\n\t\t\t}\n\t\tcase 'MARK_STEP_ATTEMPTED':\n\t\t\treturn state.attemptedSteps.has(action.stepId)\n\t\t\t\t? state\n\t\t\t\t: { ...state, attemptedSteps: new Set([...state.attemptedSteps, action.stepId]) }\n\t\tcase 'REMOVE_REPEATER_ROW':\n\t\t\t// The row value is removed by the field's own SET_VALUE; this shifts the composite issue keys\n\t\t\t// (`name[i].sub`) that a plain value array cannot carry, so a deleted row's errors never strand\n\t\t\t// on a survivor or linger unreachably.\n\t\t\treturn {\n\t\t\t\t...state,\n\t\t\t\terrors: reindexRepeaterKeys(state.errors, action.name, action.index),\n\t\t\t\ttouched: reindexRepeaterKeys(state.touched, action.name, action.index),\n\t\t\t\tdirty: reindexRepeaterKeys(state.dirty, action.name, action.index),\n\t\t\t}\n\t\tcase 'SUBMIT_START':\n\t\t\treturn { ...state, submitting: true, submitError: undefined }\n\t\tcase 'SUBMIT_SUCCESS':\n\t\t\treturn { ...state, submitting: false, submitted: true }\n\t\tcase 'SUBMIT_ERROR':\n\t\t\treturn { ...state, submitting: false, submitError: action.message }\n\t\tcase 'RESET':\n\t\t\treturn initialFormState(action.values)\n\t\tdefault:\n\t\t\treturn state\n\t}\n}\n"],"mappings":";;;;;;;AAUA,MAAa,kBAAkB;;;;;;;;AA0C/B,MAAa,mBAAmB,WAC/B,OAAO,YACN,OAAO,OAAO,YAAY,EAAE,KAAK,UAAU;CAC1C,IAAI,MAAM,cAAc,YAAY;EACnC,MAAM,UAAU,OAAO,MAAM,YAAY,WAAW,MAAM,UAAU;EACpE,IAAI,UAAU,GACb,OAAO,CAAC,MAAM,MAAM,MAAM,KAAK,EAAE,QAAQ,QAAQ,UAAU,CAAC,EAAE,CAAC;CAEjE;CAIA,IAAI,MAAM,cAAc,aAAa,iBAAiB,KAAK,MAAM,UAChE,OAAO,CAAC,MAAM,MAAM,IAAI;CAEzB,OAAO,CAAC,MAAM,MAAM,KAAA,CAAS;AAC9B,CAAC,CACF;AAED,MAAa,oBAAoB,YAAgD;CAChF;CACA,QAAQ,CAAC;CACT,SAAS,CAAC;CACV,OAAO,CAAC;CACR,YAAY;CACZ,WAAW;CACX,gCAAgB,IAAI,IAAI;AACzB;;;;;;;;AASA,MAAM,uBACL,KACA,MACA,YACuB;CACvB,MAAM,SAAS,GAAG,KAAK;CACvB,IAAI,UAAU;CACd,MAAM,OAA0B,CAAC;CACjC,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,GAAG,GAAG;EAC/C,IAAI,CAAC,IAAI,WAAW,MAAM,GAAG;GAC5B,KAAK,OAAO;GACZ;EACD;EACA,MAAM,QAAQ,IAAI,QAAQ,KAAK,OAAO,MAAM;EAC5C,MAAM,MAAM,UAAU,KAAK,MAAa,OAAO,IAAI,MAAM,OAAO,QAAQ,KAAK,CAAC;EAC9E,IAAI,CAAC,OAAO,UAAU,GAAG,KAAK,MAAM,SAAS;GAC5C,KAAK,OAAO;GACZ;EACD;EACA,IAAI,QAAQ,SAAS;GACpB,UAAU;GACV;EACD;EACA,KAAK,GAAG,KAAK,GAAG,MAAM,EAAE,GAAG,IAAI,MAAM,QAAQ,CAAC,OAAO;EACrD,UAAU;CACX;CACA,OAAO,UAAU,OAAO;AACzB;;AAGA,MAAa,eAAe,OAAkB,WAAkC;CAC/E,QAAQ,OAAO,MAAf;EACC,KAAK,aAAa;GACjB,MAAM,GAAG,OAAO,OAAO,UAAU,GAAG,eAAe,MAAM;GACzD,OAAO;IACN,GAAG;IACH,QAAQ;KAAE,GAAG,MAAM;MAAS,OAAO,OAAO,OAAO;IAAM;IACvD,QAAQ;IACR,OAAO,MAAM,MAAM,OAAO,QAAQ,MAAM,QAAQ;KAAE,GAAG,MAAM;MAAQ,OAAO,OAAO;IAAK;GACvF;EACD;EACA,KAAK,SACJ,OAAO,MAAM,QAAQ,OAAO,QACzB,QACA;GAAE,GAAG;GAAO,SAAS;IAAE,GAAG,MAAM;KAAU,OAAO,OAAO;GAAK;EAAE;EACnE,KAAK,oBACJ,OAAO;GACN,GAAG;GACH,QAAQ;IAAE,GAAG,MAAM;KAAS,OAAO,OAAO,OAAO;GAAO;EACzD;EACD,KAAK,kBACJ,OAAO;GACN,GAAG;GACH,QAAQ,OAAO;GACf,gBAAgB,IAAI,IAAI,CAAC,GAAG,MAAM,gBAAgB,GAAG,OAAO,KAAK,CAAC;EACnE;EACD,KAAK,uBACJ,OAAO,MAAM,eAAe,IAAI,OAAO,MAAM,IAC1C,QACA;GAAE,GAAG;GAAO,gBAAgB,IAAI,IAAI,CAAC,GAAG,MAAM,gBAAgB,OAAO,MAAM,CAAC;EAAE;EAClF,KAAK,uBAIJ,OAAO;GACN,GAAG;GACH,QAAQ,oBAAoB,MAAM,QAAQ,OAAO,MAAM,OAAO,KAAK;GACnE,SAAS,oBAAoB,MAAM,SAAS,OAAO,MAAM,OAAO,KAAK;GACrE,OAAO,oBAAoB,MAAM,OAAO,OAAO,MAAM,OAAO,KAAK;EAClE;EACD,KAAK,gBACJ,OAAO;GAAE,GAAG;GAAO,YAAY;GAAM,aAAa,KAAA;EAAU;EAC7D,KAAK,kBACJ,OAAO;GAAE,GAAG;GAAO,YAAY;GAAO,WAAW;EAAK;EACvD,KAAK,gBACJ,OAAO;GAAE,GAAG;GAAO,YAAY;GAAO,aAAa,OAAO;EAAQ;EACnE,KAAK,SACJ,OAAO,iBAAiB,OAAO,MAAM;EACtC,SACC,OAAO;CACT;AACD"}
|
package/dist/react/submitForm.js
CHANGED
|
@@ -49,7 +49,7 @@ const submitForm = async (input) => {
|
|
|
49
49
|
}
|
|
50
50
|
return {
|
|
51
51
|
ok: false,
|
|
52
|
-
message: `Request failed (${response.status})`
|
|
52
|
+
message: (await response.json().catch(() => ({}))).errors?.[0]?.message ?? `Request failed (${response.status})`
|
|
53
53
|
};
|
|
54
54
|
};
|
|
55
55
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"submitForm.js","names":[],"sources":["../../src/react/submitForm.ts"],"sourcesContent":["import type { SubmissionValue } from '../submissions/types'\n\nexport type SubmitFormInput = {\n\tformId: number | string\n\tvalues: SubmissionValue[]\n\t/** Payload API route prefix; defaults to `/api`. */\n\tapiRoute?: string\n\t/** Injectable for testing; defaults to global `fetch`. */\n\tfetchImpl?: typeof fetch\n}\n\nexport type SubmitFormResult =\n\t| { ok: true; submissionId?: string }\n\t| { ok: false; fieldErrors?: Record<string, string[]>; message?: string }\n\ntype ValidationErrorBody = {\n\terrors?: Array<{\n\t\tmessage?: string\n\t\tdata?: { errors?: Array<{ path?: string; message?: string }> }\n\t}>\n}\n\nconst toFieldErrors = (body: ValidationErrorBody): Record<string, string[]> => {\n\tconst nested = body.errors?.[0]?.data?.errors ?? []\n\tconst map: Record<string, string[]> = {}\n\tfor (const entry of nested) {\n\t\tif (typeof entry.path === 'string' && typeof entry.message === 'string') {\n\t\t\tmap[entry.path] = [...(map[entry.path] ?? []), entry.message]\n\t\t}\n\t}\n\treturn map\n}\n\n/**\n * The default submission transport: POST `{apiRoute}/form-submissions` with `{ form, values }`. On 201\n * returns the created submission id; on a 400 Payload `ValidationError` maps `data.errors[].path` to\n * per-field messages; otherwise returns a generic message. Pure: inject `fetchImpl` in tests.\n */\nexport const submitForm = async (input: SubmitFormInput): Promise<SubmitFormResult> => {\n\tconst { formId, values, apiRoute = '/api', fetchImpl = fetch } = input\n\tlet response: Response\n\ttry {\n\t\tresponse = await fetchImpl(`${apiRoute}/form-submissions`, {\n\t\t\tmethod: 'POST',\n\t\t\theaders: { 'Content-Type': 'application/json' },\n\t\t\tbody: JSON.stringify({ form: formId, values }),\n\t\t})\n\t} catch (error) {\n\t\treturn { ok: false, message: error instanceof Error ? error.message : 'Network error' }\n\t}\n\tif (response.ok) {\n\t\tconst data = (await response.json().catch(() => ({}))) as { doc?: { id?: number | string } }\n\t\tconst id = data.doc?.id\n\t\treturn { ok: true, submissionId: id === undefined ? undefined : String(id) }\n\t}\n\tif (response.status === 400) {\n\t\tconst body = (await response.json().catch(() => ({}))) as ValidationErrorBody\n\t\tconst fieldErrors = toFieldErrors(body)\n\t\tif (Object.keys(fieldErrors).length > 0) {\n\t\t\treturn { ok: false, fieldErrors }\n\t\t}\n\t\treturn { ok: false, message: body.errors?.[0]?.message ?? 'Validation failed' }\n\t}\n\treturn { ok: false, message: `Request failed (${response.status})` }\n}\n\n/** A consumer override for the transport: given the form id + values, resolve to a submit result. */\nexport type SubmitHandler = (input: {\n\tformId: number | string\n\tvalues: SubmissionValue[]\n}) => Promise<SubmitFormResult>\n"],"mappings":";AAsBA,MAAM,iBAAiB,SAAwD;CAC9E,MAAM,SAAS,KAAK,SAAS,IAAI,MAAM,UAAU,CAAC;CAClD,MAAM,MAAgC,CAAC;CACvC,KAAK,MAAM,SAAS,QACnB,IAAI,OAAO,MAAM,SAAS,YAAY,OAAO,MAAM,YAAY,UAC9D,IAAI,MAAM,QAAQ,CAAC,GAAI,IAAI,MAAM,SAAS,CAAC,GAAI,MAAM,OAAO;CAG9D,OAAO;AACR;;;;;;AAOA,MAAa,aAAa,OAAO,UAAsD;CACtF,MAAM,EAAE,QAAQ,QAAQ,WAAW,QAAQ,YAAY,UAAU;CACjE,IAAI;CACJ,IAAI;EACH,WAAW,MAAM,UAAU,GAAG,SAAS,oBAAoB;GAC1D,QAAQ;GACR,SAAS,EAAE,gBAAgB,mBAAmB;GAC9C,MAAM,KAAK,UAAU;IAAE,MAAM;IAAQ;GAAO,CAAC;EAC9C,CAAC;CACF,SAAS,OAAO;EACf,OAAO;GAAE,IAAI;GAAO,SAAS,iBAAiB,QAAQ,MAAM,UAAU;EAAgB;CACvF;CACA,IAAI,SAAS,IAAI;EAEhB,MAAM,MAAK,MADS,SAAS,KAAK,EAAE,aAAa,CAAC,EAAE,GACpC,KAAK;EACrB,OAAO;GAAE,IAAI;GAAM,cAAc,OAAO,KAAA,IAAY,KAAA,IAAY,OAAO,EAAE;EAAE;CAC5E;CACA,IAAI,SAAS,WAAW,KAAK;EAC5B,MAAM,OAAQ,MAAM,SAAS,KAAK,EAAE,aAAa,CAAC,EAAE;EACpD,MAAM,cAAc,cAAc,IAAI;EACtC,IAAI,OAAO,KAAK,WAAW,EAAE,SAAS,GACrC,OAAO;GAAE,IAAI;GAAO;EAAY;EAEjC,OAAO;GAAE,IAAI;GAAO,SAAS,KAAK,SAAS,IAAI,WAAW;EAAoB;CAC/E;
|
|
1
|
+
{"version":3,"file":"submitForm.js","names":[],"sources":["../../src/react/submitForm.ts"],"sourcesContent":["import type { SubmissionValue } from '../submissions/types'\n\nexport type SubmitFormInput = {\n\tformId: number | string\n\tvalues: SubmissionValue[]\n\t/** Payload API route prefix; defaults to `/api`. */\n\tapiRoute?: string\n\t/** Injectable for testing; defaults to global `fetch`. */\n\tfetchImpl?: typeof fetch\n}\n\nexport type SubmitFormResult =\n\t| { ok: true; submissionId?: string }\n\t| { ok: false; fieldErrors?: Record<string, string[]>; message?: string }\n\ntype ValidationErrorBody = {\n\terrors?: Array<{\n\t\tmessage?: string\n\t\tdata?: { errors?: Array<{ path?: string; message?: string }> }\n\t}>\n}\n\nconst toFieldErrors = (body: ValidationErrorBody): Record<string, string[]> => {\n\tconst nested = body.errors?.[0]?.data?.errors ?? []\n\tconst map: Record<string, string[]> = {}\n\tfor (const entry of nested) {\n\t\tif (typeof entry.path === 'string' && typeof entry.message === 'string') {\n\t\t\tmap[entry.path] = [...(map[entry.path] ?? []), entry.message]\n\t\t}\n\t}\n\treturn map\n}\n\n/**\n * The default submission transport: POST `{apiRoute}/form-submissions` with `{ form, values }`. On 201\n * returns the created submission id; on a 400 Payload `ValidationError` maps `data.errors[].path` to\n * per-field messages; otherwise returns a generic message. Pure: inject `fetchImpl` in tests.\n */\nexport const submitForm = async (input: SubmitFormInput): Promise<SubmitFormResult> => {\n\tconst { formId, values, apiRoute = '/api', fetchImpl = fetch } = input\n\tlet response: Response\n\ttry {\n\t\tresponse = await fetchImpl(`${apiRoute}/form-submissions`, {\n\t\t\tmethod: 'POST',\n\t\t\theaders: { 'Content-Type': 'application/json' },\n\t\t\tbody: JSON.stringify({ form: formId, values }),\n\t\t})\n\t} catch (error) {\n\t\treturn { ok: false, message: error instanceof Error ? error.message : 'Network error' }\n\t}\n\tif (response.ok) {\n\t\tconst data = (await response.json().catch(() => ({}))) as { doc?: { id?: number | string } }\n\t\tconst id = data.doc?.id\n\t\treturn { ok: true, submissionId: id === undefined ? undefined : String(id) }\n\t}\n\tif (response.status === 400) {\n\t\tconst body = (await response.json().catch(() => ({}))) as ValidationErrorBody\n\t\tconst fieldErrors = toFieldErrors(body)\n\t\tif (Object.keys(fieldErrors).length > 0) {\n\t\t\treturn { ok: false, fieldErrors }\n\t\t}\n\t\treturn { ok: false, message: body.errors?.[0]?.message ?? 'Validation failed' }\n\t}\n\t// A non-400 failure can still carry a server-authored message worth showing verbatim, e.g. the\n\t// translated essential-action rejection; fall back to the generic line when there is none.\n\tconst body = (await response.json().catch(() => ({}))) as ValidationErrorBody\n\tconst message = body.errors?.[0]?.message\n\treturn { ok: false, message: message ?? `Request failed (${response.status})` }\n}\n\n/** A consumer override for the transport: given the form id + values, resolve to a submit result. */\nexport type SubmitHandler = (input: {\n\tformId: number | string\n\tvalues: SubmissionValue[]\n}) => Promise<SubmitFormResult>\n"],"mappings":";AAsBA,MAAM,iBAAiB,SAAwD;CAC9E,MAAM,SAAS,KAAK,SAAS,IAAI,MAAM,UAAU,CAAC;CAClD,MAAM,MAAgC,CAAC;CACvC,KAAK,MAAM,SAAS,QACnB,IAAI,OAAO,MAAM,SAAS,YAAY,OAAO,MAAM,YAAY,UAC9D,IAAI,MAAM,QAAQ,CAAC,GAAI,IAAI,MAAM,SAAS,CAAC,GAAI,MAAM,OAAO;CAG9D,OAAO;AACR;;;;;;AAOA,MAAa,aAAa,OAAO,UAAsD;CACtF,MAAM,EAAE,QAAQ,QAAQ,WAAW,QAAQ,YAAY,UAAU;CACjE,IAAI;CACJ,IAAI;EACH,WAAW,MAAM,UAAU,GAAG,SAAS,oBAAoB;GAC1D,QAAQ;GACR,SAAS,EAAE,gBAAgB,mBAAmB;GAC9C,MAAM,KAAK,UAAU;IAAE,MAAM;IAAQ;GAAO,CAAC;EAC9C,CAAC;CACF,SAAS,OAAO;EACf,OAAO;GAAE,IAAI;GAAO,SAAS,iBAAiB,QAAQ,MAAM,UAAU;EAAgB;CACvF;CACA,IAAI,SAAS,IAAI;EAEhB,MAAM,MAAK,MADS,SAAS,KAAK,EAAE,aAAa,CAAC,EAAE,GACpC,KAAK;EACrB,OAAO;GAAE,IAAI;GAAM,cAAc,OAAO,KAAA,IAAY,KAAA,IAAY,OAAO,EAAE;EAAE;CAC5E;CACA,IAAI,SAAS,WAAW,KAAK;EAC5B,MAAM,OAAQ,MAAM,SAAS,KAAK,EAAE,aAAa,CAAC,EAAE;EACpD,MAAM,cAAc,cAAc,IAAI;EACtC,IAAI,OAAO,KAAK,WAAW,EAAE,SAAS,GACrC,OAAO;GAAE,IAAI;GAAO;EAAY;EAEjC,OAAO;GAAE,IAAI;GAAO,SAAS,KAAK,SAAS,IAAI,WAAW;EAAoB;CAC/E;CAKA,OAAO;EAAE,IAAI;EAAO,UADJ,MADI,SAAS,KAAK,EAAE,aAAa,CAAC,EAAE,GAC/B,SAAS,IAAI,WACM,mBAAmB,SAAS,OAAO;CAAG;AAC/E"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
//#region src/react/uploadFile.d.ts
|
|
2
2
|
type UploadFileInput = {
|
|
3
|
-
file: File; /** Upload collection slug.
|
|
4
|
-
collection
|
|
3
|
+
file: File; /** Upload collection slug. File fields carry it as the server-stamped `collection` block config. */
|
|
4
|
+
collection: string;
|
|
5
5
|
apiRoute?: string;
|
|
6
6
|
fetchImpl?: typeof fetch;
|
|
7
7
|
};
|
package/dist/react/uploadFile.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* at submit, so the client is never trusted for it. Pure: inject `fetchImpl` in tests.
|
|
6
6
|
*/
|
|
7
7
|
const uploadFile = async (input) => {
|
|
8
|
-
const { file, collection
|
|
8
|
+
const { file, collection, apiRoute = "/api", fetchImpl = fetch } = input;
|
|
9
9
|
const body = new FormData();
|
|
10
10
|
body.append("file", file);
|
|
11
11
|
let response;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"uploadFile.js","names":[],"sources":["../../src/react/uploadFile.ts"],"sourcesContent":["export type UploadFileInput = {\n\tfile: File\n\t/** Upload collection slug.
|
|
1
|
+
{"version":3,"file":"uploadFile.js","names":[],"sources":["../../src/react/uploadFile.ts"],"sourcesContent":["export type UploadFileInput = {\n\tfile: File\n\t/** Upload collection slug. File fields carry it as the server-stamped `collection` block config. */\n\tcollection: string\n\tapiRoute?: string\n\tfetchImpl?: typeof fetch\n}\n\nexport type UploadFileResult = { ok: true; id: string | number } | { ok: false; message?: string }\n\n/**\n * Upload one file to a Payload upload collection (`POST {apiRoute}/{collection}`, multipart) and return its\n * id, which the file field stores as its value. The server re-derives the file metadata from the stored doc\n * at submit, so the client is never trusted for it. Pure: inject `fetchImpl` in tests.\n */\nexport const uploadFile = async (input: UploadFileInput): Promise<UploadFileResult> => {\n\tconst { file, collection, apiRoute = '/api', fetchImpl = fetch } = input\n\tconst body = new FormData()\n\tbody.append('file', file)\n\tlet response: Response\n\ttry {\n\t\tresponse = await fetchImpl(`${apiRoute}/${collection}`, { method: 'POST', body })\n\t} catch (error) {\n\t\treturn { ok: false, message: error instanceof Error ? error.message : 'Network error' }\n\t}\n\tif (!response.ok) {\n\t\treturn { ok: false, message: `Upload failed (${response.status})` }\n\t}\n\tconst data = (await response.json().catch(() => ({}))) as { doc?: { id?: string | number } }\n\tconst id = data.doc?.id\n\treturn id == null ? { ok: false, message: 'No id returned' } : { ok: true, id }\n}\n"],"mappings":";;;;;;AAeA,MAAa,aAAa,OAAO,UAAsD;CACtF,MAAM,EAAE,MAAM,YAAY,WAAW,QAAQ,YAAY,UAAU;CACnE,MAAM,OAAO,IAAI,SAAS;CAC1B,KAAK,OAAO,QAAQ,IAAI;CACxB,IAAI;CACJ,IAAI;EACH,WAAW,MAAM,UAAU,GAAG,SAAS,GAAG,cAAc;GAAE,QAAQ;GAAQ;EAAK,CAAC;CACjF,SAAS,OAAO;EACf,OAAO;GAAE,IAAI;GAAO,SAAS,iBAAiB,QAAQ,MAAM,UAAU;EAAgB;CACvF;CACA,IAAI,CAAC,SAAS,IACb,OAAO;EAAE,IAAI;EAAO,SAAS,kBAAkB,SAAS,OAAO;CAAG;CAGnE,MAAM,MAAK,MADS,SAAS,KAAK,EAAE,aAAa,CAAC,EAAE,GACpC,KAAK;CACrB,OAAO,MAAM,OAAO;EAAE,IAAI;EAAO,SAAS;CAAiB,IAAI;EAAE,IAAI;EAAM;CAAG;AAC/E"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
//#region src/react/useCalcValues.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Live computed calculation values (field name -> number), recomputed as answers change. For
|
|
4
|
+
* composed frontends (custom layouts over `useFormContext`/`FormFields`) that render running
|
|
5
|
+
* totals without re-evaluating expressions themselves.
|
|
6
|
+
*/
|
|
7
|
+
declare const useCalcValues: () => Record<string, number>;
|
|
8
|
+
//#endregion
|
|
9
|
+
export { useCalcValues };
|
|
10
|
+
//# sourceMappingURL=useCalcValues.d.ts.map
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useFormContext } from "./FormContext.js";
|
|
3
|
+
//#region src/react/useCalcValues.ts
|
|
4
|
+
/**
|
|
5
|
+
* Live computed calculation values (field name -> number), recomputed as answers change. For
|
|
6
|
+
* composed frontends (custom layouts over `useFormContext`/`FormFields`) that render running
|
|
7
|
+
* totals without re-evaluating expressions themselves.
|
|
8
|
+
*/
|
|
9
|
+
const useCalcValues = () => useFormContext().calcValues ?? {};
|
|
10
|
+
//#endregion
|
|
11
|
+
export { useCalcValues };
|
|
12
|
+
|
|
13
|
+
//# sourceMappingURL=useCalcValues.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useCalcValues.js","names":[],"sources":["../../src/react/useCalcValues.ts"],"sourcesContent":["'use client'\n\nimport { useFormContext } from './FormContext'\n\n/**\n * Live computed calculation values (field name -> number), recomputed as answers change. For\n * composed frontends (custom layouts over `useFormContext`/`FormFields`) that render running\n * totals without re-evaluating expressions themselves.\n */\nexport const useCalcValues = (): Record<string, number> => useFormContext().calcValues ?? {}\n"],"mappings":";;;;;;;;AASA,MAAa,sBAA8C,eAAe,EAAE,cAAc,CAAC"}
|
package/dist/react/useField.d.ts
CHANGED
package/dist/react/useField.js
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { useFormContext } from "./FormContext.js";
|
|
3
|
+
import "./state.js";
|
|
3
4
|
import { useCallback } from "react";
|
|
4
5
|
//#region src/react/useField.ts
|
|
5
6
|
/** Bind one field by name to the form controller: its value, issues, and change/blur handlers. */
|
|
6
7
|
const useField = (name) => {
|
|
7
|
-
const { state, dispatch, validateField } = useFormContext();
|
|
8
|
+
const { state, dispatch, validateField, stepIdOfField } = useFormContext();
|
|
8
9
|
const touched = state.touched[name] ?? false;
|
|
9
|
-
const
|
|
10
|
+
const dirty = state.dirty[name] ?? false;
|
|
11
|
+
const stepAttempted = state.attemptedSteps.has(stepIdOfField?.(name) ?? "__form__");
|
|
12
|
+
const showIssues = touched && dirty || stepAttempted;
|
|
10
13
|
const value = state.values[name];
|
|
11
14
|
const setValue = useCallback((next) => {
|
|
12
15
|
dispatch({
|
|
@@ -14,12 +17,11 @@ const useField = (name) => {
|
|
|
14
17
|
name,
|
|
15
18
|
value: next
|
|
16
19
|
});
|
|
17
|
-
if (
|
|
20
|
+
if (showIssues) validateField(name, next);
|
|
18
21
|
}, [
|
|
19
22
|
dispatch,
|
|
20
23
|
name,
|
|
21
|
-
|
|
22
|
-
state.submitAttempted,
|
|
24
|
+
showIssues,
|
|
23
25
|
validateField
|
|
24
26
|
]);
|
|
25
27
|
const onBlur = useCallback(() => {
|
|
@@ -37,7 +39,6 @@ const useField = (name) => {
|
|
|
37
39
|
return {
|
|
38
40
|
value,
|
|
39
41
|
errors: showIssues ? state.errors[name] ?? [] : [],
|
|
40
|
-
warnings: showIssues ? state.warnings[name] ?? [] : [],
|
|
41
42
|
touched,
|
|
42
43
|
setValue,
|
|
43
44
|
onBlur
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useField.js","names":[],"sources":["../../src/react/useField.ts"],"sourcesContent":["'use client'\n\nimport { useCallback } from 'react'\nimport { useFormContext } from './FormContext'\n\nexport type UseFieldResult<TValue = unknown> = {\n\tvalue: TValue | undefined\n\terrors: string[]\n\
|
|
1
|
+
{"version":3,"file":"useField.js","names":[],"sources":["../../src/react/useField.ts"],"sourcesContent":["'use client'\n\nimport { useCallback } from 'react'\nimport { useFormContext } from './FormContext'\nimport { DEFAULT_STEP_ID } from './state'\n\nexport type UseFieldResult<TValue = unknown> = {\n\tvalue: TValue | undefined\n\terrors: string[]\n\ttouched: boolean\n\tsetValue: (value: TValue) => void\n\t/** Mark touched and validate now (call on blur). */\n\tonBlur: () => void\n}\n\n/** Bind one field by name to the form controller: its value, issues, and change/blur handlers. */\nexport const useField = <TValue = unknown>(name: string): UseFieldResult<TValue> => {\n\tconst { state, dispatch, validateField, stepIdOfField } = useFormContext()\n\tconst touched = state.touched[name] ?? false\n\tconst dirty = state.dirty[name] ?? false\n\t// Reveal is a function of this field's own step, never a single global flag: the field's error\n\t// shows once it is touched AND dirty (a pristine blur, focus-then-leave, reveals nothing), or\n\t// once the step it belongs to has been attempted (a blocked advance or submit).\n\tconst stepAttempted = state.attemptedSteps.has(stepIdOfField?.(name) ?? DEFAULT_STEP_ID)\n\tconst showIssues = (touched && dirty) || stepAttempted\n\tconst value = state.values[name] as TValue | undefined\n\n\tconst setValue = useCallback(\n\t\t(next: TValue) => {\n\t\t\tdispatch({ type: 'SET_VALUE', name, value: next })\n\t\t\t// Re-validate on change only once the error is already revealed; never reveal an untouched field mid-typing.\n\t\t\tif (showIssues) {\n\t\t\t\tvalidateField(name, next)\n\t\t\t}\n\t\t},\n\t\t[dispatch, name, showIssues, validateField]\n\t)\n\n\tconst onBlur = useCallback(() => {\n\t\tdispatch({ type: 'TOUCH', name })\n\t\tvalidateField(name, value)\n\t}, [dispatch, name, validateField, value])\n\n\treturn {\n\t\tvalue,\n\t\terrors: showIssues ? (state.errors[name] ?? []) : [],\n\t\ttouched,\n\t\tsetValue,\n\t\tonBlur,\n\t}\n}\n"],"mappings":";;;;;;AAgBA,MAAa,YAA8B,SAAyC;CACnF,MAAM,EAAE,OAAO,UAAU,eAAe,kBAAkB,eAAe;CACzE,MAAM,UAAU,MAAM,QAAQ,SAAS;CACvC,MAAM,QAAQ,MAAM,MAAM,SAAS;CAInC,MAAM,gBAAgB,MAAM,eAAe,IAAI,gBAAgB,IAAI,KAAA,UAAoB;CACvF,MAAM,aAAc,WAAW,SAAU;CACzC,MAAM,QAAQ,MAAM,OAAO;CAE3B,MAAM,WAAW,aACf,SAAiB;EACjB,SAAS;GAAE,MAAM;GAAa;GAAM,OAAO;EAAK,CAAC;EAEjD,IAAI,YACH,cAAc,MAAM,IAAI;CAE1B,GACA;EAAC;EAAU;EAAM;EAAY;CAAa,CAC3C;CAEA,MAAM,SAAS,kBAAkB;EAChC,SAAS;GAAE,MAAM;GAAS;EAAK,CAAC;EAChC,cAAc,MAAM,KAAK;CAC1B,GAAG;EAAC;EAAU;EAAM;EAAe;CAAK,CAAC;CAEzC,OAAO;EACN;EACA,QAAQ,aAAc,MAAM,OAAO,SAAS,CAAC,IAAK,CAAC;EACnD;EACA;EACA;CACD;AACD"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { FormState } from "./state.js";
|
|
2
2
|
|
|
3
3
|
//#region src/react/useFormState.d.ts
|
|
4
|
-
/** The whole form state (values, errors,
|
|
4
|
+
/** The whole form state (values, errors, touched, submitting, submitted, submitError). */
|
|
5
5
|
declare const useFormState: () => FormState;
|
|
6
6
|
//#endregion
|
|
7
7
|
export { useFormState };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { useFormContext } from "./FormContext.js";
|
|
3
3
|
//#region src/react/useFormState.ts
|
|
4
|
-
/** The whole form state (values, errors,
|
|
4
|
+
/** The whole form state (values, errors, touched, submitting, submitted, submitError). */
|
|
5
5
|
const useFormState = () => useFormContext().state;
|
|
6
6
|
//#endregion
|
|
7
7
|
export { useFormState };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useFormState.js","names":[],"sources":["../../src/react/useFormState.ts"],"sourcesContent":["'use client'\n\nimport { useFormContext } from './FormContext'\nimport type { FormState } from './state'\n\n/** The whole form state (values, errors,
|
|
1
|
+
{"version":3,"file":"useFormState.js","names":[],"sources":["../../src/react/useFormState.ts"],"sourcesContent":["'use client'\n\nimport { useFormContext } from './FormContext'\nimport type { FormState } from './state'\n\n/** The whole form state (values, errors, touched, submitting, submitted, submitError). */\nexport const useFormState = (): FormState => useFormContext().state\n"],"mappings":";;;;AAMA,MAAa,qBAAgC,eAAe,EAAE"}
|
|
@@ -2,11 +2,11 @@ import { runValidation } from "../validation/runValidation.js";
|
|
|
2
2
|
//#region src/react/validateField.ts
|
|
3
3
|
/**
|
|
4
4
|
* Run client-side validation for one field, reusing the shared engine in `mode: 'client'` (server-only
|
|
5
|
-
* rules are skipped, no `req`/`payload`).
|
|
5
|
+
* rules are skipped, no `req`/`payload`). Every returned message is a blocking error.
|
|
6
6
|
*/
|
|
7
7
|
const validateFieldValue = async (input) => {
|
|
8
8
|
const { field, value, registry, ruleRegistry, answers, locale, t } = input;
|
|
9
|
-
const { errors
|
|
9
|
+
const { errors } = await runValidation({
|
|
10
10
|
field,
|
|
11
11
|
fieldDefinition: registry.get(field.blockType),
|
|
12
12
|
value,
|
|
@@ -19,10 +19,7 @@ const validateFieldValue = async (input) => {
|
|
|
19
19
|
event: "onChange",
|
|
20
20
|
mode: "client"
|
|
21
21
|
});
|
|
22
|
-
return {
|
|
23
|
-
errors: issues.filter((issue) => issue.severity === "error").map((issue) => issue.message),
|
|
24
|
-
warnings: issues.filter((issue) => issue.severity === "warning").map((issue) => issue.message)
|
|
25
|
-
};
|
|
22
|
+
return { errors };
|
|
26
23
|
};
|
|
27
24
|
//#endregion
|
|
28
25
|
export { validateFieldValue };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validateField.js","names":[],"sources":["../../src/react/validateField.ts"],"sourcesContent":["import type { FieldTypeRegistry } from '../fields/registry'\nimport type { Translate } from '../fields/types'\nimport type { FormFieldInstance } from '../submissions/types'\nimport type { ValidationRuleRegistry } from '../validation/registry'\nimport { runValidation } from '../validation/runValidation'\n\nexport type ValidateFieldInput = {\n\tfield: FormFieldInstance\n\tvalue: unknown\n\tregistry: FieldTypeRegistry\n\truleRegistry: ValidationRuleRegistry\n\tanswers: Record<string, unknown>\n\tlocale: string\n\tt: Translate\n}\n\nexport type ValidateFieldResult = { errors: string[]
|
|
1
|
+
{"version":3,"file":"validateField.js","names":[],"sources":["../../src/react/validateField.ts"],"sourcesContent":["import type { FieldTypeRegistry } from '../fields/registry'\nimport type { Translate } from '../fields/types'\nimport type { FormFieldInstance } from '../submissions/types'\nimport type { ValidationRuleRegistry } from '../validation/registry'\nimport { runValidation } from '../validation/runValidation'\n\nexport type ValidateFieldInput = {\n\tfield: FormFieldInstance\n\tvalue: unknown\n\tregistry: FieldTypeRegistry\n\truleRegistry: ValidationRuleRegistry\n\tanswers: Record<string, unknown>\n\tlocale: string\n\tt: Translate\n}\n\nexport type ValidateFieldResult = { errors: string[] }\n\n/**\n * Run client-side validation for one field, reusing the shared engine in `mode: 'client'` (server-only\n * rules are skipped, no `req`/`payload`). Every returned message is a blocking error.\n */\nexport const validateFieldValue = async (\n\tinput: ValidateFieldInput\n): Promise<ValidateFieldResult> => {\n\tconst { field, value, registry, ruleRegistry, answers, locale, t } = input\n\tconst { errors } = await runValidation({\n\t\tfield,\n\t\tfieldDefinition: registry.get(field.blockType),\n\t\tvalue,\n\t\tfieldType: field.blockType,\n\t\truleRegistry,\n\t\tanswers,\n\t\tlocale,\n\t\tt,\n\t\toperation: 'create',\n\t\tevent: 'onChange',\n\t\tmode: 'client',\n\t})\n\treturn { errors }\n}\n"],"mappings":";;;;;;AAsBA,MAAa,qBAAqB,OACjC,UACkC;CAClC,MAAM,EAAE,OAAO,OAAO,UAAU,cAAc,SAAS,QAAQ,MAAM;CACrE,MAAM,EAAE,WAAW,MAAM,cAAc;EACtC;EACA,iBAAiB,SAAS,IAAI,MAAM,SAAS;EAC7C;EACA,WAAW,MAAM;EACjB;EACA;EACA;EACA;EACA,WAAW;EACX,OAAO;EACP,MAAM;CACP,CAAC;CACD,OAAO,EAAE,OAAO;AACjB"}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
//#region src/recall/interpolate.d.ts
|
|
2
2
|
/**
|
|
3
|
-
* Replace `{{ name }}
|
|
4
|
-
*
|
|
5
|
-
*
|
|
3
|
+
* Replace `{{ name }}`, `{{ name|fallback }}`, and `{{ name||fallback }}` tokens (single and
|
|
4
|
+
* double pipe are equivalent; the second pipe is just consumed, not part of the fallback text).
|
|
5
|
+
* `resolve` returns the recalled value ('' when absent); the fallback (or '') is substituted when
|
|
6
|
+
* `resolve` yields ''. Token-free input is returned unchanged, so this is a no-op for ordinary text.
|
|
6
7
|
*/
|
|
7
8
|
declare const interpolate: (template: string, resolve: (name: string) => string) => string;
|
|
8
9
|
//#endregion
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
//#region src/recall/interpolate.ts
|
|
2
|
-
const TOKEN = /\{\{\s*([^{}|]+?)\s*(
|
|
2
|
+
const TOKEN = /\{\{\s*([^{}|]+?)\s*(?:\|\|?([^{}]*?))?\}\}/g;
|
|
3
3
|
/**
|
|
4
|
-
* Replace `{{ name }}
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* Replace `{{ name }}`, `{{ name|fallback }}`, and `{{ name||fallback }}` tokens (single and
|
|
5
|
+
* double pipe are equivalent; the second pipe is just consumed, not part of the fallback text).
|
|
6
|
+
* `resolve` returns the recalled value ('' when absent); the fallback (or '') is substituted when
|
|
7
|
+
* `resolve` yields ''. Token-free input is returned unchanged, so this is a no-op for ordinary text.
|
|
7
8
|
*/
|
|
8
9
|
const interpolate = (template, resolve) => template.replace(TOKEN, (_match, rawName, rawFallback) => {
|
|
9
10
|
const value = resolve(rawName.trim());
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"interpolate.js","names":[],"sources":["../../src/recall/interpolate.ts"],"sourcesContent":["const TOKEN = /\\{\\{\\s*([^{}|]+?)\\s*(
|
|
1
|
+
{"version":3,"file":"interpolate.js","names":[],"sources":["../../src/recall/interpolate.ts"],"sourcesContent":["const TOKEN = /\\{\\{\\s*([^{}|]+?)\\s*(?:\\|\\|?([^{}]*?))?\\}\\}/g\n\n/**\n * Replace `{{ name }}`, `{{ name|fallback }}`, and `{{ name||fallback }}` tokens (single and\n * double pipe are equivalent; the second pipe is just consumed, not part of the fallback text).\n * `resolve` returns the recalled value ('' when absent); the fallback (or '') is substituted when\n * `resolve` yields ''. Token-free input is returned unchanged, so this is a no-op for ordinary text.\n */\nexport const interpolate = (template: string, resolve: (name: string) => string): string =>\n\ttemplate.replace(TOKEN, (_match, rawName: string, rawFallback?: string) => {\n\t\tconst value = resolve(rawName.trim())\n\t\tif (value !== '') {\n\t\t\treturn value\n\t\t}\n\t\treturn rawFallback === undefined ? '' : rawFallback.trim()\n\t})\n"],"mappings":";AAAA,MAAM,QAAQ;;;;;;;AAQd,MAAa,eAAe,UAAkB,YAC7C,SAAS,QAAQ,QAAQ,QAAQ,SAAiB,gBAAyB;CAC1E,MAAM,QAAQ,QAAQ,QAAQ,KAAK,CAAC;CACpC,IAAI,UAAU,IACb,OAAO;CAER,OAAO,gBAAgB,KAAA,IAAY,KAAK,YAAY,KAAK;AAC1D,CAAC"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { AnyFormFieldDefinition } from "../fields/types.js";
|
|
2
1
|
import { FormFieldInstance } from "../submissions/types.js";
|
|
2
|
+
import { AnyFormFieldDefinition } from "../fields/types.js";
|
|
3
3
|
|
|
4
4
|
//#region src/recall/resolver.d.ts
|
|
5
5
|
type RecallResolver = (name: string) => string;
|
package/dist/recall/resolver.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
+
import { isNamedField } from "../fields/fieldKey.js";
|
|
1
2
|
//#region src/recall/resolver.ts
|
|
2
3
|
/** Derive a value->label map from a select-like field instance's `options`. */
|
|
3
4
|
const optionLabelsFor = (field) => {
|
|
4
5
|
const options = field.options;
|
|
5
6
|
if (!Array.isArray(options)) return;
|
|
6
7
|
const map = {};
|
|
7
|
-
for (const option of options) if (option && typeof option.value === "string") map[option.value] = option.label
|
|
8
|
+
for (const option of options) if (option && typeof option.value === "string") map[option.value] = option.label?.trim() ? option.label : option.value;
|
|
8
9
|
return Object.keys(map).length > 0 ? map : void 0;
|
|
9
10
|
};
|
|
10
11
|
/**
|
|
@@ -13,7 +14,7 @@ const optionLabelsFor = (field) => {
|
|
|
13
14
|
* value -> ''. Pure and isomorphic; the renderer and server templates share it.
|
|
14
15
|
*/
|
|
15
16
|
const buildRecallResolver = (args) => {
|
|
16
|
-
const byName = new Map(args.fields.map((field) => [field.name, field]));
|
|
17
|
+
const byName = new Map(args.fields.filter(isNamedField).map((field) => [field.name, field]));
|
|
17
18
|
return (name) => {
|
|
18
19
|
const field = byName.get(name);
|
|
19
20
|
if (!field) return "";
|
|
@@ -30,7 +31,18 @@ const buildRecallResolver = (args) => {
|
|
|
30
31
|
return Array.isArray(value) ? value.join(", ") : String(value);
|
|
31
32
|
};
|
|
32
33
|
};
|
|
34
|
+
/**
|
|
35
|
+
* Build a submission-shaped descriptor per named field: the client-side counterpart to the
|
|
36
|
+
* per-field descriptors `runSubmission` snapshots server-side. Lets client-rendered templates
|
|
37
|
+
* (the response message) label rows the same way server-rendered ones (email-team) do. `optionLabels`
|
|
38
|
+
* is omitted: pair with values already formatted via `buildRecallResolver`, not raw stored values.
|
|
39
|
+
*/
|
|
40
|
+
const descriptorsFor = (fields) => fields.filter(isNamedField).map((field) => ({
|
|
41
|
+
field: field.name,
|
|
42
|
+
label: field.label ?? field.name,
|
|
43
|
+
fieldType: field.blockType
|
|
44
|
+
}));
|
|
33
45
|
//#endregion
|
|
34
|
-
export { buildRecallResolver, optionLabelsFor };
|
|
46
|
+
export { buildRecallResolver, descriptorsFor, optionLabelsFor };
|
|
35
47
|
|
|
36
48
|
//# sourceMappingURL=resolver.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolver.js","names":[],"sources":["../../src/recall/resolver.ts"],"sourcesContent":["import type { AnyFormFieldDefinition } from '../fields/types'\nimport type { FormFieldInstance } from '../submissions/types'\n\nexport type RecallResolver = (name: string) => string\n\ntype Option = { label?: string; value?: string }\n\n/** Derive a value->label map from a select-like field instance's `options`. */\nexport const optionLabelsFor = (field: FormFieldInstance): Record<string, string> | undefined => {\n\tconst options = field.options\n\tif (!Array.isArray(options)) {\n\t\treturn undefined\n\t}\n\tconst map: Record<string, string> = {}\n\tfor (const option of options as Option[]) {\n\t\tif (option && typeof option.value === 'string') {\n\t\t\tmap[option.value] = option.label
|
|
1
|
+
{"version":3,"file":"resolver.js","names":[],"sources":["../../src/recall/resolver.ts"],"sourcesContent":["import { isNamedField } from '../fields/fieldKey'\nimport type { AnyFormFieldDefinition } from '../fields/types'\nimport type { FormFieldInstance, SubmissionDescriptor } from '../submissions/types'\n\nexport type RecallResolver = (name: string) => string\n\ntype Option = { label?: string; value?: string }\n\n/** Derive a value->label map from a select-like field instance's `options`. */\nexport const optionLabelsFor = (field: FormFieldInstance): Record<string, string> | undefined => {\n\tconst options = field.options\n\tif (!Array.isArray(options)) {\n\t\treturn undefined\n\t}\n\tconst map: Record<string, string> = {}\n\tfor (const option of options as Option[]) {\n\t\tif (option && typeof option.value === 'string') {\n\t\t\tmap[option.value] = option.label?.trim() ? option.label : option.value\n\t\t}\n\t}\n\treturn Object.keys(map).length > 0 ? map : undefined\n}\n\n/**\n * Build a recall resolver: `{{name}}` -> the field's current value, formatted via its type's `format`\n * (so a select shows its option label, a checkbox Yes/No, a date localized). Missing field or empty\n * value -> ''. Pure and isomorphic; the renderer and server templates share it.\n */\nexport const buildRecallResolver = (args: {\n\tfields: FormFieldInstance[]\n\tvalues: Record<string, unknown>\n\tregistry: Map<string, AnyFormFieldDefinition>\n\tlocale: string\n\tt: (key: string) => string\n}): RecallResolver => {\n\tconst byName = new Map(args.fields.filter(isNamedField).map((field) => [field.name, field]))\n\treturn (name) => {\n\t\tconst field = byName.get(name)\n\t\tif (!field) {\n\t\t\treturn ''\n\t\t}\n\t\tconst value = args.values[name]\n\t\tif (value == null || value === '' || (Array.isArray(value) && value.length === 0)) {\n\t\t\treturn ''\n\t\t}\n\t\tconst definition = args.registry.get(field.blockType)\n\t\tif (definition?.format) {\n\t\t\treturn definition.format({\n\t\t\t\tvalue,\n\t\t\t\tconfig: {},\n\t\t\t\toptionLabels: optionLabelsFor(field),\n\t\t\t\tlocale: args.locale,\n\t\t\t\tt: args.t,\n\t\t\t})\n\t\t}\n\t\treturn Array.isArray(value) ? value.join(', ') : String(value)\n\t}\n}\n\n/**\n * Build a submission-shaped descriptor per named field: the client-side counterpart to the\n * per-field descriptors `runSubmission` snapshots server-side. Lets client-rendered templates\n * (the response message) label rows the same way server-rendered ones (email-team) do. `optionLabels`\n * is omitted: pair with values already formatted via `buildRecallResolver`, not raw stored values.\n */\nexport const descriptorsFor = (fields: FormFieldInstance[]): SubmissionDescriptor[] =>\n\tfields.filter(isNamedField).map((field) => ({\n\t\tfield: field.name,\n\t\tlabel: field.label ?? field.name,\n\t\tfieldType: field.blockType,\n\t}))\n"],"mappings":";;;AASA,MAAa,mBAAmB,UAAiE;CAChG,MAAM,UAAU,MAAM;CACtB,IAAI,CAAC,MAAM,QAAQ,OAAO,GACzB;CAED,MAAM,MAA8B,CAAC;CACrC,KAAK,MAAM,UAAU,SACpB,IAAI,UAAU,OAAO,OAAO,UAAU,UACrC,IAAI,OAAO,SAAS,OAAO,OAAO,KAAK,IAAI,OAAO,QAAQ,OAAO;CAGnE,OAAO,OAAO,KAAK,GAAG,EAAE,SAAS,IAAI,MAAM,KAAA;AAC5C;;;;;;AAOA,MAAa,uBAAuB,SAMd;CACrB,MAAM,SAAS,IAAI,IAAI,KAAK,OAAO,OAAO,YAAY,EAAE,KAAK,UAAU,CAAC,MAAM,MAAM,KAAK,CAAC,CAAC;CAC3F,QAAQ,SAAS;EAChB,MAAM,QAAQ,OAAO,IAAI,IAAI;EAC7B,IAAI,CAAC,OACJ,OAAO;EAER,MAAM,QAAQ,KAAK,OAAO;EAC1B,IAAI,SAAS,QAAQ,UAAU,MAAO,MAAM,QAAQ,KAAK,KAAK,MAAM,WAAW,GAC9E,OAAO;EAER,MAAM,aAAa,KAAK,SAAS,IAAI,MAAM,SAAS;EACpD,IAAI,YAAY,QACf,OAAO,WAAW,OAAO;GACxB;GACA,QAAQ,CAAC;GACT,cAAc,gBAAgB,KAAK;GACnC,QAAQ,KAAK;GACb,GAAG,KAAK;EACT,CAAC;EAEF,OAAO,MAAM,QAAQ,KAAK,IAAI,MAAM,KAAK,IAAI,IAAI,OAAO,KAAK;CAC9D;AACD;;;;;;;AAQA,MAAa,kBAAkB,WAC9B,OAAO,OAAO,YAAY,EAAE,KAAK,WAAW;CAC3C,OAAO,MAAM;CACb,OAAO,MAAM,SAAS,MAAM;CAC5B,WAAW,MAAM;AAClB,EAAE"}
|
package/dist/spam/captcha.d.ts
CHANGED
|
@@ -2,9 +2,10 @@ import { CaptchaProvider } from "./types.js";
|
|
|
2
2
|
|
|
3
3
|
//#region src/spam/captcha.d.ts
|
|
4
4
|
/**
|
|
5
|
-
* Identity helper for authoring a captcha provider (mirrors `defineAction`/`
|
|
6
|
-
*
|
|
7
|
-
*
|
|
5
|
+
* Identity helper for authoring a captcha provider (mirrors `defineAction`/`definePollOptionSource`).
|
|
6
|
+
* Bundled adapters (`turnstileProvider`, `recaptchaProvider`, `hcaptchaProvider`) are built with it;
|
|
7
|
+
* use it directly for any other verification service. The submit path verifies a token carried on
|
|
8
|
+
* the submission.
|
|
8
9
|
*/
|
|
9
10
|
declare const defineCaptchaProvider: (provider: CaptchaProvider) => CaptchaProvider;
|
|
10
11
|
//#endregion
|
package/dist/spam/captcha.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
//#region src/spam/captcha.ts
|
|
2
2
|
/**
|
|
3
|
-
* Identity helper for authoring a captcha provider (mirrors `defineAction`/`
|
|
4
|
-
*
|
|
5
|
-
*
|
|
3
|
+
* Identity helper for authoring a captcha provider (mirrors `defineAction`/`definePollOptionSource`).
|
|
4
|
+
* Bundled adapters (`turnstileProvider`, `recaptchaProvider`, `hcaptchaProvider`) are built with it;
|
|
5
|
+
* use it directly for any other verification service. The submit path verifies a token carried on
|
|
6
|
+
* the submission.
|
|
6
7
|
*/
|
|
7
8
|
const defineCaptchaProvider = (provider) => provider;
|
|
8
9
|
//#endregion
|
package/dist/spam/captcha.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"captcha.js","names":[],"sources":["../../src/spam/captcha.ts"],"sourcesContent":["import type { CaptchaProvider } from './types'\n\n/**\n * Identity helper for authoring a captcha provider (mirrors `defineAction`/`
|
|
1
|
+
{"version":3,"file":"captcha.js","names":[],"sources":["../../src/spam/captcha.ts"],"sourcesContent":["import type { CaptchaProvider } from './types'\n\n/**\n * Identity helper for authoring a captcha provider (mirrors `defineAction`/`definePollOptionSource`).\n * Bundled adapters (`turnstileProvider`, `recaptchaProvider`, `hcaptchaProvider`) are built with it;\n * use it directly for any other verification service. The submit path verifies a token carried on\n * the submission.\n */\nexport const defineCaptchaProvider = (provider: CaptchaProvider): CaptchaProvider => provider\n"],"mappings":";;;;;;;AAQA,MAAa,yBAAyB,aAA+C"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
//#region src/spam/clientIp.ts
|
|
2
|
+
/** First hop of a comma-separated proxy header (the client, per X-Forwarded-For convention), or undefined. */
|
|
3
|
+
const firstHop = (headers, header) => {
|
|
4
|
+
return headers?.get(header)?.split(",")[0]?.trim() || void 0;
|
|
5
|
+
};
|
|
6
|
+
//#endregion
|
|
7
|
+
export { firstHop };
|
|
8
|
+
|
|
9
|
+
//# sourceMappingURL=clientIp.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clientIp.js","names":[],"sources":["../../src/spam/clientIp.ts"],"sourcesContent":["/** First hop of a comma-separated proxy header (the client, per X-Forwarded-For convention), or undefined. */\nexport const firstHop = (headers: Headers | undefined, header: string): string | undefined => {\n\tconst first = headers?.get(header)?.split(',')[0]?.trim()\n\treturn first || undefined\n}\n"],"mappings":";;AACA,MAAa,YAAY,SAA8B,WAAuC;CAE7F,OADc,SAAS,IAAI,MAAM,GAAG,MAAM,GAAG,EAAE,IAAI,KAAK,KACxC,KAAA;AACjB"}
|