@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
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CalcExpressionBuilder.js","names":["useTranslation"],"sources":["../../src/client/CalcExpressionBuilder.tsx"],"sourcesContent":["'use client'\n\nimport {\n\tButton,\n\tFieldError,\n\tFieldLabel,\n\tReactSelect,\n\ttype ReactSelectOption,\n\tRenderCustomComponent,\n\tuseField,\n\tuseFormFields,\n} from '@payloadcms/ui'\nimport { reduceFieldsToValues } from 'payload/shared'\nimport { useMemo, useState } from 'react'\nimport { formatCalc } from '../calc/formatCalc'\nimport { normalizeCalc } from '../calc/normalizeCalc'\nimport {\n\tCALC_FNS,\n\tCALC_OPS,\n\ttype CalcExpression,\n\ttype CalcFn,\n\ttype CalcFnName,\n\ttype CalcOp,\n\tisCalcFn,\n} from '../calc/types'\nimport type { CalcSourceClientMeta } from '../fields/builtin/calculation'\nimport { keys, type TranslationKey } from '../translations/keys'\nimport { useTranslation } from '../translations/useTranslation'\nimport type { FieldRow } from './synthesizeClientField'\nimport { toStaticLabel } from './toStaticLabel'\nimport './admin.css'\n\nexport type CalcExpressionBuilderProps = {\n\tpath?: string\n\tfield?: { label?: unknown }\n\treadOnly?: boolean\n\t/** Registered calc-source metadata (key, label, modes), threaded as clientProps by `buildCalculationField`. */\n\tsources?: CalcSourceClientMeta[]\n\t/** Registered custom calc function names, so client-side normalization accepts what the server accepts. */\n\tfunctions?: string[]\n}\n\n/**\n * The editing view model: authors read and build expressions left-to-right, so the UI edits a\n * chain (first operand, then op+operand steps, then an optional wrapping unary function) and the\n * stored `CalcExpression` AST is derived by left-folding. The AST contract is untouched.\n */\nexport type CalcChain = { first: CalcOperand; steps: CalcChainStep[]; finish?: CalcFn }\nexport type CalcChainStep = { op: CalcOp; operand: CalcOperand }\nexport type CalcOperand =\n\t| { kind: 'ref'; field: string }\n\t| { kind: 'lit'; value: number }\n\t| { kind: 'weight'; field: string; weights?: Record<string, number>; source?: string }\n\t| { kind: 'source'; source: string }\n\t| { kind: 'group'; chain: CalcChain }\n\t| { kind: 'fn'; fn: CalcFnName; args: CalcChain[] }\n\t| { kind: 'neg'; operand: CalcOperand }\n\n/** Kinds a leaf operand card can switch between in place; containers come from Start with, loading, or JSON. */\ntype LeafKind = 'lit' | 'ref' | 'weight'\ntype StartKind = 'fn' | LeafKind\n\n/** The single-argument functions offered by the \"Then apply\" finisher; min/max are variadic and stay Function operands. */\nconst UNARY_FNS = CALC_FNS.filter((fn) => fn !== 'min' && fn !== 'max')\n\nconst seedOperand = (kind: LeafKind): CalcOperand => {\n\tswitch (kind) {\n\t\tcase 'ref':\n\t\t\treturn { kind: 'ref', field: '' }\n\t\tcase 'lit':\n\t\t\treturn { kind: 'lit', value: 0 }\n\t\tcase 'weight':\n\t\t\treturn { kind: 'weight', field: '', weights: {} }\n\t}\n}\n\nconst seedAst = (kind: StartKind): CalcExpression => {\n\tswitch (kind) {\n\t\tcase 'ref':\n\t\t\treturn { type: 'ref', field: '' }\n\t\tcase 'lit':\n\t\t\treturn { type: 'lit', value: 0 }\n\t\tcase 'weight':\n\t\t\treturn { type: 'weight', field: '', weights: {} }\n\t\tcase 'fn':\n\t\t\treturn { type: 'fn', fn: 'min', args: [{ type: 'lit', value: 0 }] }\n\t}\n}\n\nconst astToOperand = (node: CalcExpression): CalcOperand => {\n\tswitch (node.type) {\n\t\tcase 'ref':\n\t\t\treturn { kind: 'ref', field: node.field }\n\t\tcase 'lit':\n\t\t\treturn { kind: 'lit', value: node.value }\n\t\tcase 'source':\n\t\t\treturn { kind: 'source', source: node.source }\n\t\tcase 'weight':\n\t\t\treturn {\n\t\t\t\tkind: 'weight',\n\t\t\t\tfield: node.field,\n\t\t\t\t...(node.weights !== undefined ? { weights: node.weights } : {}),\n\t\t\t\t...(node.source !== undefined ? { source: node.source } : {}),\n\t\t\t}\n\t\tcase 'neg':\n\t\t\treturn { kind: 'neg', operand: astToOperand(node.operand) }\n\t\tcase 'fn':\n\t\t\treturn { kind: 'fn', fn: node.fn, args: node.args.map((arg) => toChain(arg, false)) }\n\t\tcase 'op':\n\t\t\treturn { kind: 'group', chain: toChain(node, false) }\n\t}\n}\n\nconst toChain = (expr: CalcExpression, allowFinish: boolean): CalcChain => {\n\tconst arg = expr.type === 'fn' ? expr.args[0] : undefined\n\tif (\n\t\tallowFinish &&\n\t\texpr.type === 'fn' &&\n\t\texpr.args.length === 1 &&\n\t\targ !== undefined &&\n\t\tisCalcFn(expr.fn) &&\n\t\t(UNARY_FNS as readonly CalcFn[]).includes(expr.fn)\n\t) {\n\t\treturn { ...toChain(arg, false), finish: expr.fn }\n\t}\n\tconst steps: CalcChainStep[] = []\n\tlet node = expr\n\twhile (node.type === 'op') {\n\t\tsteps.unshift({ op: node.op, operand: astToOperand(node.right) })\n\t\tnode = node.left\n\t}\n\treturn { first: astToOperand(node), steps }\n}\n\n/**\n * AST -> chain: the left spine of binary ops flattens into first + steps (a nested op on the right\n * becomes a `group`); a root unary fn wrapping the whole expression loads as `finish` (min/max stay\n * fn operands so the finisher select never holds a value it cannot offer). Total: every valid\n * `CalcExpression` loads without loss, and `chainToAst(astToChain(x))` is structurally `x`.\n */\nexport const astToChain = (expr: CalcExpression): CalcChain => toChain(expr, true)\n\nconst operandToAst = (operand: CalcOperand): CalcExpression => {\n\tswitch (operand.kind) {\n\t\tcase 'ref':\n\t\t\treturn { type: 'ref', field: operand.field }\n\t\tcase 'lit':\n\t\t\treturn { type: 'lit', value: operand.value }\n\t\tcase 'weight':\n\t\t\treturn {\n\t\t\t\ttype: 'weight',\n\t\t\t\tfield: operand.field,\n\t\t\t\t...(operand.weights !== undefined ? { weights: operand.weights } : {}),\n\t\t\t\t...(operand.source !== undefined ? { source: operand.source } : {}),\n\t\t\t}\n\t\tcase 'source':\n\t\t\treturn { type: 'source', source: operand.source }\n\t\tcase 'neg':\n\t\t\treturn { type: 'neg', operand: operandToAst(operand.operand) }\n\t\tcase 'fn':\n\t\t\treturn { type: 'fn', fn: operand.fn, args: operand.args.map(chainBodyToAst) }\n\t\tcase 'group':\n\t\t\treturn chainBodyToAst(operand.chain)\n\t}\n}\n\n/** Folds first + steps only. `finish` is root-only by design: nested chains (groups, fn args) never carry one, so it is deliberately ignored here. */\nconst chainBodyToAst = (chain: CalcChain): CalcExpression =>\n\tchain.steps.reduce<CalcExpression>(\n\t\t(left, step) => ({ type: 'op', op: step.op, left, right: operandToAst(step.operand) }),\n\t\toperandToAst(chain.first)\n\t)\n\n/** Chain -> AST: left-fold first + steps into the binary tree (left-assoc matches `-`/`/`/`%`), then wrap in `finish` when set. */\nexport const chainToAst = (chain: CalcChain): CalcExpression => {\n\tconst body = chainBodyToAst(chain)\n\treturn chain.finish ? { type: 'fn', fn: chain.finish, args: [body] } : body\n}\n\ntype ChoiceOption = { label: string; value: string }\ntype ChoiceSibling = { name: string; label: string; options: ChoiceOption[] }\ntype Siblings = {\n\tnumeric: ChoiceOption[]\n\tchoices: ChoiceSibling[]\n\tlabels: Record<string, string>\n}\n\nconst optionRows = (options: unknown): ChoiceOption[] => {\n\tif (!Array.isArray(options)) {\n\t\treturn []\n\t}\n\treturn options.flatMap((option) => {\n\t\tif (typeof option === 'string') {\n\t\t\treturn option.length > 0 ? [{ label: option, value: option }] : []\n\t\t}\n\t\tif (!option || typeof option !== 'object') {\n\t\t\treturn []\n\t\t}\n\t\tconst { label, value } = option as { label?: unknown; value?: unknown }\n\t\tif (typeof value !== 'string' || value.length === 0) {\n\t\t\treturn []\n\t\t}\n\t\treturn [{ label: typeof label === 'string' && label.length > 0 ? label : value, value }]\n\t})\n}\n\nconst siblingsFromData = (data: Record<string, unknown>, selfIndex: number): Siblings => {\n\tconst rows = Array.isArray(data.fields) ? (data.fields as unknown[]) : []\n\tconst siblings: Siblings = { numeric: [], choices: [], labels: {} }\n\trows.forEach((row, index) => {\n\t\tif (!row || typeof row !== 'object') {\n\t\t\treturn\n\t\t}\n\t\tconst { blockType, name, label, options } = row as FieldRow\n\t\tconst trimmed = typeof name === 'string' ? name.trim() : ''\n\t\tif (trimmed.length === 0) {\n\t\t\treturn\n\t\t}\n\t\tconst display = typeof label === 'string' && label.length > 0 ? label : trimmed\n\t\tsiblings.labels[trimmed] = display\n\t\t// Calculations fold in declaration order, so a calculation is only referenceable when it is\n\t\t// declared before this one; a forward (or self) reference would always evaluate to 0.\n\t\tconst referenceable =\n\t\t\tblockType === 'number' || (blockType === 'calculation' && index < selfIndex)\n\t\tif (referenceable) {\n\t\t\tsiblings.numeric.push({ label: display, value: trimmed })\n\t\t}\n\t\tif (blockType === 'select') {\n\t\t\tsiblings.choices.push({ name: trimmed, label: display, options: optionRows(options) })\n\t\t}\n\t})\n\treturn siblings\n}\n\nconst singleOption = (\n\tselected: ReactSelectOption | ReactSelectOption[] | null\n): ReactSelectOption | undefined => {\n\tconst chosen = Array.isArray(selected) ? selected[0] : selected\n\treturn chosen ?? undefined\n}\n\n/** Keeps a stored reference selectable even when it no longer matches any option, like FieldNameSelect. */\nconst withStored = (options: ChoiceOption[], stored: string): ChoiceOption[] =>\n\tstored.length > 0 && !options.some((option) => option.value === stored)\n\t\t? [...options, { label: stored, value: stored }]\n\t\t: options\n\ntype NumberInputProps = {\n\tvalue: number | undefined\n\tonCommit: (value: number) => void\n\tclassName: string\n\tid?: string\n\tdisabled?: boolean\n\t'aria-label'?: string\n}\n\n/**\n * Number input with a local draft: keystrokes commit only when the text parses to a finite number,\n * an invalid draft reverts to the committed value on blur, and an external value change resyncs\n * the draft.\n */\nconst NumberInput = ({\n\tvalue,\n\tonCommit,\n\tclassName,\n\tid,\n\tdisabled,\n\t'aria-label': ariaLabel,\n}: NumberInputProps) => {\n\tconst [draft, setDraft] = useState(value === undefined ? '' : String(value))\n\tconst [lastValue, setLastValue] = useState(value)\n\tif (value !== lastValue) {\n\t\tsetLastValue(value)\n\t\tif (draft.trim() === '' || Number(draft) !== value) {\n\t\t\tsetDraft(value === undefined ? '' : String(value))\n\t\t}\n\t}\n\treturn (\n\t\t<input\n\t\t\ttype=\"number\"\n\t\t\tclassName={className}\n\t\t\tid={id}\n\t\t\tdisabled={disabled}\n\t\t\taria-label={ariaLabel}\n\t\t\tvalue={draft}\n\t\t\tonChange={(event) => {\n\t\t\t\tconst text = event.target.value\n\t\t\t\tsetDraft(text)\n\t\t\t\tconst parsed = Number(text)\n\t\t\t\tif (text.trim() !== '' && Number.isFinite(parsed)) {\n\t\t\t\t\tonCommit(parsed)\n\t\t\t\t}\n\t\t\t}}\n\t\t\tonBlur={() => {\n\t\t\t\tconst parsed = Number(draft)\n\t\t\t\tif (draft.trim() === '' || !Number.isFinite(parsed)) {\n\t\t\t\t\tsetDraft(value === undefined ? '' : String(value))\n\t\t\t\t}\n\t\t\t}}\n\t\t/>\n\t)\n}\n\ntype BuilderCtx = {\n\tt: (key: TranslationKey) => string\n\tsiblings: Siblings\n\treadOnly: boolean\n\t/** Resolves a calc source key to its admin-locale display label (raw key when unregistered). */\n\tsourceLabelOf: (key: string) => string\n\t/** Scalar-capable sources as select options (`source:`-prefixed values). */\n\tscalarSourceOptions: ChoiceOption[]\n\t/** Weights-capable sources as select options (`source:`-prefixed values). */\n\tweightSourceOptions: ChoiceOption[]\n\t/** Registered custom calc function names, offered by the fn select after the built-ins. */\n\tcustomFnOptions: ChoiceOption[]\n}\n\nconst OP_OPTIONS: ChoiceOption[] = CALC_OPS.map((op) => ({ label: op, value: op }))\nconst FN_OPTIONS: ChoiceOption[] = CALC_FNS.map((fn) => ({ label: fn, value: fn }))\nconst UNARY_OPTIONS: ChoiceOption[] = UNARY_FNS.map((fn) => ({ label: fn, value: fn }))\n\n/** Source entries share kind/start selects with the fixed kinds, namespaced to avoid key collisions. */\nconst SOURCE_PREFIX = 'source:'\nconst sourceOptionValue = (key: string): string => `${SOURCE_PREFIX}${key}`\nconst sourceKeyOf = (value: string): string | undefined =>\n\tvalue.startsWith(SOURCE_PREFIX) ? value.slice(SOURCE_PREFIX.length) : undefined\n\n/** A source label is a plain string or a per-locale record; resolve it for the admin UI language. */\nconst resolveSourceLabel = (label: string | Record<string, string>, language: string): string =>\n\ttypeof label === 'string' ? label : (label[language] ?? label.en ?? Object.values(label)[0] ?? '')\n\ntype SelectOptionOrGroup = ChoiceOption | { label: string; options: ChoiceOption[] }\n\n/** Fixed kinds stay flat; sources join as a labeled group when any exist (react-select mixes both). */\nconst withSourceGroup = (\n\tbase: ChoiceOption[],\n\tsourceOptions: ChoiceOption[],\n\tgroupLabel: string\n): SelectOptionOrGroup[] =>\n\tsourceOptions.length > 0 ? [...base, { label: groupLabel, options: sourceOptions }] : base\n\ntype OperandCardProps = {\n\toperand: CalcOperand\n\tonChange: (next: CalcOperand) => void\n\tctx: BuilderCtx\n\tidPrefix: string\n}\n\nconst OperandCard = ({ operand, onChange, ctx, idPrefix }: OperandCardProps) => {\n\tconst { t, siblings, readOnly } = ctx\n\n\tif (operand.kind === 'group') {\n\t\treturn (\n\t\t\t<div className=\"fb-calc-operand fb-calc-operand--group\">\n\t\t\t\t<div className=\"fb-calc-operand__title\">{t(keys.calcBuilderGroup)}</div>\n\t\t\t\t<ChainEditor\n\t\t\t\t\tchain={operand.chain}\n\t\t\t\t\tonChange={(chain) => onChange({ ...operand, chain })}\n\t\t\t\t\tctx={ctx}\n\t\t\t\t\tidPrefix={`${idPrefix}-g`}\n\t\t\t\t/>\n\t\t\t</div>\n\t\t)\n\t}\n\n\tif (operand.kind === 'fn') {\n\t\tconst fnOptions = withStored([...FN_OPTIONS, ...ctx.customFnOptions], operand.fn)\n\t\treturn (\n\t\t\t<div className=\"fb-calc-operand fb-calc-operand--fn\">\n\t\t\t\t<div className=\"fb-calc-operand__header\">\n\t\t\t\t\t<label className=\"fb-visually-hidden\" htmlFor={`${idPrefix}-fn`}>\n\t\t\t\t\t\t{t(keys.calcBuilderFunction)}\n\t\t\t\t\t</label>\n\t\t\t\t\t<ReactSelect\n\t\t\t\t\t\tclassName=\"fb-calc-operand__fn\"\n\t\t\t\t\t\tinputId={`${idPrefix}-fn`}\n\t\t\t\t\t\toptions={fnOptions}\n\t\t\t\t\t\tvalue={fnOptions.find((option) => option.value === operand.fn)}\n\t\t\t\t\t\tisClearable={false}\n\t\t\t\t\t\tdisabled={readOnly}\n\t\t\t\t\t\tonChange={(selected) => {\n\t\t\t\t\t\t\tconst chosen = singleOption(selected)\n\t\t\t\t\t\t\tif (chosen) {\n\t\t\t\t\t\t\t\tonChange({ ...operand, fn: String(chosen.value) })\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}}\n\t\t\t\t\t/>\n\t\t\t\t</div>\n\t\t\t\t<div className=\"fb-calc-fn__args\">\n\t\t\t\t\t{operand.args.map((arg, index) => (\n\t\t\t\t\t\t// biome-ignore lint/suspicious/noArrayIndexKey: args are positional and never reordered\n\t\t\t\t\t\t<div key={index} className=\"fb-calc-fn__arg\">\n\t\t\t\t\t\t\t<div className=\"fb-calc-fn__arg-chain\">\n\t\t\t\t\t\t\t\t<ChainEditor\n\t\t\t\t\t\t\t\t\tchain={arg}\n\t\t\t\t\t\t\t\t\tonChange={(next) =>\n\t\t\t\t\t\t\t\t\t\tonChange({\n\t\t\t\t\t\t\t\t\t\t\t...operand,\n\t\t\t\t\t\t\t\t\t\t\targs: operand.args.map((a, i) => (i === index ? next : a)),\n\t\t\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tctx={ctx}\n\t\t\t\t\t\t\t\t\tidPrefix={`${idPrefix}-a${index}`}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t{operand.args.length > 1 ? (\n\t\t\t\t\t\t\t\t<div className=\"fb-calc-fn__arg-remove\">\n\t\t\t\t\t\t\t\t\t<Button\n\t\t\t\t\t\t\t\t\t\tbuttonStyle=\"icon-label\"\n\t\t\t\t\t\t\t\t\t\ticon=\"x\"\n\t\t\t\t\t\t\t\t\t\taria-label={t(keys.calcBuilderRemove)}\n\t\t\t\t\t\t\t\t\t\tmargin={false}\n\t\t\t\t\t\t\t\t\t\tdisabled={readOnly}\n\t\t\t\t\t\t\t\t\t\tonClick={() =>\n\t\t\t\t\t\t\t\t\t\t\tonChange({\n\t\t\t\t\t\t\t\t\t\t\t\t...operand,\n\t\t\t\t\t\t\t\t\t\t\t\targs: operand.args.filter((_, i) => i !== index),\n\t\t\t\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t))}\n\t\t\t\t\t<div className=\"fb-calc-fn__add\">\n\t\t\t\t\t\t<Button\n\t\t\t\t\t\t\tbuttonStyle=\"icon-label\"\n\t\t\t\t\t\t\ticon=\"plus\"\n\t\t\t\t\t\t\ticonStyle=\"with-border\"\n\t\t\t\t\t\t\ticonPosition=\"left\"\n\t\t\t\t\t\t\tmargin={false}\n\t\t\t\t\t\t\tdisabled={readOnly}\n\t\t\t\t\t\t\tonClick={() =>\n\t\t\t\t\t\t\t\tonChange({\n\t\t\t\t\t\t\t\t\t...operand,\n\t\t\t\t\t\t\t\t\targs: [...operand.args, { first: { kind: 'lit', value: 0 }, steps: [] }],\n\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{t(keys.calcBuilderAddArgument)}\n\t\t\t\t\t\t</Button>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t)\n\t}\n\n\tif (operand.kind === 'neg') {\n\t\treturn (\n\t\t\t<div className=\"fb-calc-operand fb-calc-operand--neg\">\n\t\t\t\t<div className=\"fb-calc-operand__title\">{t(keys.calcBuilderNegate)}</div>\n\t\t\t\t<OperandCard\n\t\t\t\t\toperand={operand.operand}\n\t\t\t\t\tonChange={(next) => onChange({ kind: 'neg', operand: next })}\n\t\t\t\t\tctx={ctx}\n\t\t\t\t\tidPrefix={`${idPrefix}-n`}\n\t\t\t\t/>\n\t\t\t</div>\n\t\t)\n\t}\n\n\tconst leafKindOptions: ChoiceOption[] = [\n\t\t{ label: t(keys.calcBuilderAnswer), value: 'ref' },\n\t\t{ label: t(keys.calcBuilderNumber), value: 'lit' },\n\t\t{ label: t(keys.calcBuilderWeights), value: 'weight' },\n\t]\n\tconst kindValue = operand.kind === 'source' ? sourceOptionValue(operand.source) : operand.kind\n\tconst kindSourceOptions =\n\t\toperand.kind === 'source' &&\n\t\t!ctx.scalarSourceOptions.some((option) => option.value === sourceOptionValue(operand.source))\n\t\t\t? [...ctx.scalarSourceOptions, { label: operand.source, value: kindValue }]\n\t\t\t: ctx.scalarSourceOptions\n\tconst kindFlat = [...leafKindOptions, ...kindSourceOptions]\n\tconst refOptions = operand.kind === 'ref' ? withStored(siblings.numeric, operand.field) : []\n\tconst choiceOptions =\n\t\toperand.kind === 'weight'\n\t\t\t? withStored(\n\t\t\t\t\tsiblings.choices.map((c) => ({ label: c.label, value: c.name })),\n\t\t\t\t\toperand.field\n\t\t\t\t)\n\t\t\t: []\n\tconst choice =\n\t\toperand.kind === 'weight' ? siblings.choices.find((c) => c.name === operand.field) : undefined\n\tconst weightSource = operand.kind === 'weight' ? operand.source : undefined\n\tconst weightValuesOptions: ChoiceOption[] = [\n\t\t{ label: t(keys.calcBuilderWeightManual), value: 'manual' },\n\t\t...(weightSource !== undefined &&\n\t\t!ctx.weightSourceOptions.some((option) => option.value === sourceOptionValue(weightSource))\n\t\t\t? [\n\t\t\t\t\t...ctx.weightSourceOptions,\n\t\t\t\t\t{ label: weightSource, value: sourceOptionValue(weightSource) },\n\t\t\t\t]\n\t\t\t: ctx.weightSourceOptions),\n\t]\n\n\treturn (\n\t\t<div className=\"fb-calc-operand\">\n\t\t\t<div className=\"fb-calc-operand__header\">\n\t\t\t\t<label className=\"fb-visually-hidden\" htmlFor={`${idPrefix}-kind`}>\n\t\t\t\t\t{t(keys.calcBuilderKind)}\n\t\t\t\t</label>\n\t\t\t\t<ReactSelect\n\t\t\t\t\tclassName=\"fb-calc-operand__kind\"\n\t\t\t\t\tinputId={`${idPrefix}-kind`}\n\t\t\t\t\toptions={\n\t\t\t\t\t\twithSourceGroup(\n\t\t\t\t\t\t\tleafKindOptions,\n\t\t\t\t\t\t\tkindSourceOptions,\n\t\t\t\t\t\t\tt(keys.calcBuilderSourcesGroup)\n\t\t\t\t\t\t) as ReactSelectOption[]\n\t\t\t\t\t}\n\t\t\t\t\tvalue={kindFlat.find((option) => option.value === kindValue)}\n\t\t\t\t\tisClearable={false}\n\t\t\t\t\tdisabled={readOnly}\n\t\t\t\t\tonChange={(selected) => {\n\t\t\t\t\t\tconst chosen = singleOption(selected)\n\t\t\t\t\t\tif (!chosen || chosen.value === kindValue) {\n\t\t\t\t\t\t\treturn\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconst sourceKey = sourceKeyOf(String(chosen.value))\n\t\t\t\t\t\tonChange(\n\t\t\t\t\t\t\tsourceKey !== undefined\n\t\t\t\t\t\t\t\t? { kind: 'source', source: sourceKey }\n\t\t\t\t\t\t\t\t: seedOperand(chosen.value as LeafKind)\n\t\t\t\t\t\t)\n\t\t\t\t\t}}\n\t\t\t\t/>\n\t\t\t\t{operand.kind === 'source' ? (\n\t\t\t\t\t<span className=\"fb-calc-operand__source\">{ctx.sourceLabelOf(operand.source)}</span>\n\t\t\t\t) : null}\n\t\t\t\t{operand.kind === 'ref' ? (\n\t\t\t\t\trefOptions.length === 0 ? (\n\t\t\t\t\t\t<p className=\"fb-calc-hint\">{t(keys.calcBuilderNoNumericFields)}</p>\n\t\t\t\t\t) : (\n\t\t\t\t\t\t<>\n\t\t\t\t\t\t\t<label className=\"fb-visually-hidden\" htmlFor={`${idPrefix}-ref`}>\n\t\t\t\t\t\t\t\t{t(keys.calcBuilderPickField)}\n\t\t\t\t\t\t\t</label>\n\t\t\t\t\t\t\t<ReactSelect\n\t\t\t\t\t\t\t\tclassName=\"fb-calc-operand__ref\"\n\t\t\t\t\t\t\t\tinputId={`${idPrefix}-ref`}\n\t\t\t\t\t\t\t\toptions={refOptions}\n\t\t\t\t\t\t\t\tvalue={refOptions.find((option) => option.value === operand.field)}\n\t\t\t\t\t\t\t\tisClearable={!readOnly}\n\t\t\t\t\t\t\t\tdisabled={readOnly}\n\t\t\t\t\t\t\t\tplaceholder={t(keys.calcBuilderPickField)}\n\t\t\t\t\t\t\t\tonChange={(selected) => {\n\t\t\t\t\t\t\t\t\tconst chosen = singleOption(selected)\n\t\t\t\t\t\t\t\t\tonChange({ kind: 'ref', field: chosen ? String(chosen.value) : '' })\n\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t</>\n\t\t\t\t\t)\n\t\t\t\t) : null}\n\t\t\t\t{operand.kind === 'lit' ? (\n\t\t\t\t\t<NumberInput\n\t\t\t\t\t\tclassName=\"fb-calc-operand__number\"\n\t\t\t\t\t\tid={`${idPrefix}-number`}\n\t\t\t\t\t\taria-label={t(keys.calcBuilderNumber)}\n\t\t\t\t\t\tdisabled={readOnly}\n\t\t\t\t\t\tvalue={operand.value}\n\t\t\t\t\t\tonCommit={(value) => onChange({ kind: 'lit', value })}\n\t\t\t\t\t/>\n\t\t\t\t) : null}\n\t\t\t\t{operand.kind === 'weight' ? (\n\t\t\t\t\tchoiceOptions.length === 0 ? (\n\t\t\t\t\t\t<p className=\"fb-calc-hint\">{t(keys.calcBuilderNoChoiceFields)}</p>\n\t\t\t\t\t) : (\n\t\t\t\t\t\t<>\n\t\t\t\t\t\t\t<label className=\"fb-visually-hidden\" htmlFor={`${idPrefix}-weight-field`}>\n\t\t\t\t\t\t\t\t{t(keys.calcBuilderPickField)}\n\t\t\t\t\t\t\t</label>\n\t\t\t\t\t\t\t<ReactSelect\n\t\t\t\t\t\t\t\tclassName=\"fb-calc-operand__weight-field\"\n\t\t\t\t\t\t\t\tinputId={`${idPrefix}-weight-field`}\n\t\t\t\t\t\t\t\toptions={choiceOptions}\n\t\t\t\t\t\t\t\tvalue={choiceOptions.find((option) => option.value === operand.field)}\n\t\t\t\t\t\t\t\tisClearable={!readOnly}\n\t\t\t\t\t\t\t\tdisabled={readOnly}\n\t\t\t\t\t\t\t\tplaceholder={t(keys.calcBuilderPickField)}\n\t\t\t\t\t\t\t\tonChange={(selected) => {\n\t\t\t\t\t\t\t\t\tconst chosen = singleOption(selected)\n\t\t\t\t\t\t\t\t\tconst field = chosen ? String(chosen.value) : ''\n\t\t\t\t\t\t\t\t\tif (field !== operand.field) {\n\t\t\t\t\t\t\t\t\t\t// Inline weights are per-option and reset with the field; a source keeps\n\t\t\t\t\t\t\t\t\t\t// resolving (its resolver receives the newly chosen field).\n\t\t\t\t\t\t\t\t\t\tonChange(\n\t\t\t\t\t\t\t\t\t\t\toperand.source !== undefined\n\t\t\t\t\t\t\t\t\t\t\t\t? { kind: 'weight', field, source: operand.source }\n\t\t\t\t\t\t\t\t\t\t\t\t: { kind: 'weight', field, weights: {} }\n\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t</>\n\t\t\t\t\t)\n\t\t\t\t) : null}\n\t\t\t</div>\n\t\t\t{operand.kind === 'weight' && ctx.weightSourceOptions.length > 0 ? (\n\t\t\t\t<div className=\"fb-calc-operand__weight-values-row\">\n\t\t\t\t\t<label className=\"fb-calc-operand__weight-values-label\" htmlFor={`${idPrefix}-wv`}>\n\t\t\t\t\t\t{t(keys.calcBuilderWeightValues)}\n\t\t\t\t\t</label>\n\t\t\t\t\t<ReactSelect\n\t\t\t\t\t\tclassName=\"fb-calc-operand__weight-values\"\n\t\t\t\t\t\tinputId={`${idPrefix}-wv`}\n\t\t\t\t\t\toptions={weightValuesOptions}\n\t\t\t\t\t\tvalue={weightValuesOptions.find(\n\t\t\t\t\t\t\t(option) =>\n\t\t\t\t\t\t\t\toption.value ===\n\t\t\t\t\t\t\t\t(operand.source !== undefined ? sourceOptionValue(operand.source) : 'manual')\n\t\t\t\t\t\t)}\n\t\t\t\t\t\tisClearable={false}\n\t\t\t\t\t\tdisabled={readOnly}\n\t\t\t\t\t\tonChange={(selected) => {\n\t\t\t\t\t\t\tconst chosen = singleOption(selected)\n\t\t\t\t\t\t\tif (!chosen) {\n\t\t\t\t\t\t\t\treturn\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tconst sourceKey = sourceKeyOf(String(chosen.value))\n\t\t\t\t\t\t\tif (sourceKey === undefined) {\n\t\t\t\t\t\t\t\tif (operand.source !== undefined) {\n\t\t\t\t\t\t\t\t\t// Back to Manual: drop the source, keep any inline weights (they were\n\t\t\t\t\t\t\t\t\t// preserved untouched while sourced) so the author's numbers return.\n\t\t\t\t\t\t\t\t\tonChange({\n\t\t\t\t\t\t\t\t\t\tkind: 'weight',\n\t\t\t\t\t\t\t\t\t\tfield: operand.field,\n\t\t\t\t\t\t\t\t\t\tweights: operand.weights ?? {},\n\t\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\treturn\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (sourceKey !== operand.source) {\n\t\t\t\t\t\t\t\tonChange({ ...operand, source: sourceKey })\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}}\n\t\t\t\t\t/>\n\t\t\t\t</div>\n\t\t\t) : null}\n\t\t\t{operand.kind === 'weight' && operand.source !== undefined ? (\n\t\t\t\t<p className=\"fb-calc-hint\">{t(keys.calcBuilderWeightsFromSource)}</p>\n\t\t\t) : null}\n\t\t\t{operand.kind === 'weight' && operand.source === undefined && choice ? (\n\t\t\t\t<div className=\"fb-calc-operand__weights\">\n\t\t\t\t\t{choice.options.map((option) => (\n\t\t\t\t\t\t<div key={option.value} className=\"fb-calc-operand__weight-row\">\n\t\t\t\t\t\t\t<label\n\t\t\t\t\t\t\t\tclassName=\"fb-calc-operand__weight-label\"\n\t\t\t\t\t\t\t\thtmlFor={`${idPrefix}-weight-${option.value}`}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{option.label}\n\t\t\t\t\t\t\t</label>\n\t\t\t\t\t\t\t<NumberInput\n\t\t\t\t\t\t\t\tclassName=\"fb-calc-operand__weight\"\n\t\t\t\t\t\t\t\tid={`${idPrefix}-weight-${option.value}`}\n\t\t\t\t\t\t\t\tdisabled={readOnly}\n\t\t\t\t\t\t\t\tvalue={operand.weights?.[option.value]}\n\t\t\t\t\t\t\t\tonCommit={(value) =>\n\t\t\t\t\t\t\t\t\tonChange({\n\t\t\t\t\t\t\t\t\t\t...operand,\n\t\t\t\t\t\t\t\t\t\tweights: { ...(operand.weights ?? {}), [option.value]: value },\n\t\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t))}\n\t\t\t\t</div>\n\t\t\t) : null}\n\t\t</div>\n\t)\n}\n\ntype ChainEditorProps = {\n\tchain: CalcChain\n\tonChange: (next: CalcChain) => void\n\t/** Root only: called when the only row is removed, clearing the expression back to Start with. */\n\tonEmptied?: () => void\n\t/**\n\t * Honest-affordance rule: an X must actually remove. The root's only-row X clears the whole\n\t * expression, so it stays; a nested chain's only row (fn arg, group) would merely reseed, so\n\t * its X is not rendered at all.\n\t */\n\tisRoot?: boolean\n\tctx: BuilderCtx\n\tidPrefix: string\n}\n\nconst ChainEditor = ({ chain, onChange, onEmptied, isRoot, ctx, idPrefix }: ChainEditorProps) => {\n\tconst { t, readOnly } = ctx\n\n\tconst removeRow = (row: number) => {\n\t\tif (row === 0) {\n\t\t\tconst [promoted, ...rest] = chain.steps\n\t\t\tif (!promoted) {\n\t\t\t\tonEmptied?.()\n\t\t\t\treturn\n\t\t\t}\n\t\t\tonChange({ ...chain, first: promoted.operand, steps: rest })\n\t\t\treturn\n\t\t}\n\t\tonChange({ ...chain, steps: chain.steps.filter((_, i) => i !== row - 1) })\n\t}\n\n\tconst rows: { op?: CalcOp; operand: CalcOperand }[] = [\n\t\t{ operand: chain.first },\n\t\t...chain.steps.map((step) => ({ op: step.op, operand: step.operand })),\n\t]\n\n\treturn (\n\t\t<div className=\"fb-calc-chain\">\n\t\t\t{rows.map((row, index) => (\n\t\t\t\t// biome-ignore lint/suspicious/noArrayIndexKey: rows are positional and never reordered\n\t\t\t\t<div key={index} className={index > 0 ? 'fb-calc-row fb-calc-row--divided' : 'fb-calc-row'}>\n\t\t\t\t\t{index === 0 ? <div className=\"fb-calc-row__op-spacer\" aria-hidden=\"true\" /> : null}\n\t\t\t\t\t{index > 0 ? (\n\t\t\t\t\t\t<>\n\t\t\t\t\t\t\t<label className=\"fb-visually-hidden\" htmlFor={`${idPrefix}-r${index}-op`}>\n\t\t\t\t\t\t\t\t{t(keys.calcBuilderMath)}\n\t\t\t\t\t\t\t</label>\n\t\t\t\t\t\t\t<ReactSelect\n\t\t\t\t\t\t\t\tclassName=\"fb-calc-row__op\"\n\t\t\t\t\t\t\t\tinputId={`${idPrefix}-r${index}-op`}\n\t\t\t\t\t\t\t\toptions={OP_OPTIONS}\n\t\t\t\t\t\t\t\tvalue={OP_OPTIONS.find((option) => option.value === row.op)}\n\t\t\t\t\t\t\t\tisClearable={false}\n\t\t\t\t\t\t\t\tdisabled={readOnly}\n\t\t\t\t\t\t\t\tonChange={(selected) => {\n\t\t\t\t\t\t\t\t\tconst chosen = singleOption(selected)\n\t\t\t\t\t\t\t\t\tif (chosen) {\n\t\t\t\t\t\t\t\t\t\tonChange({\n\t\t\t\t\t\t\t\t\t\t\t...chain,\n\t\t\t\t\t\t\t\t\t\t\tsteps: chain.steps.map((step, i) =>\n\t\t\t\t\t\t\t\t\t\t\t\ti === index - 1 ? { ...step, op: chosen.value as CalcOp } : step\n\t\t\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t</>\n\t\t\t\t\t) : null}\n\t\t\t\t\t<div className=\"fb-calc-row__operand\">\n\t\t\t\t\t\t<OperandCard\n\t\t\t\t\t\t\toperand={row.operand}\n\t\t\t\t\t\t\tonChange={(operand) =>\n\t\t\t\t\t\t\t\tindex === 0\n\t\t\t\t\t\t\t\t\t? onChange({ ...chain, first: operand })\n\t\t\t\t\t\t\t\t\t: onChange({\n\t\t\t\t\t\t\t\t\t\t\t...chain,\n\t\t\t\t\t\t\t\t\t\t\tsteps: chain.steps.map((step, i) =>\n\t\t\t\t\t\t\t\t\t\t\t\ti === index - 1 ? { ...step, operand } : step\n\t\t\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tctx={ctx}\n\t\t\t\t\t\t\tidPrefix={`${idPrefix}-r${index}`}\n\t\t\t\t\t\t/>\n\t\t\t\t\t</div>\n\t\t\t\t\t{rows.length > 1 || isRoot ? (\n\t\t\t\t\t\t<div className=\"fb-calc-row__remove\">\n\t\t\t\t\t\t\t<Button\n\t\t\t\t\t\t\t\tbuttonStyle=\"icon-label\"\n\t\t\t\t\t\t\t\ticon=\"x\"\n\t\t\t\t\t\t\t\taria-label={t(keys.calcBuilderRemove)}\n\t\t\t\t\t\t\t\tmargin={false}\n\t\t\t\t\t\t\t\tdisabled={readOnly}\n\t\t\t\t\t\t\t\tonClick={() => removeRow(index)}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t) : null}\n\t\t\t\t</div>\n\t\t\t))}\n\t\t\t<div className=\"fb-calc-chain__add\">\n\t\t\t\t<Button\n\t\t\t\t\tbuttonStyle=\"icon-label\"\n\t\t\t\t\ticon=\"plus\"\n\t\t\t\t\ticonStyle=\"with-border\"\n\t\t\t\t\ticonPosition=\"left\"\n\t\t\t\t\tmargin={false}\n\t\t\t\t\tdisabled={readOnly}\n\t\t\t\t\tonClick={() =>\n\t\t\t\t\t\tonChange({\n\t\t\t\t\t\t\t...chain,\n\t\t\t\t\t\t\tsteps: [...chain.steps, { op: '*', operand: seedOperand('ref') }],\n\t\t\t\t\t\t})\n\t\t\t\t\t}\n\t\t\t\t>\n\t\t\t\t\t{t(keys.calcBuilderAddStep)}\n\t\t\t\t</Button>\n\t\t\t</div>\n\t\t</div>\n\t)\n}\n\n/**\n * Visual editor for the calculation field's `expression` AST, presented as a left-to-right chain.\n * Storage shape is unchanged and `validateExpression` stays the server gate; the AST remains\n * authorable via the API.\n */\nexport const CalcExpressionBuilder = (props: CalcExpressionBuilderProps) => {\n\tconst {\n\t\tcustomComponents: { Error: ErrorComponent, Label } = {},\n\t\tdisabled,\n\t\tpath,\n\t\tsetValue,\n\t\tshowError,\n\t\tvalue,\n\t} = useField<unknown>({ path: props.path })\n\tconst { t, i18n } = useTranslation()\n\tconst label = toStaticLabel(props.field?.label)\n\tconst readOnly = props.readOnly === true || disabled === true\n\n\tconst sources = useMemo(() => props.sources ?? [], [props.sources])\n\t// Mirrors the server-side allowed sets, so the builder accepts exactly the expressions\n\t// `buildValidateExpression` accepts (a sourced expression must not read as \"stored invalid\").\n\tconst allowed = useMemo(\n\t\t() => ({\n\t\t\tsources: new Set(sources.map((source) => source.key)),\n\t\t\tfunctions: new Set(props.functions ?? []),\n\t\t}),\n\t\t[sources, props.functions]\n\t)\n\tconst sourceLabelOf = (key: string): string => {\n\t\tconst meta = sources.find((source) => source.key === key)\n\t\treturn meta ? resolveSourceLabel(meta.label, i18n.language) : key\n\t}\n\tconst scalarSourceOptions: ChoiceOption[] = sources\n\t\t.filter((source) => source.scalar)\n\t\t.map((source) => ({ label: sourceLabelOf(source.key), value: sourceOptionValue(source.key) }))\n\tconst weightSourceOptions: ChoiceOption[] = sources\n\t\t.filter((source) => source.weights)\n\t\t.map((source) => ({ label: sourceLabelOf(source.key), value: sourceOptionValue(source.key) }))\n\tconst customFnOptions: ChoiceOption[] = (props.functions ?? []).map((fn) => ({\n\t\tlabel: fn,\n\t\tvalue: fn,\n\t}))\n\n\tconst expression = useMemo(() => normalizeCalc(value, allowed), [value, allowed])\n\tconst chain = useMemo(() => (expression ? astToChain(expression) : undefined), [expression])\n\tconst storedInvalid = expression === undefined && value != null && value !== ''\n\n\t// The expression path is `fields.<row>.expression`; that row is the calculation block being\n\t// edited, so it bounds which calculation siblings are referenceable (see siblingsFromData).\n\t// An unparseable path (never expected) offers every calculation rather than none.\n\tconst selfIndex = useMemo(() => {\n\t\tconst match = /^fields\\.(\\d+)\\./.exec(path)\n\t\treturn match ? Number(match[1]) : Number.MAX_SAFE_INTEGER\n\t}, [path])\n\n\tconst siblingsJson = useFormFields(([fields]) =>\n\t\tJSON.stringify(siblingsFromData(reduceFieldsToValues(fields, true), selfIndex))\n\t)\n\tconst siblings = useMemo(() => JSON.parse(siblingsJson) as Siblings, [siblingsJson])\n\n\tconst startOptions: ChoiceOption[] = [\n\t\t{ label: t(keys.calcBuilderAnswer), value: 'ref' },\n\t\t{ label: t(keys.calcBuilderNumber), value: 'lit' },\n\t\t{ label: t(keys.calcBuilderWeights), value: 'weight' },\n\t\t{ label: t(keys.calcBuilderFunction), value: 'fn' },\n\t]\n\tconst startDescriptions: { key: string; label: string; description: string }[] = [\n\t\t{\n\t\t\tkey: 'ref',\n\t\t\tlabel: t(keys.calcBuilderAnswer),\n\t\t\tdescription: t(keys.calcBuilderFieldDescription),\n\t\t},\n\t\t{\n\t\t\tkey: 'lit',\n\t\t\tlabel: t(keys.calcBuilderNumber),\n\t\t\tdescription: t(keys.calcBuilderNumberDescription),\n\t\t},\n\t\t{\n\t\t\tkey: 'weight',\n\t\t\tlabel: t(keys.calcBuilderWeights),\n\t\t\tdescription: t(keys.calcBuilderWeightsDescription),\n\t\t},\n\t\t{\n\t\t\tkey: 'fn',\n\t\t\tlabel: t(keys.calcBuilderFunction),\n\t\t\tdescription: t(keys.calcBuilderFunctionDescription),\n\t\t},\n\t]\n\n\tconst commitChain = (next: CalcChain) => {\n\t\tif (!readOnly) {\n\t\t\tsetValue(chainToAst(next))\n\t\t}\n\t}\n\n\tconst clear = () => {\n\t\tif (!readOnly) {\n\t\t\tsetValue(null)\n\t\t}\n\t}\n\n\t// An unfilled slot (blank ref) previews as \"?\" so a partial chain reads \"Price × ?\" instead of\n\t// trailing off; formatCalc itself stays pure.\n\tconst labelOf = (field: string) => (field.trim() === '' ? '?' : (siblings.labels[field] ?? field))\n\n\tconst idBase = `calc-${path.replace(/\\./g, '__')}`\n\tconst ctx: BuilderCtx = {\n\t\tt,\n\t\tsiblings,\n\t\treadOnly,\n\t\tsourceLabelOf,\n\t\tscalarSourceOptions,\n\t\tweightSourceOptions,\n\t\tcustomFnOptions,\n\t}\n\n\treturn (\n\t\t<div\n\t\t\tclassName={['field-type', 'fb-calc-builder', showError && 'error', readOnly && 'read-only']\n\t\t\t\t.filter(Boolean)\n\t\t\t\t.join(' ')}\n\t\t\tid={path ? `field-${path.replace(/\\./g, '__')}` : undefined}\n\t\t>\n\t\t\t<RenderCustomComponent\n\t\t\t\tCustomComponent={Label}\n\t\t\t\tFallback={<FieldLabel label={label} path={path} />}\n\t\t\t/>\n\t\t\t<div className=\"field-type__wrap\">\n\t\t\t\t<RenderCustomComponent\n\t\t\t\t\tCustomComponent={ErrorComponent}\n\t\t\t\t\tFallback={<FieldError path={path} showError={showError} />}\n\t\t\t\t/>\n\t\t\t\t{chain ? (\n\t\t\t\t\t<>\n\t\t\t\t\t\t<ChainEditor\n\t\t\t\t\t\t\tchain={chain}\n\t\t\t\t\t\t\tonChange={commitChain}\n\t\t\t\t\t\t\tonEmptied={clear}\n\t\t\t\t\t\t\tisRoot\n\t\t\t\t\t\t\tctx={ctx}\n\t\t\t\t\t\t\tidPrefix={idBase}\n\t\t\t\t\t\t/>\n\t\t\t\t\t\t<div className=\"fb-calc-finish\">\n\t\t\t\t\t\t\t<label\n\t\t\t\t\t\t\t\tclassName=\"fb-calc-finish__label\"\n\t\t\t\t\t\t\t\thtmlFor={`${idBase}-finish`}\n\t\t\t\t\t\t\t\ttitle={t(keys.calcBuilderThenApply)}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{t(keys.calcBuilderThenApply)}\n\t\t\t\t\t\t\t</label>\n\t\t\t\t\t\t\t<ReactSelect\n\t\t\t\t\t\t\t\tclassName=\"fb-calc-finish__select\"\n\t\t\t\t\t\t\t\tinputId={`${idBase}-finish`}\n\t\t\t\t\t\t\t\toptions={UNARY_OPTIONS}\n\t\t\t\t\t\t\t\tvalue={UNARY_OPTIONS.find((option) => option.value === chain.finish)}\n\t\t\t\t\t\t\t\tisClearable={!readOnly}\n\t\t\t\t\t\t\t\tdisabled={readOnly}\n\t\t\t\t\t\t\t\tonChange={(selected) => {\n\t\t\t\t\t\t\t\t\tconst chosen = singleOption(selected)\n\t\t\t\t\t\t\t\t\tcommitChain({\n\t\t\t\t\t\t\t\t\t\t...chain,\n\t\t\t\t\t\t\t\t\t\tfinish: chosen ? (chosen.value as CalcFn) : undefined,\n\t\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</>\n\t\t\t\t) : (\n\t\t\t\t\t<div className=\"fb-calc-builder__empty\">\n\t\t\t\t\t\t{storedInvalid ? (\n\t\t\t\t\t\t\t<p className=\"fb-calc-builder__warning\">{t(keys.calcBuilderStoredInvalid)}</p>\n\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t<p className=\"fb-calc-builder__hint\">{t(keys.calcBuilderAddExpression)}</p>\n\t\t\t\t\t\t<label className=\"fb-visually-hidden\" htmlFor={`${idBase}-seed`}>\n\t\t\t\t\t\t\t{t(keys.calcBuilderStartWith)}\n\t\t\t\t\t\t</label>\n\t\t\t\t\t\t<ReactSelect\n\t\t\t\t\t\t\tclassName=\"fb-calc-builder__seed\"\n\t\t\t\t\t\t\tinputId={`${idBase}-seed`}\n\t\t\t\t\t\t\toptions={\n\t\t\t\t\t\t\t\twithSourceGroup(\n\t\t\t\t\t\t\t\t\tstartOptions,\n\t\t\t\t\t\t\t\t\tscalarSourceOptions,\n\t\t\t\t\t\t\t\t\tt(keys.calcBuilderSourcesGroup)\n\t\t\t\t\t\t\t\t) as ReactSelectOption[]\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tdisabled={readOnly}\n\t\t\t\t\t\t\tplaceholder={t(keys.calcBuilderStartWith)}\n\t\t\t\t\t\t\tonChange={(selected) => {\n\t\t\t\t\t\t\t\tconst chosen = singleOption(selected)\n\t\t\t\t\t\t\t\tif (!chosen || readOnly) {\n\t\t\t\t\t\t\t\t\treturn\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tconst sourceKey = sourceKeyOf(String(chosen.value))\n\t\t\t\t\t\t\t\tsetValue(\n\t\t\t\t\t\t\t\t\tsourceKey !== undefined\n\t\t\t\t\t\t\t\t\t\t? { type: 'source', source: sourceKey }\n\t\t\t\t\t\t\t\t\t\t: seedAst(chosen.value as StartKind)\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t/>\n\t\t\t\t\t\t<ul className=\"fb-calc-builder__kinds\">\n\t\t\t\t\t\t\t{startDescriptions.map((entry) => (\n\t\t\t\t\t\t\t\t<li key={entry.key}>\n\t\t\t\t\t\t\t\t\t<span className=\"fb-calc-builder__kind-label\">{entry.label}</span>{' '}\n\t\t\t\t\t\t\t\t\t{entry.description}\n\t\t\t\t\t\t\t\t</li>\n\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t</ul>\n\t\t\t\t\t</div>\n\t\t\t\t)}\n\t\t\t\t<p className=\"fb-calc-builder__preview\" aria-live=\"polite\">\n\t\t\t\t\t{expression ? formatCalc(expression, labelOf, sourceLabelOf) : ''}\n\t\t\t\t</p>\n\t\t\t</div>\n\t\t</div>\n\t)\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
//#region src/client/ClosePollButton.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* The `poll.closePoll` UI field: one button that closes the poll and, once closed, reopens it, by
|
|
4
|
+
* saving the whole document rather than calling the `/:id/close` endpoint. Closing stamps
|
|
5
|
+
* `poll.closesAt` now while keeping the admin's just-picked winner, so both persist together through
|
|
6
|
+
* the normal save (`pollOutcomeBeforeChange` validates the winner and stamps `resolvedAt`; the
|
|
7
|
+
* `afterChange` hook enqueues the close for a `mostVoted`/`source` strategy). Reopening clears both
|
|
8
|
+
* `closesAt` and `winningValues`, since either one keeps a poll finalized. A `manual` poll with no
|
|
9
|
+
* winner selected disables the button (there is nothing to record); `mostVoted`/`source` stay enabled
|
|
10
|
+
* because the winner is server-computed. Disabled on an unsaved document (no id yet).
|
|
11
|
+
*/
|
|
12
|
+
declare const ClosePollButton: () => import("react/jsx-runtime").JSX.Element;
|
|
13
|
+
//#endregion
|
|
14
|
+
export { ClosePollButton };
|
|
15
|
+
//# sourceMappingURL=ClosePollButton.d.ts.map
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { keys } from "../translations/keys.js";
|
|
3
|
+
import { useTranslation as useTranslation$1 } from "../translations/useTranslation.js";
|
|
4
|
+
import { Button, useDocumentInfo, useForm, useFormFields } from "@payloadcms/ui";
|
|
5
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
6
|
+
import { useState } from "react";
|
|
7
|
+
//#region src/client/ClosePollButton.tsx
|
|
8
|
+
/** The help line under the button when closing, tailored to the strategy that closing will apply. */
|
|
9
|
+
const closeHintKeyFor = (type) => {
|
|
10
|
+
if (type === "mostVoted") return keys.pollCloseHintMostVoted;
|
|
11
|
+
if (type === "source") return keys.pollCloseHintSource;
|
|
12
|
+
return keys.pollCloseHintManual;
|
|
13
|
+
};
|
|
14
|
+
const strOf = (value) => typeof value === "string" && value.length > 0 ? value : "manual";
|
|
15
|
+
/** True once a `closesAt` is set (scheduled or past): the toggle treats that as closed/finalized. */
|
|
16
|
+
const isClosed = (value) => typeof value === "string" && value.length > 0;
|
|
17
|
+
/** True when the winner set holds at least one non-empty value. */
|
|
18
|
+
const hasWinner = (value) => Array.isArray(value) && value.some((entry) => typeof entry === "string" && entry.length > 0);
|
|
19
|
+
const asRecord = (value) => value != null && typeof value === "object" ? value : {};
|
|
20
|
+
/**
|
|
21
|
+
* The `poll.closePoll` UI field: one button that closes the poll and, once closed, reopens it, by
|
|
22
|
+
* saving the whole document rather than calling the `/:id/close` endpoint. Closing stamps
|
|
23
|
+
* `poll.closesAt` now while keeping the admin's just-picked winner, so both persist together through
|
|
24
|
+
* the normal save (`pollOutcomeBeforeChange` validates the winner and stamps `resolvedAt`; the
|
|
25
|
+
* `afterChange` hook enqueues the close for a `mostVoted`/`source` strategy). Reopening clears both
|
|
26
|
+
* `closesAt` and `winningValues`, since either one keeps a poll finalized. A `manual` poll with no
|
|
27
|
+
* winner selected disables the button (there is nothing to record); `mostVoted`/`source` stay enabled
|
|
28
|
+
* because the winner is server-computed. Disabled on an unsaved document (no id yet).
|
|
29
|
+
*/
|
|
30
|
+
const ClosePollButton = () => {
|
|
31
|
+
const { t } = useTranslation$1();
|
|
32
|
+
const { id } = useDocumentInfo();
|
|
33
|
+
const { getDataByPath, submit } = useForm();
|
|
34
|
+
const type = useFormFields(([fields]) => strOf(fields?.["poll.type"]?.value));
|
|
35
|
+
const closed = useFormFields(([fields]) => isClosed(fields?.["poll.closesAt"]?.value));
|
|
36
|
+
const winnerSet = useFormFields(([fields]) => hasWinner(fields?.["poll.outcome.winningValues"]?.value));
|
|
37
|
+
const [submitting, setSubmitting] = useState(false);
|
|
38
|
+
const manualNeedsWinner = !closed && type === "manual" && !winnerSet;
|
|
39
|
+
const disabled = id == null || submitting || manualNeedsWinner;
|
|
40
|
+
const save = async (nextPoll) => {
|
|
41
|
+
if (id == null) return;
|
|
42
|
+
setSubmitting(true);
|
|
43
|
+
try {
|
|
44
|
+
await submit({ overrides: { poll: nextPoll(asRecord(getDataByPath("poll"))) } });
|
|
45
|
+
} finally {
|
|
46
|
+
setSubmitting(false);
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
const close = () => save((poll) => ({
|
|
50
|
+
...poll,
|
|
51
|
+
closesAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
52
|
+
}));
|
|
53
|
+
const reopen = () => save((poll) => ({
|
|
54
|
+
...poll,
|
|
55
|
+
closesAt: null,
|
|
56
|
+
outcome: {
|
|
57
|
+
...asRecord(poll.outcome),
|
|
58
|
+
winningValues: []
|
|
59
|
+
}
|
|
60
|
+
}));
|
|
61
|
+
const hintKey = closed ? keys.pollReopenHint : manualNeedsWinner ? keys.pollCloseNeedsWinner : closeHintKeyFor(type);
|
|
62
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
63
|
+
className: "field-type",
|
|
64
|
+
style: { marginBlockEnd: "1rem" },
|
|
65
|
+
children: [/* @__PURE__ */ jsx(Button, {
|
|
66
|
+
buttonStyle: "secondary",
|
|
67
|
+
onClick: closed ? reopen : close,
|
|
68
|
+
disabled,
|
|
69
|
+
children: t(closed ? keys.pollReopenButton : keys.pollCloseButton)
|
|
70
|
+
}), /* @__PURE__ */ jsx("p", {
|
|
71
|
+
className: "field-description",
|
|
72
|
+
style: { marginBlockStart: "0.5rem" },
|
|
73
|
+
children: t(hintKey)
|
|
74
|
+
})]
|
|
75
|
+
});
|
|
76
|
+
};
|
|
77
|
+
//#endregion
|
|
78
|
+
export { ClosePollButton };
|
|
79
|
+
|
|
80
|
+
//# sourceMappingURL=ClosePollButton.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ClosePollButton.js","names":["useTranslation"],"sources":["../../src/client/ClosePollButton.tsx"],"sourcesContent":["'use client'\n\nimport { Button, useDocumentInfo, useForm, useFormFields } from '@payloadcms/ui'\nimport { useState } from 'react'\nimport { keys, type TranslationKey } from '../translations/keys'\nimport { useTranslation } from '../translations/useTranslation'\n\n/** The help line under the button when closing, tailored to the strategy that closing will apply. */\nconst closeHintKeyFor = (type: string): TranslationKey => {\n\tif (type === 'mostVoted') {\n\t\treturn keys.pollCloseHintMostVoted\n\t}\n\tif (type === 'source') {\n\t\treturn keys.pollCloseHintSource\n\t}\n\treturn keys.pollCloseHintManual\n}\n\nconst strOf = (value: unknown): string =>\n\ttypeof value === 'string' && value.length > 0 ? value : 'manual'\n\n/** True once a `closesAt` is set (scheduled or past): the toggle treats that as closed/finalized. */\nconst isClosed = (value: unknown): boolean => typeof value === 'string' && value.length > 0\n\n/** True when the winner set holds at least one non-empty value. */\nconst hasWinner = (value: unknown): boolean =>\n\tArray.isArray(value) && value.some((entry) => typeof entry === 'string' && entry.length > 0)\n\nconst asRecord = (value: unknown): Record<string, unknown> =>\n\tvalue != null && typeof value === 'object' ? (value as Record<string, unknown>) : {}\n\n/**\n * The `poll.closePoll` UI field: one button that closes the poll and, once closed, reopens it, by\n * saving the whole document rather than calling the `/:id/close` endpoint. Closing stamps\n * `poll.closesAt` now while keeping the admin's just-picked winner, so both persist together through\n * the normal save (`pollOutcomeBeforeChange` validates the winner and stamps `resolvedAt`; the\n * `afterChange` hook enqueues the close for a `mostVoted`/`source` strategy). Reopening clears both\n * `closesAt` and `winningValues`, since either one keeps a poll finalized. A `manual` poll with no\n * winner selected disables the button (there is nothing to record); `mostVoted`/`source` stay enabled\n * because the winner is server-computed. Disabled on an unsaved document (no id yet).\n */\nexport const ClosePollButton = () => {\n\tconst { t } = useTranslation()\n\tconst { id } = useDocumentInfo()\n\tconst { getDataByPath, submit } = useForm()\n\tconst type = useFormFields(([fields]) => strOf(fields?.['poll.type']?.value))\n\tconst closed = useFormFields(([fields]) => isClosed(fields?.['poll.closesAt']?.value))\n\tconst winnerSet = useFormFields(([fields]) =>\n\t\thasWinner(fields?.['poll.outcome.winningValues']?.value)\n\t)\n\tconst [submitting, setSubmitting] = useState(false)\n\n\tconst manualNeedsWinner = !closed && type === 'manual' && !winnerSet\n\tconst disabled = id == null || submitting || manualNeedsWinner\n\n\tconst save = async (nextPoll: (poll: Record<string, unknown>) => Record<string, unknown>) => {\n\t\tif (id == null) {\n\t\t\treturn\n\t\t}\n\t\tsetSubmitting(true)\n\t\ttry {\n\t\t\t// Rebuild the whole poll group from live form state and override it in one shot: a shallow\n\t\t\t// top-level override, so the winner and every other poll field are preserved (a dotted\n\t\t\t// `poll.closesAt` override key never reaches the nested field on the server).\n\t\t\tconst poll = asRecord(getDataByPath('poll'))\n\t\t\tawait submit({ overrides: { poll: nextPoll(poll) } })\n\t\t} finally {\n\t\t\tsetSubmitting(false)\n\t\t}\n\t}\n\n\tconst close = () => save((poll) => ({ ...poll, closesAt: new Date().toISOString() }))\n\tconst reopen = () =>\n\t\tsave((poll) => ({\n\t\t\t...poll,\n\t\t\tclosesAt: null,\n\t\t\toutcome: { ...asRecord(poll.outcome), winningValues: [] },\n\t\t}))\n\n\tconst hintKey: TranslationKey = closed\n\t\t? keys.pollReopenHint\n\t\t: manualNeedsWinner\n\t\t\t? keys.pollCloseNeedsWinner\n\t\t\t: closeHintKeyFor(type)\n\n\treturn (\n\t\t<div className=\"field-type\" style={{ marginBlockEnd: '1rem' }}>\n\t\t\t<Button buttonStyle=\"secondary\" onClick={closed ? reopen : close} disabled={disabled}>\n\t\t\t\t{t(closed ? keys.pollReopenButton : keys.pollCloseButton)}\n\t\t\t</Button>\n\t\t\t<p className=\"field-description\" style={{ marginBlockStart: '0.5rem' }}>\n\t\t\t\t{t(hintKey)}\n\t\t\t</p>\n\t\t</div>\n\t)\n}\n"],"mappings":";;;;;;;;AAQA,MAAM,mBAAmB,SAAiC;CACzD,IAAI,SAAS,aACZ,OAAO,KAAK;CAEb,IAAI,SAAS,UACZ,OAAO,KAAK;CAEb,OAAO,KAAK;AACb;AAEA,MAAM,SAAS,UACd,OAAO,UAAU,YAAY,MAAM,SAAS,IAAI,QAAQ;;AAGzD,MAAM,YAAY,UAA4B,OAAO,UAAU,YAAY,MAAM,SAAS;;AAG1F,MAAM,aAAa,UAClB,MAAM,QAAQ,KAAK,KAAK,MAAM,MAAM,UAAU,OAAO,UAAU,YAAY,MAAM,SAAS,CAAC;AAE5F,MAAM,YAAY,UACjB,SAAS,QAAQ,OAAO,UAAU,WAAY,QAAoC,CAAC;;;;;;;;;;;AAYpF,MAAa,wBAAwB;CACpC,MAAM,EAAE,MAAMA,iBAAe;CAC7B,MAAM,EAAE,OAAO,gBAAgB;CAC/B,MAAM,EAAE,eAAe,WAAW,QAAQ;CAC1C,MAAM,OAAO,eAAe,CAAC,YAAY,MAAM,SAAS,cAAc,KAAK,CAAC;CAC5E,MAAM,SAAS,eAAe,CAAC,YAAY,SAAS,SAAS,kBAAkB,KAAK,CAAC;CACrF,MAAM,YAAY,eAAe,CAAC,YACjC,UAAU,SAAS,+BAA+B,KAAK,CACxD;CACA,MAAM,CAAC,YAAY,iBAAiB,SAAS,KAAK;CAElD,MAAM,oBAAoB,CAAC,UAAU,SAAS,YAAY,CAAC;CAC3D,MAAM,WAAW,MAAM,QAAQ,cAAc;CAE7C,MAAM,OAAO,OAAO,aAAyE;EAC5F,IAAI,MAAM,MACT;EAED,cAAc,IAAI;EAClB,IAAI;GAKH,MAAM,OAAO,EAAE,WAAW,EAAE,MAAM,SADrB,SAAS,cAAc,MAAM,CACI,CAAC,EAAE,EAAE,CAAC;EACrD,UAAU;GACT,cAAc,KAAK;EACpB;CACD;CAEA,MAAM,cAAc,MAAM,UAAU;EAAE,GAAG;EAAM,2BAAU,IAAI,KAAK,GAAE,YAAY;CAAE,EAAE;CACpF,MAAM,eACL,MAAM,UAAU;EACf,GAAG;EACH,UAAU;EACV,SAAS;GAAE,GAAG,SAAS,KAAK,OAAO;GAAG,eAAe,CAAC;EAAE;CACzD,EAAE;CAEH,MAAM,UAA0B,SAC7B,KAAK,iBACL,oBACC,KAAK,uBACL,gBAAgB,IAAI;CAExB,OACC,qBAAC,OAAD;EAAK,WAAU;EAAa,OAAO,EAAE,gBAAgB,OAAO;YAA5D,CACC,oBAAC,QAAD;GAAQ,aAAY;GAAY,SAAS,SAAS,SAAS;GAAiB;aAC1E,EAAE,SAAS,KAAK,mBAAmB,KAAK,eAAe;EACjD,CAAA,GACR,oBAAC,KAAD;GAAG,WAAU;GAAoB,OAAO,EAAE,kBAAkB,SAAS;aACnE,EAAE,OAAO;EACR,CAAA,CACC;;AAEP"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { ArrayFieldClientComponent } from "payload";
|
|
2
|
+
//#region src/client/CondensedArray.d.ts
|
|
3
|
+
/**
|
|
4
|
+
* A custom `Field` for a real Payload `array` that renders its rows flat: each row is `[label, email]`
|
|
5
|
+
* laid out at 50% width with a remove control, added by a footer button, and never wrapped in the
|
|
6
|
+
* per-row `Collapsible` that Payload's native array applies unconditionally. Row ids and per-locale
|
|
7
|
+
* storage stay Payload's: rows come from `useField({ hasRows: true })`, mutations go through
|
|
8
|
+
* `useForm`'s `addFieldRow`/`removeFieldRow`, and each row's subfields render through `RenderFields`
|
|
9
|
+
* at `{path}.{index}` exactly as the native array does, so localization, validation, and descriptions
|
|
10
|
+
* work natively. Placed by {@link departmentsField}.
|
|
11
|
+
*/
|
|
12
|
+
declare const CondensedArray: ArrayFieldClientComponent;
|
|
13
|
+
//#endregion
|
|
14
|
+
export { CondensedArray };
|
|
15
|
+
//# sourceMappingURL=CondensedArray.d.ts.map
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { keys } from "../translations/keys.js";
|
|
3
|
+
import { useTranslation as useTranslation$1 } from "../translations/useTranslation.js";
|
|
4
|
+
import { Button, FieldDescription, FieldLabel, RenderCustomComponent, RenderFields, useField, useForm } from "@payloadcms/ui";
|
|
5
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
6
|
+
import "./admin.css";
|
|
7
|
+
//#region src/client/CondensedArray.tsx
|
|
8
|
+
const baseClass = "fb-condensed-array";
|
|
9
|
+
/**
|
|
10
|
+
* A custom `Field` for a real Payload `array` that renders its rows flat: each row is `[label, email]`
|
|
11
|
+
* laid out at 50% width with a remove control, added by a footer button, and never wrapped in the
|
|
12
|
+
* per-row `Collapsible` that Payload's native array applies unconditionally. Row ids and per-locale
|
|
13
|
+
* storage stay Payload's: rows come from `useField({ hasRows: true })`, mutations go through
|
|
14
|
+
* `useForm`'s `addFieldRow`/`removeFieldRow`, and each row's subfields render through `RenderFields`
|
|
15
|
+
* at `{path}.{index}` exactly as the native array does, so localization, validation, and descriptions
|
|
16
|
+
* work natively. Placed by {@link departmentsField}.
|
|
17
|
+
*/
|
|
18
|
+
const CondensedArray = (props) => {
|
|
19
|
+
const { field: { name, admin: { description } = {}, fields, label, localized }, forceRender = false, path: pathFromProps, permissions, readOnly, schemaPath: schemaPathFromProps } = props;
|
|
20
|
+
const schemaPath = schemaPathFromProps ?? name;
|
|
21
|
+
const { t } = useTranslation$1();
|
|
22
|
+
const { addFieldRow, removeFieldRow } = useForm();
|
|
23
|
+
const { customComponents: { Description, Label } = {}, path, rows = [] } = useField({
|
|
24
|
+
hasRows: true,
|
|
25
|
+
potentiallyStalePath: pathFromProps
|
|
26
|
+
});
|
|
27
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
28
|
+
className: `field-type ${baseClass}`,
|
|
29
|
+
id: `field-${path.replace(/\./g, "__")}`,
|
|
30
|
+
children: [
|
|
31
|
+
/* @__PURE__ */ jsx(RenderCustomComponent, {
|
|
32
|
+
CustomComponent: Label,
|
|
33
|
+
Fallback: /* @__PURE__ */ jsx(FieldLabel, {
|
|
34
|
+
label,
|
|
35
|
+
localized,
|
|
36
|
+
path
|
|
37
|
+
})
|
|
38
|
+
}),
|
|
39
|
+
/* @__PURE__ */ jsx(RenderCustomComponent, {
|
|
40
|
+
CustomComponent: Description,
|
|
41
|
+
Fallback: /* @__PURE__ */ jsx(FieldDescription, {
|
|
42
|
+
description,
|
|
43
|
+
path
|
|
44
|
+
})
|
|
45
|
+
}),
|
|
46
|
+
rows.length > 0 ? /* @__PURE__ */ jsx("div", {
|
|
47
|
+
className: `${baseClass}__rows`,
|
|
48
|
+
children: rows.map((row, index) => /* @__PURE__ */ jsxs("div", {
|
|
49
|
+
className: `${baseClass}__row`,
|
|
50
|
+
children: [/* @__PURE__ */ jsx(RenderFields, {
|
|
51
|
+
className: `${baseClass}__fields`,
|
|
52
|
+
fields,
|
|
53
|
+
forceRender,
|
|
54
|
+
margins: false,
|
|
55
|
+
parentIndexPath: "",
|
|
56
|
+
parentPath: `${path}.${index}`,
|
|
57
|
+
parentSchemaPath: schemaPath,
|
|
58
|
+
permissions: permissions === true ? permissions : permissions?.fields ?? {},
|
|
59
|
+
readOnly
|
|
60
|
+
}), !readOnly ? /* @__PURE__ */ jsx("div", {
|
|
61
|
+
className: `${baseClass}__remove`,
|
|
62
|
+
children: /* @__PURE__ */ jsx(Button, {
|
|
63
|
+
buttonStyle: "icon-label",
|
|
64
|
+
icon: "x",
|
|
65
|
+
onClick: () => removeFieldRow({
|
|
66
|
+
path,
|
|
67
|
+
rowIndex: index
|
|
68
|
+
}),
|
|
69
|
+
"aria-label": t(keys.departmentRemoveRow),
|
|
70
|
+
margin: false
|
|
71
|
+
})
|
|
72
|
+
}) : null]
|
|
73
|
+
}, row.id))
|
|
74
|
+
}) : null,
|
|
75
|
+
!readOnly ? /* @__PURE__ */ jsx("div", {
|
|
76
|
+
className: `${baseClass}__actions`,
|
|
77
|
+
children: /* @__PURE__ */ jsx(Button, {
|
|
78
|
+
buttonStyle: "icon-label",
|
|
79
|
+
icon: "plus",
|
|
80
|
+
iconStyle: "with-border",
|
|
81
|
+
iconPosition: "left",
|
|
82
|
+
onClick: () => addFieldRow({
|
|
83
|
+
path,
|
|
84
|
+
rowIndex: rows.length,
|
|
85
|
+
schemaPath
|
|
86
|
+
}),
|
|
87
|
+
margin: false,
|
|
88
|
+
children: t(keys.departmentAddRow)
|
|
89
|
+
})
|
|
90
|
+
}) : null
|
|
91
|
+
]
|
|
92
|
+
});
|
|
93
|
+
};
|
|
94
|
+
//#endregion
|
|
95
|
+
export { CondensedArray };
|
|
96
|
+
|
|
97
|
+
//# sourceMappingURL=CondensedArray.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CondensedArray.js","names":["useTranslation"],"sources":["../../src/client/CondensedArray.tsx"],"sourcesContent":["'use client'\n\nimport {\n\tButton,\n\tFieldDescription,\n\tFieldLabel,\n\tRenderCustomComponent,\n\tRenderFields,\n\tuseField,\n\tuseForm,\n} from '@payloadcms/ui'\nimport type { ArrayFieldClientComponent } from 'payload'\nimport { keys } from '../translations/keys'\nimport { useTranslation } from '../translations/useTranslation'\nimport './admin.css'\n\nconst baseClass = 'fb-condensed-array'\n\n/**\n * A custom `Field` for a real Payload `array` that renders its rows flat: each row is `[label, email]`\n * laid out at 50% width with a remove control, added by a footer button, and never wrapped in the\n * per-row `Collapsible` that Payload's native array applies unconditionally. Row ids and per-locale\n * storage stay Payload's: rows come from `useField({ hasRows: true })`, mutations go through\n * `useForm`'s `addFieldRow`/`removeFieldRow`, and each row's subfields render through `RenderFields`\n * at `{path}.{index}` exactly as the native array does, so localization, validation, and descriptions\n * work natively. Placed by {@link departmentsField}.\n */\nexport const CondensedArray: ArrayFieldClientComponent = (props) => {\n\tconst {\n\t\tfield: { name, admin: { description } = {}, fields, label, localized },\n\t\tforceRender = false,\n\t\tpath: pathFromProps,\n\t\tpermissions,\n\t\treadOnly,\n\t\tschemaPath: schemaPathFromProps,\n\t} = props\n\tconst schemaPath = schemaPathFromProps ?? name\n\n\tconst { t } = useTranslation()\n\tconst { addFieldRow, removeFieldRow } = useForm()\n\tconst {\n\t\tcustomComponents: { Description, Label } = {},\n\t\tpath,\n\t\trows = [],\n\t} = useField<number>({ hasRows: true, potentiallyStalePath: pathFromProps })\n\n\treturn (\n\t\t<div className={`field-type ${baseClass}`} id={`field-${path.replace(/\\./g, '__')}`}>\n\t\t\t<RenderCustomComponent\n\t\t\t\tCustomComponent={Label}\n\t\t\t\tFallback={<FieldLabel label={label} localized={localized} path={path} />}\n\t\t\t/>\n\t\t\t<RenderCustomComponent\n\t\t\t\tCustomComponent={Description}\n\t\t\t\tFallback={<FieldDescription description={description} path={path} />}\n\t\t\t/>\n\t\t\t{rows.length > 0 ? (\n\t\t\t\t<div className={`${baseClass}__rows`}>\n\t\t\t\t\t{rows.map((row, index) => (\n\t\t\t\t\t\t<div key={row.id} className={`${baseClass}__row`}>\n\t\t\t\t\t\t\t<RenderFields\n\t\t\t\t\t\t\t\tclassName={`${baseClass}__fields`}\n\t\t\t\t\t\t\t\tfields={fields}\n\t\t\t\t\t\t\t\tforceRender={forceRender}\n\t\t\t\t\t\t\t\tmargins={false}\n\t\t\t\t\t\t\t\tparentIndexPath=\"\"\n\t\t\t\t\t\t\t\tparentPath={`${path}.${index}`}\n\t\t\t\t\t\t\t\tparentSchemaPath={schemaPath}\n\t\t\t\t\t\t\t\tpermissions={permissions === true ? permissions : (permissions?.fields ?? {})}\n\t\t\t\t\t\t\t\treadOnly={readOnly}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t{!readOnly ? (\n\t\t\t\t\t\t\t\t<div className={`${baseClass}__remove`}>\n\t\t\t\t\t\t\t\t\t<Button\n\t\t\t\t\t\t\t\t\t\tbuttonStyle=\"icon-label\"\n\t\t\t\t\t\t\t\t\t\ticon=\"x\"\n\t\t\t\t\t\t\t\t\t\tonClick={() => removeFieldRow({ path, rowIndex: index })}\n\t\t\t\t\t\t\t\t\t\taria-label={t(keys.departmentRemoveRow)}\n\t\t\t\t\t\t\t\t\t\tmargin={false}\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t))}\n\t\t\t\t</div>\n\t\t\t) : null}\n\t\t\t{!readOnly ? (\n\t\t\t\t<div className={`${baseClass}__actions`}>\n\t\t\t\t\t<Button\n\t\t\t\t\t\tbuttonStyle=\"icon-label\"\n\t\t\t\t\t\ticon=\"plus\"\n\t\t\t\t\t\ticonStyle=\"with-border\"\n\t\t\t\t\t\ticonPosition=\"left\"\n\t\t\t\t\t\tonClick={() => addFieldRow({ path, rowIndex: rows.length, schemaPath })}\n\t\t\t\t\t\tmargin={false}\n\t\t\t\t\t>\n\t\t\t\t\t\t{t(keys.departmentAddRow)}\n\t\t\t\t\t</Button>\n\t\t\t\t</div>\n\t\t\t) : null}\n\t\t</div>\n\t)\n}\n"],"mappings":";;;;;;;AAgBA,MAAM,YAAY;;;;;;;;;;AAWlB,MAAa,kBAA6C,UAAU;CACnE,MAAM,EACL,OAAO,EAAE,MAAM,OAAO,EAAE,gBAAgB,CAAC,GAAG,QAAQ,OAAO,aAC3D,cAAc,OACd,MAAM,eACN,aACA,UACA,YAAY,wBACT;CACJ,MAAM,aAAa,uBAAuB;CAE1C,MAAM,EAAE,MAAMA,iBAAe;CAC7B,MAAM,EAAE,aAAa,mBAAmB,QAAQ;CAChD,MAAM,EACL,kBAAkB,EAAE,aAAa,UAAU,CAAC,GAC5C,MACA,OAAO,CAAC,MACL,SAAiB;EAAE,SAAS;EAAM,sBAAsB;CAAc,CAAC;CAE3E,OACC,qBAAC,OAAD;EAAK,WAAW,cAAc;EAAa,IAAI,SAAS,KAAK,QAAQ,OAAO,IAAI;YAAhF;GACC,oBAAC,uBAAD;IACC,iBAAiB;IACjB,UAAU,oBAAC,YAAD;KAAmB;KAAkB;KAAiB;IAAO,CAAA;GACvE,CAAA;GACD,oBAAC,uBAAD;IACC,iBAAiB;IACjB,UAAU,oBAAC,kBAAD;KAA+B;KAAmB;IAAO,CAAA;GACnE,CAAA;GACA,KAAK,SAAS,IACd,oBAAC,OAAD;IAAK,WAAW,GAAG,UAAU;cAC3B,KAAK,KAAK,KAAK,UACf,qBAAC,OAAD;KAAkB,WAAW,GAAG,UAAU;eAA1C,CACC,oBAAC,cAAD;MACC,WAAW,GAAG,UAAU;MAChB;MACK;MACb,SAAS;MACT,iBAAgB;MAChB,YAAY,GAAG,KAAK,GAAG;MACvB,kBAAkB;MAClB,aAAa,gBAAgB,OAAO,cAAe,aAAa,UAAU,CAAC;MACjE;KACV,CAAA,GACA,CAAC,WACD,oBAAC,OAAD;MAAK,WAAW,GAAG,UAAU;gBAC5B,oBAAC,QAAD;OACC,aAAY;OACZ,MAAK;OACL,eAAe,eAAe;QAAE;QAAM,UAAU;OAAM,CAAC;OACvD,cAAY,EAAE,KAAK,mBAAmB;OACtC,QAAQ;MACR,CAAA;KACG,CAAA,IACF,IACA;OAvBK,IAAI,EAuBT,CACL;GACG,CAAA,IACF;GACH,CAAC,WACD,oBAAC,OAAD;IAAK,WAAW,GAAG,UAAU;cAC5B,oBAAC,QAAD;KACC,aAAY;KACZ,MAAK;KACL,WAAU;KACV,cAAa;KACb,eAAe,YAAY;MAAE;MAAM,UAAU,KAAK;MAAQ;KAAW,CAAC;KACtE,QAAQ;eAEP,EAAE,KAAK,gBAAgB;IACjB,CAAA;GACJ,CAAA,IACF;EACA;;AAEP"}
|
|
@@ -6,8 +6,9 @@ import { operandFromRow } from "./synthesizeClientField.js";
|
|
|
6
6
|
import { ConditionRow } from "./ConditionRow.js";
|
|
7
7
|
import { reduceFieldsToValues, transformWhereQuery } from "payload/shared";
|
|
8
8
|
import { Button, useFormFields } from "@payloadcms/ui";
|
|
9
|
-
import { useMemo } from "react";
|
|
10
9
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
10
|
+
import { useMemo } from "react";
|
|
11
|
+
import "./admin.css";
|
|
11
12
|
//#region src/client/ConditionBuilder.tsx
|
|
12
13
|
const toRow = (constraint) => {
|
|
13
14
|
const field = Object.keys(constraint)[0];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ConditionBuilder.js","names":["useTranslation"],"sources":["../../src/client/ConditionBuilder.tsx"],"sourcesContent":["'use client'\n\nimport { Button, useFormFields } from '@payloadcms/ui'\nimport type { Operator, Where } from 'payload'\nimport { reduceFieldsToValues, transformWhereQuery } from 'payload/shared'\nimport { useMemo } from 'react'\nimport { type ConditionFieldType, firstOperatorFor } from '../conditions/fieldTypes'\nimport { keys } from '../translations/keys'\nimport { useTranslation } from '../translations/useTranslation'\nimport { ConditionRow, type RowCondition } from './ConditionRow'\nimport { type ConditionOperand, type FieldRow, operandFromRow } from './synthesizeClientField'\n\nexport type ConditionBuilderProps = {\n\tvalue?: Where\n\tonChange: (next: Where) => void\n\tconditionTypes: Record<string, ConditionFieldType>\n\t/** This field's own machine name, excluded from the operand list (a field cannot condition on itself). */\n\tselfName?: string\n}\n\nconst toRow = (constraint: Record<string, unknown>): RowCondition | null => {\n\tconst field = Object.keys(constraint)[0]\n\tif (!field) {\n\t\treturn null\n\t}\n\tconst ops = constraint[field] as Record<string, unknown>\n\tconst operator = Object.keys(ops)[0] as Operator | undefined\n\tif (!operator) {\n\t\treturn null\n\t}\n\treturn { field, operator, value: ops[operator] }\n}\n\nconst fromRow = (row: RowCondition): Where => ({ [row.field]: { [row.operator]: row.value } })\n\nconst readGroups = (value: Where | undefined): RowCondition[][] => {\n\tif (!value || Object.keys(value).length === 0) {\n\t\treturn []\n\t}\n\tconst canonical = transformWhereQuery(value)\n\tconst or = Array.isArray(canonical.or) ? canonical.or : []\n\treturn or.map((group) => {\n\t\tconst and = Array.isArray((group as Where).and) ? ((group as Where).and as Where[]) : []\n\t\treturn and\n\t\t\t.map((constraint) => toRow(constraint as Record<string, unknown>))\n\t\t\t.filter((row): row is RowCondition => row !== null)\n\t})\n}\n\nconst writeGroups = (groups: RowCondition[][]): Where => ({\n\tor: groups.filter((group) => group.length > 0).map((group) => ({ and: group.map(fromRow) })),\n})\n\nconst operandsFromData = (\n\tdata: Record<string, unknown>,\n\tconditionTypes: Record<string, ConditionFieldType>,\n\tselfName: string | undefined\n): ConditionOperand[] => {\n\tconst rows = Array.isArray(data.fields) ? (data.fields as FieldRow[]) : []\n\treturn rows\n\t\t.map((row) => operandFromRow(row, conditionTypes))\n\t\t.filter((operand): operand is ConditionOperand => operand !== null && operand.name !== selfName)\n}\n\nexport const ConditionBuilder = ({\n\tvalue,\n\tonChange,\n\tconditionTypes,\n\tselfName,\n}: ConditionBuilderProps) => {\n\tconst { t } = useTranslation()\n\t// Serialize the operand list so the builder re-renders only when operands actually change (a field\n\t// added, renamed, retyped, or its options edited), not on every unrelated form-state update.\n\tconst operandsJson = useFormFields(([fields]) =>\n\t\tJSON.stringify(operandsFromData(reduceFieldsToValues(fields, true), conditionTypes, selfName))\n\t)\n\tconst operands = useMemo(() => JSON.parse(operandsJson) as ConditionOperand[], [operandsJson])\n\n\tconst groups = readGroups(value)\n\tconst emit = (next: RowCondition[][]) => onChange(writeGroups(next))\n\n\tconst addCondition = (groupIndex: number) => {\n\t\tconst first = operands[0]\n\t\tif (!first) {\n\t\t\treturn\n\t\t}\n\t\tconst row: RowCondition = {\n\t\t\tfield: first.name,\n\t\t\toperator: firstOperatorFor(first.conditionType),\n\t\t\tvalue: undefined,\n\t\t}\n\t\temit(\n\t\t\tgroups.length === 0\n\t\t\t\t? [[row]]\n\t\t\t\t: groups.map((group, index) => (index === groupIndex ? [...group, row] : group))\n\t\t)\n\t}\n\n\tconst addOrGroup = () => {\n\t\tconst first = operands[0]\n\t\tif (!first) {\n\t\t\treturn\n\t\t}\n\t\temit([\n\t\t\t...groups,\n\t\t\t[{ field: first.name, operator: firstOperatorFor(first.conditionType), value: undefined }],\n\t\t])\n\t}\n\n\tconst updateRow = (groupIndex: number, rowIndex: number, row: RowCondition) =>\n\t\temit(\n\t\t\tgroups.map((group, index) =>\n\t\t\t\tindex === groupIndex\n\t\t\t\t\t? group.map((existing, position) => (position === rowIndex ? row : existing))\n\t\t\t\t\t: group\n\t\t\t)\n\t\t)\n\n\tconst removeRow = (groupIndex: number, rowIndex: number) =>\n\t\temit(\n\t\t\tgroups\n\t\t\t\t.map((group, index) =>\n\t\t\t\t\tindex === groupIndex ? group.filter((_, position) => position !== rowIndex) : group\n\t\t\t\t)\n\t\t\t\t.filter((group) => group.length > 0)\n\t\t)\n\n\tif (operands.length === 0) {\n\t\treturn <p className=\"fb-condition-builder__hint\">{t(keys.conditionNoFields)}</p>\n\t}\n\n\treturn (\n\t\t<div className=\"fb-condition-builder\">\n\t\t\t{groups.length === 0 ? (\n\t\t\t\t<p className=\"fb-condition-builder__hint\">{t(keys.conditionEmpty)}</p>\n\t\t\t) : (\n\t\t\t\tgroups.map((group, groupIndex) => (\n\t\t\t\t\t// biome-ignore lint/suspicious/noArrayIndexKey: groups are positional and never reordered\n\t\t\t\t\t<div key={groupIndex} className=\"fb-condition-builder__group\">\n\t\t\t\t\t\t{groupIndex > 0 ? (\n\t\t\t\t\t\t\t<div className=\"fb-condition-builder__or-label\">{t(keys.conditionOr)}</div>\n\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t{group.map((row, rowIndex) => (\n\t\t\t\t\t\t\t// biome-ignore lint/suspicious/noArrayIndexKey: rows are positional and never reordered\n\t\t\t\t\t\t\t<div key={rowIndex} className=\"fb-condition-builder__and-row\">\n\t\t\t\t\t\t\t\t{rowIndex > 0 ? (\n\t\t\t\t\t\t\t\t\t<span className=\"fb-condition-builder__and-label\">{t(keys.conditionAnd)}</span>\n\t\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t\t<ConditionRow\n\t\t\t\t\t\t\t\t\tcondition={row}\n\t\t\t\t\t\t\t\t\toperands={operands}\n\t\t\t\t\t\t\t\t\tonChange={(next) => updateRow(groupIndex, rowIndex, next)}\n\t\t\t\t\t\t\t\t\tonRemove={() => removeRow(groupIndex, rowIndex)}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t))}\n\t\t\t\t\t\t<div className=\"fb-condition-builder__add-condition\">\n\t\t\t\t\t\t\t<Button\n\t\t\t\t\t\t\t\tbuttonStyle=\"icon-label\"\n\t\t\t\t\t\t\t\ticon=\"plus\"\n\t\t\t\t\t\t\t\ticonStyle=\"with-border\"\n\t\t\t\t\t\t\t\ticonPosition=\"left\"\n\t\t\t\t\t\t\t\tonClick={() => addCondition(groupIndex)}\n\t\t\t\t\t\t\t\tmargin={false}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{t(keys.conditionAddCondition)}\n\t\t\t\t\t\t\t</Button>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\t\t\t\t))\n\t\t\t)}\n\t\t\t<div className=\"fb-condition-builder__actions\">\n\t\t\t\t<Button\n\t\t\t\t\tbuttonStyle=\"icon-label\"\n\t\t\t\t\ticon=\"plus\"\n\t\t\t\t\ticonStyle=\"with-border\"\n\t\t\t\t\ticonPosition=\"left\"\n\t\t\t\t\tonClick={() => (groups.length === 0 ? addCondition(0) : addOrGroup())}\n\t\t\t\t\tmargin={false}\n\t\t\t\t>\n\t\t\t\t\t{groups.length === 0 ? t(keys.conditionAddCondition) : t(keys.conditionAddOr)}\n\t\t\t\t</Button>\n\t\t\t</div>\n\t\t</div>\n\t)\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"ConditionBuilder.js","names":["useTranslation"],"sources":["../../src/client/ConditionBuilder.tsx"],"sourcesContent":["'use client'\n\nimport { Button, useFormFields } from '@payloadcms/ui'\nimport type { Operator, Where } from 'payload'\nimport { reduceFieldsToValues, transformWhereQuery } from 'payload/shared'\nimport { useMemo } from 'react'\nimport { type ConditionFieldType, firstOperatorFor } from '../conditions/fieldTypes'\nimport { keys } from '../translations/keys'\nimport { useTranslation } from '../translations/useTranslation'\nimport { ConditionRow, type RowCondition } from './ConditionRow'\nimport { type ConditionOperand, type FieldRow, operandFromRow } from './synthesizeClientField'\nimport './admin.css'\n\nexport type ConditionBuilderProps = {\n\tvalue?: Where\n\tonChange: (next: Where) => void\n\tconditionTypes: Record<string, ConditionFieldType>\n\t/** This field's own machine name, excluded from the operand list (a field cannot condition on itself). */\n\tselfName?: string\n}\n\nconst toRow = (constraint: Record<string, unknown>): RowCondition | null => {\n\tconst field = Object.keys(constraint)[0]\n\tif (!field) {\n\t\treturn null\n\t}\n\tconst ops = constraint[field] as Record<string, unknown>\n\tconst operator = Object.keys(ops)[0] as Operator | undefined\n\tif (!operator) {\n\t\treturn null\n\t}\n\treturn { field, operator, value: ops[operator] }\n}\n\nconst fromRow = (row: RowCondition): Where => ({ [row.field]: { [row.operator]: row.value } })\n\nconst readGroups = (value: Where | undefined): RowCondition[][] => {\n\tif (!value || Object.keys(value).length === 0) {\n\t\treturn []\n\t}\n\tconst canonical = transformWhereQuery(value)\n\tconst or = Array.isArray(canonical.or) ? canonical.or : []\n\treturn or.map((group) => {\n\t\tconst and = Array.isArray((group as Where).and) ? ((group as Where).and as Where[]) : []\n\t\treturn and\n\t\t\t.map((constraint) => toRow(constraint as Record<string, unknown>))\n\t\t\t.filter((row): row is RowCondition => row !== null)\n\t})\n}\n\nconst writeGroups = (groups: RowCondition[][]): Where => ({\n\tor: groups.filter((group) => group.length > 0).map((group) => ({ and: group.map(fromRow) })),\n})\n\nconst operandsFromData = (\n\tdata: Record<string, unknown>,\n\tconditionTypes: Record<string, ConditionFieldType>,\n\tselfName: string | undefined\n): ConditionOperand[] => {\n\tconst rows = Array.isArray(data.fields) ? (data.fields as FieldRow[]) : []\n\treturn rows\n\t\t.map((row) => operandFromRow(row, conditionTypes))\n\t\t.filter((operand): operand is ConditionOperand => operand !== null && operand.name !== selfName)\n}\n\nexport const ConditionBuilder = ({\n\tvalue,\n\tonChange,\n\tconditionTypes,\n\tselfName,\n}: ConditionBuilderProps) => {\n\tconst { t } = useTranslation()\n\t// Serialize the operand list so the builder re-renders only when operands actually change (a field\n\t// added, renamed, retyped, or its options edited), not on every unrelated form-state update.\n\tconst operandsJson = useFormFields(([fields]) =>\n\t\tJSON.stringify(operandsFromData(reduceFieldsToValues(fields, true), conditionTypes, selfName))\n\t)\n\tconst operands = useMemo(() => JSON.parse(operandsJson) as ConditionOperand[], [operandsJson])\n\n\tconst groups = readGroups(value)\n\tconst emit = (next: RowCondition[][]) => onChange(writeGroups(next))\n\n\tconst addCondition = (groupIndex: number) => {\n\t\tconst first = operands[0]\n\t\tif (!first) {\n\t\t\treturn\n\t\t}\n\t\tconst row: RowCondition = {\n\t\t\tfield: first.name,\n\t\t\toperator: firstOperatorFor(first.conditionType),\n\t\t\tvalue: undefined,\n\t\t}\n\t\temit(\n\t\t\tgroups.length === 0\n\t\t\t\t? [[row]]\n\t\t\t\t: groups.map((group, index) => (index === groupIndex ? [...group, row] : group))\n\t\t)\n\t}\n\n\tconst addOrGroup = () => {\n\t\tconst first = operands[0]\n\t\tif (!first) {\n\t\t\treturn\n\t\t}\n\t\temit([\n\t\t\t...groups,\n\t\t\t[{ field: first.name, operator: firstOperatorFor(first.conditionType), value: undefined }],\n\t\t])\n\t}\n\n\tconst updateRow = (groupIndex: number, rowIndex: number, row: RowCondition) =>\n\t\temit(\n\t\t\tgroups.map((group, index) =>\n\t\t\t\tindex === groupIndex\n\t\t\t\t\t? group.map((existing, position) => (position === rowIndex ? row : existing))\n\t\t\t\t\t: group\n\t\t\t)\n\t\t)\n\n\tconst removeRow = (groupIndex: number, rowIndex: number) =>\n\t\temit(\n\t\t\tgroups\n\t\t\t\t.map((group, index) =>\n\t\t\t\t\tindex === groupIndex ? group.filter((_, position) => position !== rowIndex) : group\n\t\t\t\t)\n\t\t\t\t.filter((group) => group.length > 0)\n\t\t)\n\n\tif (operands.length === 0) {\n\t\treturn <p className=\"fb-condition-builder__hint\">{t(keys.conditionNoFields)}</p>\n\t}\n\n\treturn (\n\t\t<div className=\"fb-condition-builder\">\n\t\t\t{groups.length === 0 ? (\n\t\t\t\t<p className=\"fb-condition-builder__hint\">{t(keys.conditionEmpty)}</p>\n\t\t\t) : (\n\t\t\t\tgroups.map((group, groupIndex) => (\n\t\t\t\t\t// biome-ignore lint/suspicious/noArrayIndexKey: groups are positional and never reordered\n\t\t\t\t\t<div key={groupIndex} className=\"fb-condition-builder__group\">\n\t\t\t\t\t\t{groupIndex > 0 ? (\n\t\t\t\t\t\t\t<div className=\"fb-condition-builder__or-label\">{t(keys.conditionOr)}</div>\n\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t{group.map((row, rowIndex) => (\n\t\t\t\t\t\t\t// biome-ignore lint/suspicious/noArrayIndexKey: rows are positional and never reordered\n\t\t\t\t\t\t\t<div key={rowIndex} className=\"fb-condition-builder__and-row\">\n\t\t\t\t\t\t\t\t{rowIndex > 0 ? (\n\t\t\t\t\t\t\t\t\t<span className=\"fb-condition-builder__and-label\">{t(keys.conditionAnd)}</span>\n\t\t\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t\t\t<ConditionRow\n\t\t\t\t\t\t\t\t\tcondition={row}\n\t\t\t\t\t\t\t\t\toperands={operands}\n\t\t\t\t\t\t\t\t\tonChange={(next) => updateRow(groupIndex, rowIndex, next)}\n\t\t\t\t\t\t\t\t\tonRemove={() => removeRow(groupIndex, rowIndex)}\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t))}\n\t\t\t\t\t\t<div className=\"fb-condition-builder__add-condition\">\n\t\t\t\t\t\t\t<Button\n\t\t\t\t\t\t\t\tbuttonStyle=\"icon-label\"\n\t\t\t\t\t\t\t\ticon=\"plus\"\n\t\t\t\t\t\t\t\ticonStyle=\"with-border\"\n\t\t\t\t\t\t\t\ticonPosition=\"left\"\n\t\t\t\t\t\t\t\tonClick={() => addCondition(groupIndex)}\n\t\t\t\t\t\t\t\tmargin={false}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{t(keys.conditionAddCondition)}\n\t\t\t\t\t\t\t</Button>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\t\t\t\t))\n\t\t\t)}\n\t\t\t<div className=\"fb-condition-builder__actions\">\n\t\t\t\t<Button\n\t\t\t\t\tbuttonStyle=\"icon-label\"\n\t\t\t\t\ticon=\"plus\"\n\t\t\t\t\ticonStyle=\"with-border\"\n\t\t\t\t\ticonPosition=\"left\"\n\t\t\t\t\tonClick={() => (groups.length === 0 ? addCondition(0) : addOrGroup())}\n\t\t\t\t\tmargin={false}\n\t\t\t\t>\n\t\t\t\t\t{groups.length === 0 ? t(keys.conditionAddCondition) : t(keys.conditionAddOr)}\n\t\t\t\t</Button>\n\t\t\t</div>\n\t\t</div>\n\t)\n}\n"],"mappings":";;;;;;;;;;;;AAqBA,MAAM,SAAS,eAA6D;CAC3E,MAAM,QAAQ,OAAO,KAAK,UAAU,EAAE;CACtC,IAAI,CAAC,OACJ,OAAO;CAER,MAAM,MAAM,WAAW;CACvB,MAAM,WAAW,OAAO,KAAK,GAAG,EAAE;CAClC,IAAI,CAAC,UACJ,OAAO;CAER,OAAO;EAAE;EAAO;EAAU,OAAO,IAAI;CAAU;AAChD;AAEA,MAAM,WAAW,SAA8B,GAAG,IAAI,QAAQ,GAAG,IAAI,WAAW,IAAI,MAAM,EAAE;AAE5F,MAAM,cAAc,UAA+C;CAClE,IAAI,CAAC,SAAS,OAAO,KAAK,KAAK,EAAE,WAAW,GAC3C,OAAO,CAAC;CAET,MAAM,YAAY,oBAAoB,KAAK;CAE3C,QADW,MAAM,QAAQ,UAAU,EAAE,IAAI,UAAU,KAAK,CAAC,GAC/C,KAAK,UAAU;EAExB,QADY,MAAM,QAAS,MAAgB,GAAG,IAAM,MAAgB,MAAkB,CAAC,GAErF,KAAK,eAAe,MAAM,UAAqC,CAAC,EAChE,QAAQ,QAA6B,QAAQ,IAAI;CACpD,CAAC;AACF;AAEA,MAAM,eAAe,YAAqC,EACzD,IAAI,OAAO,QAAQ,UAAU,MAAM,SAAS,CAAC,EAAE,KAAK,WAAW,EAAE,KAAK,MAAM,IAAI,OAAO,EAAE,EAAE,EAC5F;AAEA,MAAM,oBACL,MACA,gBACA,aACwB;CAExB,QADa,MAAM,QAAQ,KAAK,MAAM,IAAK,KAAK,SAAwB,CAAC,GAEvE,KAAK,QAAQ,eAAe,KAAK,cAAc,CAAC,EAChD,QAAQ,YAAyC,YAAY,QAAQ,QAAQ,SAAS,QAAQ;AACjG;AAEA,MAAa,oBAAoB,EAChC,OACA,UACA,gBACA,eAC4B;CAC5B,MAAM,EAAE,MAAMA,iBAAe;CAG7B,MAAM,eAAe,eAAe,CAAC,YACpC,KAAK,UAAU,iBAAiB,qBAAqB,QAAQ,IAAI,GAAG,gBAAgB,QAAQ,CAAC,CAC9F;CACA,MAAM,WAAW,cAAc,KAAK,MAAM,YAAY,GAAyB,CAAC,YAAY,CAAC;CAE7F,MAAM,SAAS,WAAW,KAAK;CAC/B,MAAM,QAAQ,SAA2B,SAAS,YAAY,IAAI,CAAC;CAEnE,MAAM,gBAAgB,eAAuB;EAC5C,MAAM,QAAQ,SAAS;EACvB,IAAI,CAAC,OACJ;EAED,MAAM,MAAoB;GACzB,OAAO,MAAM;GACb,UAAU,iBAAiB,MAAM,aAAa;GAC9C,OAAO,KAAA;EACR;EACA,KACC,OAAO,WAAW,IACf,CAAC,CAAC,GAAG,CAAC,IACN,OAAO,KAAK,OAAO,UAAW,UAAU,aAAa,CAAC,GAAG,OAAO,GAAG,IAAI,KAAM,CACjF;CACD;CAEA,MAAM,mBAAmB;EACxB,MAAM,QAAQ,SAAS;EACvB,IAAI,CAAC,OACJ;EAED,KAAK,CACJ,GAAG,QACH,CAAC;GAAE,OAAO,MAAM;GAAM,UAAU,iBAAiB,MAAM,aAAa;GAAG,OAAO,KAAA;EAAU,CAAC,CAC1F,CAAC;CACF;CAEA,MAAM,aAAa,YAAoB,UAAkB,QACxD,KACC,OAAO,KAAK,OAAO,UAClB,UAAU,aACP,MAAM,KAAK,UAAU,aAAc,aAAa,WAAW,MAAM,QAAS,IAC1E,KACJ,CACD;CAED,MAAM,aAAa,YAAoB,aACtC,KACC,OACE,KAAK,OAAO,UACZ,UAAU,aAAa,MAAM,QAAQ,GAAG,aAAa,aAAa,QAAQ,IAAI,KAC/E,EACC,QAAQ,UAAU,MAAM,SAAS,CAAC,CACrC;CAED,IAAI,SAAS,WAAW,GACvB,OAAO,oBAAC,KAAD;EAAG,WAAU;YAA8B,EAAE,KAAK,iBAAiB;CAAK,CAAA;CAGhF,OACC,qBAAC,OAAD;EAAK,WAAU;YAAf,CACE,OAAO,WAAW,IAClB,oBAAC,KAAD;GAAG,WAAU;aAA8B,EAAE,KAAK,cAAc;EAAK,CAAA,IAErE,OAAO,KAAK,OAAO,eAElB,qBAAC,OAAD;GAAsB,WAAU;aAAhC;IACE,aAAa,IACb,oBAAC,OAAD;KAAK,WAAU;eAAkC,EAAE,KAAK,WAAW;IAAO,CAAA,IACvE;IACH,MAAM,KAAK,KAAK,aAEhB,qBAAC,OAAD;KAAoB,WAAU;eAA9B,CACE,WAAW,IACX,oBAAC,QAAD;MAAM,WAAU;gBAAmC,EAAE,KAAK,YAAY;KAAQ,CAAA,IAC3E,MACJ,oBAAC,cAAD;MACC,WAAW;MACD;MACV,WAAW,SAAS,UAAU,YAAY,UAAU,IAAI;MACxD,gBAAgB,UAAU,YAAY,QAAQ;KAC9C,CAAA,CACG;OAVK,QAUL,CACL;IACD,oBAAC,OAAD;KAAK,WAAU;eACd,oBAAC,QAAD;MACC,aAAY;MACZ,MAAK;MACL,WAAU;MACV,cAAa;MACb,eAAe,aAAa,UAAU;MACtC,QAAQ;gBAEP,EAAE,KAAK,qBAAqB;KACtB,CAAA;IACJ,CAAA;GACD;KA9BK,UA8BL,CACL,GAEF,oBAAC,OAAD;GAAK,WAAU;aACd,oBAAC,QAAD;IACC,aAAY;IACZ,MAAK;IACL,WAAU;IACV,cAAa;IACb,eAAgB,OAAO,WAAW,IAAI,aAAa,CAAC,IAAI,WAAW;IACnE,QAAQ;cAEP,OAAO,WAAW,IAAI,EAAE,KAAK,qBAAqB,IAAI,EAAE,KAAK,cAAc;GACrE,CAAA;EACJ,CAAA,CACD;;AAEP"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
//#region src/client/ConsentBlockLabel.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Block row header for a consent field. The consent field stores only the source id, so this resolves
|
|
4
|
+
* it to the source's name via the same `consent-sources` endpoint the Source select uses, rendering
|
|
5
|
+
* "NN Consent {name}". Falls back to "NN Consent" while loading, when unset, or on an unsaved form
|
|
6
|
+
* (no document id yet, so the endpoint cannot resolve options).
|
|
7
|
+
*/
|
|
8
|
+
declare const ConsentBlockLabel: ({
|
|
9
|
+
typeLabelKey
|
|
10
|
+
}: {
|
|
11
|
+
typeLabelKey?: string;
|
|
12
|
+
}) => import("react/jsx-runtime").JSX.Element;
|
|
13
|
+
//#endregion
|
|
14
|
+
export { ConsentBlockLabel };
|
|
15
|
+
//# sourceMappingURL=ConsentBlockLabel.d.ts.map
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useTranslation as useTranslation$1 } from "../translations/useTranslation.js";
|
|
3
|
+
import { buildEndpointOptionsUrl, parseEndpointOptions } from "./endpointOptions.js";
|
|
4
|
+
import { useConfig, useDocumentInfo, useRowLabel } from "@payloadcms/ui";
|
|
5
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
6
|
+
import { useEffect, useState } from "react";
|
|
7
|
+
//#region src/client/ConsentBlockLabel.tsx
|
|
8
|
+
/** Endpoint url -> `{ sourceId: name }`, shared across every consent block label and re-render. */
|
|
9
|
+
const nameCache = /* @__PURE__ */ new Map();
|
|
10
|
+
/**
|
|
11
|
+
* Block row header for a consent field. The consent field stores only the source id, so this resolves
|
|
12
|
+
* it to the source's name via the same `consent-sources` endpoint the Source select uses, rendering
|
|
13
|
+
* "NN Consent {name}". Falls back to "NN Consent" while loading, when unset, or on an unsaved form
|
|
14
|
+
* (no document id yet, so the endpoint cannot resolve options).
|
|
15
|
+
*/
|
|
16
|
+
const ConsentBlockLabel = ({ typeLabelKey }) => {
|
|
17
|
+
const { data, rowNumber } = useRowLabel();
|
|
18
|
+
const { t } = useTranslation$1();
|
|
19
|
+
const { id, collectionSlug } = useDocumentInfo();
|
|
20
|
+
const { config } = useConfig();
|
|
21
|
+
const source = typeof data?.source === "string" ? data.source : "";
|
|
22
|
+
const [names, setNames] = useState({});
|
|
23
|
+
useEffect(() => {
|
|
24
|
+
if (id == null || !collectionSlug) return;
|
|
25
|
+
const url = buildEndpointOptionsUrl({
|
|
26
|
+
apiRoute: config.routes.api,
|
|
27
|
+
collectionSlug,
|
|
28
|
+
id,
|
|
29
|
+
endpoint: "consent-sources"
|
|
30
|
+
});
|
|
31
|
+
const cached = nameCache.get(url);
|
|
32
|
+
if (cached) {
|
|
33
|
+
setNames(cached);
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
const controller = new AbortController();
|
|
37
|
+
fetch(url, {
|
|
38
|
+
credentials: "include",
|
|
39
|
+
headers: { Accept: "application/json" },
|
|
40
|
+
signal: controller.signal
|
|
41
|
+
}).then(async (response) => {
|
|
42
|
+
if (!response.ok) throw new Error(`Options request failed with ${response.status}`);
|
|
43
|
+
const map = Object.fromEntries(parseEndpointOptions(await response.json()).map((o) => [o.value, o.label]));
|
|
44
|
+
nameCache.set(url, map);
|
|
45
|
+
setNames(map);
|
|
46
|
+
}).catch(() => {});
|
|
47
|
+
return () => controller.abort();
|
|
48
|
+
}, [
|
|
49
|
+
config.routes.api,
|
|
50
|
+
collectionSlug,
|
|
51
|
+
id
|
|
52
|
+
]);
|
|
53
|
+
const typeLabel = typeLabelKey ? t(typeLabelKey) : "";
|
|
54
|
+
const number = String((rowNumber ?? 0) + 1).padStart(2, "0");
|
|
55
|
+
const name = source ? names[source] ?? "" : "";
|
|
56
|
+
return /* @__PURE__ */ jsxs("span", {
|
|
57
|
+
style: {
|
|
58
|
+
alignItems: "center",
|
|
59
|
+
display: "inline-flex",
|
|
60
|
+
gap: "0.5rem"
|
|
61
|
+
},
|
|
62
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
63
|
+
style: { color: "var(--theme-elevation-500)" },
|
|
64
|
+
children: typeLabel ? `${number} ${typeLabel}` : number
|
|
65
|
+
}), name ? /* @__PURE__ */ jsx("span", { children: name }) : null]
|
|
66
|
+
});
|
|
67
|
+
};
|
|
68
|
+
//#endregion
|
|
69
|
+
export { ConsentBlockLabel };
|
|
70
|
+
|
|
71
|
+
//# sourceMappingURL=ConsentBlockLabel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ConsentBlockLabel.js","names":["useTranslation"],"sources":["../../src/client/ConsentBlockLabel.tsx"],"sourcesContent":["'use client'\n\nimport { useConfig, useDocumentInfo, useRowLabel } from '@payloadcms/ui'\nimport { useEffect, useState } from 'react'\nimport type { TranslationKey } from '../translations/keys'\nimport { useTranslation } from '../translations/useTranslation'\nimport { buildEndpointOptionsUrl, parseEndpointOptions } from './endpointOptions'\n\ntype RowData = { source?: unknown }\n\n/** Endpoint url -> `{ sourceId: name }`, shared across every consent block label and re-render. */\nconst nameCache = new Map<string, Record<string, string>>()\n\n/**\n * Block row header for a consent field. The consent field stores only the source id, so this resolves\n * it to the source's name via the same `consent-sources` endpoint the Source select uses, rendering\n * \"NN Consent {name}\". Falls back to \"NN Consent\" while loading, when unset, or on an unsaved form\n * (no document id yet, so the endpoint cannot resolve options).\n */\nexport const ConsentBlockLabel = ({ typeLabelKey }: { typeLabelKey?: string }) => {\n\tconst { data, rowNumber } = useRowLabel<RowData>()\n\tconst { t } = useTranslation()\n\tconst { id, collectionSlug } = useDocumentInfo()\n\tconst { config } = useConfig()\n\tconst source = typeof data?.source === 'string' ? data.source : ''\n\tconst [names, setNames] = useState<Record<string, string>>({})\n\n\tuseEffect(() => {\n\t\tif (id == null || !collectionSlug) {\n\t\t\treturn\n\t\t}\n\t\tconst url = buildEndpointOptionsUrl({\n\t\t\tapiRoute: config.routes.api,\n\t\t\tcollectionSlug,\n\t\t\tid,\n\t\t\tendpoint: 'consent-sources',\n\t\t})\n\t\tconst cached = nameCache.get(url)\n\t\tif (cached) {\n\t\t\tsetNames(cached)\n\t\t\treturn\n\t\t}\n\t\tconst controller = new AbortController()\n\t\tfetch(url, {\n\t\t\tcredentials: 'include',\n\t\t\theaders: { Accept: 'application/json' },\n\t\t\tsignal: controller.signal,\n\t\t})\n\t\t\t.then(async (response) => {\n\t\t\t\tif (!response.ok) {\n\t\t\t\t\tthrow new Error(`Options request failed with ${response.status}`)\n\t\t\t\t}\n\t\t\t\tconst map = Object.fromEntries(\n\t\t\t\t\tparseEndpointOptions(await response.json()).map((o) => [o.value, o.label])\n\t\t\t\t)\n\t\t\t\tnameCache.set(url, map)\n\t\t\t\tsetNames(map)\n\t\t\t})\n\t\t\t.catch(() => {})\n\t\treturn () => controller.abort()\n\t}, [config.routes.api, collectionSlug, id])\n\n\tconst typeLabel = typeLabelKey ? t(typeLabelKey as TranslationKey) : ''\n\tconst number = String((rowNumber ?? 0) + 1).padStart(2, '0')\n\tconst name = source ? (names[source] ?? '') : ''\n\treturn (\n\t\t<span style={{ alignItems: 'center', display: 'inline-flex', gap: '0.5rem' }}>\n\t\t\t<span style={{ color: 'var(--theme-elevation-500)' }}>\n\t\t\t\t{typeLabel ? `${number} ${typeLabel}` : number}\n\t\t\t</span>\n\t\t\t{name ? <span>{name}</span> : null}\n\t\t</span>\n\t)\n}\n"],"mappings":";;;;;;;;AAWA,MAAM,4BAAY,IAAI,IAAoC;;;;;;;AAQ1D,MAAa,qBAAqB,EAAE,mBAA8C;CACjF,MAAM,EAAE,MAAM,cAAc,YAAqB;CACjD,MAAM,EAAE,MAAMA,iBAAe;CAC7B,MAAM,EAAE,IAAI,mBAAmB,gBAAgB;CAC/C,MAAM,EAAE,WAAW,UAAU;CAC7B,MAAM,SAAS,OAAO,MAAM,WAAW,WAAW,KAAK,SAAS;CAChE,MAAM,CAAC,OAAO,YAAY,SAAiC,CAAC,CAAC;CAE7D,gBAAgB;EACf,IAAI,MAAM,QAAQ,CAAC,gBAClB;EAED,MAAM,MAAM,wBAAwB;GACnC,UAAU,OAAO,OAAO;GACxB;GACA;GACA,UAAU;EACX,CAAC;EACD,MAAM,SAAS,UAAU,IAAI,GAAG;EAChC,IAAI,QAAQ;GACX,SAAS,MAAM;GACf;EACD;EACA,MAAM,aAAa,IAAI,gBAAgB;EACvC,MAAM,KAAK;GACV,aAAa;GACb,SAAS,EAAE,QAAQ,mBAAmB;GACtC,QAAQ,WAAW;EACpB,CAAC,EACC,KAAK,OAAO,aAAa;GACzB,IAAI,CAAC,SAAS,IACb,MAAM,IAAI,MAAM,+BAA+B,SAAS,QAAQ;GAEjE,MAAM,MAAM,OAAO,YAClB,qBAAqB,MAAM,SAAS,KAAK,CAAC,EAAE,KAAK,MAAM,CAAC,EAAE,OAAO,EAAE,KAAK,CAAC,CAC1E;GACA,UAAU,IAAI,KAAK,GAAG;GACtB,SAAS,GAAG;EACb,CAAC,EACA,YAAY,CAAC,CAAC;EAChB,aAAa,WAAW,MAAM;CAC/B,GAAG;EAAC,OAAO,OAAO;EAAK;EAAgB;CAAE,CAAC;CAE1C,MAAM,YAAY,eAAe,EAAE,YAA8B,IAAI;CACrE,MAAM,SAAS,QAAQ,aAAa,KAAK,CAAC,EAAE,SAAS,GAAG,GAAG;CAC3D,MAAM,OAAO,SAAU,MAAM,WAAW,KAAM;CAC9C,OACC,qBAAC,QAAD;EAAM,OAAO;GAAE,YAAY;GAAU,SAAS;GAAe,KAAK;EAAS;YAA3E,CACC,oBAAC,QAAD;GAAM,OAAO,EAAE,OAAO,6BAA6B;aACjD,YAAY,GAAG,OAAO,GAAG,cAAc;EACnC,CAAA,GACL,OAAO,oBAAC,QAAD,EAAA,UAAO,KAAW,CAAA,IAAI,IACzB;;AAER"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
//#region src/client/ConsentSourceRowLabel.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Row header for a consent source array row: shows the source `name` (e.g. "Privacy Policy") instead
|
|
4
|
+
* of Payload's default "Consent source NN". Falls back to the singular label + number while unnamed.
|
|
5
|
+
*/
|
|
6
|
+
declare const ConsentSourceRowLabel: () => import("react/jsx-runtime").JSX.Element;
|
|
7
|
+
//#endregion
|
|
8
|
+
export { ConsentSourceRowLabel };
|
|
9
|
+
//# sourceMappingURL=ConsentSourceRowLabel.d.ts.map
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { keys } from "../translations/keys.js";
|
|
3
|
+
import { useTranslation as useTranslation$1 } from "../translations/useTranslation.js";
|
|
4
|
+
import { useRowLabel } from "@payloadcms/ui";
|
|
5
|
+
import { jsx } from "react/jsx-runtime";
|
|
6
|
+
//#region src/client/ConsentSourceRowLabel.tsx
|
|
7
|
+
/**
|
|
8
|
+
* Row header for a consent source array row: shows the source `name` (e.g. "Privacy Policy") instead
|
|
9
|
+
* of Payload's default "Consent source NN". Falls back to the singular label + number while unnamed.
|
|
10
|
+
*/
|
|
11
|
+
const ConsentSourceRowLabel = () => {
|
|
12
|
+
const { data, rowNumber } = useRowLabel();
|
|
13
|
+
const { t } = useTranslation$1();
|
|
14
|
+
const name = typeof data?.name === "string" && data.name.trim().length > 0 ? data.name.trim() : "";
|
|
15
|
+
const number = String((rowNumber ?? 0) + 1).padStart(2, "0");
|
|
16
|
+
return /* @__PURE__ */ jsx("span", { children: name || `${t(keys.consentSourceSingular)} ${number}` });
|
|
17
|
+
};
|
|
18
|
+
//#endregion
|
|
19
|
+
export { ConsentSourceRowLabel };
|
|
20
|
+
|
|
21
|
+
//# sourceMappingURL=ConsentSourceRowLabel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ConsentSourceRowLabel.js","names":["useTranslation"],"sources":["../../src/client/ConsentSourceRowLabel.tsx"],"sourcesContent":["'use client'\n\nimport { useRowLabel } from '@payloadcms/ui'\nimport { keys } from '../translations/keys'\nimport { useTranslation } from '../translations/useTranslation'\n\ntype RowData = { name?: unknown }\n\n/**\n * Row header for a consent source array row: shows the source `name` (e.g. \"Privacy Policy\") instead\n * of Payload's default \"Consent source NN\". Falls back to the singular label + number while unnamed.\n */\nexport const ConsentSourceRowLabel = () => {\n\tconst { data, rowNumber } = useRowLabel<RowData>()\n\tconst { t } = useTranslation()\n\tconst name = typeof data?.name === 'string' && data.name.trim().length > 0 ? data.name.trim() : ''\n\tconst number = String((rowNumber ?? 0) + 1).padStart(2, '0')\n\treturn <span>{name || `${t(keys.consentSourceSingular)} ${number}`}</span>\n}\n"],"mappings":";;;;;;;;;;AAYA,MAAa,8BAA8B;CAC1C,MAAM,EAAE,MAAM,cAAc,YAAqB;CACjD,MAAM,EAAE,MAAMA,iBAAe;CAC7B,MAAM,OAAO,OAAO,MAAM,SAAS,YAAY,KAAK,KAAK,KAAK,EAAE,SAAS,IAAI,KAAK,KAAK,KAAK,IAAI;CAChG,MAAM,SAAS,QAAQ,aAAa,KAAK,CAAC,EAAE,SAAS,GAAG,GAAG;CAC3D,OAAO,oBAAC,QAAD,EAAA,UAAO,QAAQ,GAAG,EAAE,KAAK,qBAAqB,EAAE,GAAG,SAAe,CAAA;AAC1E"}
|