@10x-media/form-builder 0.1.0-beta.11 → 0.1.0-beta.13

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.
Files changed (151) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/dist/aggregation/resolveResultsRequest.d.ts +6 -0
  3. package/dist/aggregation/resolveResultsRequest.js +32 -3
  4. package/dist/aggregation/resolveResultsRequest.js.map +1 -1
  5. package/dist/calc/computeCalcFields.d.ts +5 -3
  6. package/dist/calc/computeCalcFields.js +4 -3
  7. package/dist/calc/computeCalcFields.js.map +1 -1
  8. package/dist/calc/evaluate.d.ts +26 -3
  9. package/dist/calc/evaluate.js +33 -11
  10. package/dist/calc/evaluate.js.map +1 -1
  11. package/dist/calc/formatCalc.d.ts +11 -0
  12. package/dist/calc/formatCalc.js +35 -0
  13. package/dist/calc/formatCalc.js.map +1 -0
  14. package/dist/calc/formatCalcValue.d.ts +17 -0
  15. package/dist/calc/formatCalcValue.js +17 -0
  16. package/dist/calc/formatCalcValue.js.map +1 -0
  17. package/dist/calc/normalizeCalc.d.ts +17 -3
  18. package/dist/calc/normalizeCalc.js +39 -17
  19. package/dist/calc/normalizeCalc.js.map +1 -1
  20. package/dist/calc/registry.d.ts +43 -0
  21. package/dist/calc/registry.js +27 -0
  22. package/dist/calc/registry.js.map +1 -0
  23. package/dist/calc/resolveCalcContext.d.ts +36 -0
  24. package/dist/calc/resolveCalcContext.js +87 -0
  25. package/dist/calc/resolveCalcContext.js.map +1 -0
  26. package/dist/calc/types.d.ts +18 -3
  27. package/dist/calc/types.js +2 -1
  28. package/dist/calc/types.js.map +1 -1
  29. package/dist/client/CalcExpressionBuilder.d.ts +20 -0
  30. package/dist/client/CalcExpressionBuilder.js +890 -0
  31. package/dist/client/CalcExpressionBuilder.js.map +1 -0
  32. package/dist/client/admin.css +282 -0
  33. package/dist/collections/formSubmissions.js +7 -9
  34. package/dist/collections/formSubmissions.js.map +1 -1
  35. package/dist/collections/forms.js +59 -34
  36. package/dist/collections/forms.js.map +1 -1
  37. package/dist/collections/formsEndpoints.js +4 -2
  38. package/dist/collections/formsEndpoints.js.map +1 -1
  39. package/dist/collections/settingsFields.d.ts +31 -0
  40. package/dist/collections/settingsFields.js +45 -0
  41. package/dist/collections/settingsFields.js.map +1 -0
  42. package/dist/exports/client.d.ts +2 -1
  43. package/dist/exports/client.js +2 -1
  44. package/dist/exports/react.d.ts +7 -3
  45. package/dist/exports/react.js +6 -2
  46. package/dist/exports/rsc.js +1 -1
  47. package/dist/exports/types.d.ts +1 -1
  48. package/dist/fields/buildFieldBlocks.js +2 -1
  49. package/dist/fields/buildFieldBlocks.js.map +1 -1
  50. package/dist/fields/builtin/calculation.d.ts +17 -0
  51. package/dist/fields/builtin/calculation.js +170 -115
  52. package/dist/fields/builtin/calculation.js.map +1 -1
  53. package/dist/fields/builtin/checkbox.js +15 -0
  54. package/dist/fields/builtin/checkbox.js.map +1 -1
  55. package/dist/fields/builtin/email.js +7 -0
  56. package/dist/fields/builtin/email.js.map +1 -1
  57. package/dist/fields/builtin/index.d.ts +6 -2
  58. package/dist/fields/builtin/index.js +9 -4
  59. package/dist/fields/builtin/index.js.map +1 -1
  60. package/dist/fields/builtin/select.js +20 -1
  61. package/dist/fields/builtin/select.js.map +1 -1
  62. package/dist/fields/builtin/text.js +7 -0
  63. package/dist/fields/builtin/text.js.map +1 -1
  64. package/dist/fields/instanceOptions.js +1 -1
  65. package/dist/fields/instanceOptions.js.map +1 -1
  66. package/dist/fields/sharedConfig.js +15 -11
  67. package/dist/fields/sharedConfig.js.map +1 -1
  68. package/dist/fields/types.d.ts +8 -2
  69. package/dist/form/toFormDocument.d.ts +7 -0
  70. package/dist/form/toFormDocument.js +2 -1
  71. package/dist/form/toFormDocument.js.map +1 -1
  72. package/dist/form/types.d.ts +7 -0
  73. package/dist/index.d.ts +12 -4
  74. package/dist/index.js +35 -8
  75. package/dist/index.js.map +1 -1
  76. package/dist/options.d.ts +35 -0
  77. package/dist/plugin/registerCollections.js +29 -19
  78. package/dist/plugin/registerCollections.js.map +1 -1
  79. package/dist/poll/closeJob.d.ts +4 -3
  80. package/dist/poll/closeJob.js +6 -4
  81. package/dist/poll/closeJob.js.map +1 -1
  82. package/dist/poll/pollTypeRegistry.js +1 -1
  83. package/dist/poll/resolvePollCloseRequest.js +2 -1
  84. package/dist/poll/resolvePollCloseRequest.js.map +1 -1
  85. package/dist/poll/resolvePollOutcome.d.ts +6 -0
  86. package/dist/poll/resolvePollOutcome.js +17 -3
  87. package/dist/poll/resolvePollOutcome.js.map +1 -1
  88. package/dist/poll/votes/aggregateFromVotes.d.ts +27 -0
  89. package/dist/poll/votes/aggregateFromVotes.js +53 -0
  90. package/dist/poll/votes/aggregateFromVotes.js.map +1 -0
  91. package/dist/poll/votes/bumpPollVote.js +88 -0
  92. package/dist/poll/votes/bumpPollVote.js.map +1 -0
  93. package/dist/poll/votes/recountPollVotes.d.ts +20 -0
  94. package/dist/poll/votes/recountPollVotes.js +63 -0
  95. package/dist/poll/votes/recountPollVotes.js.map +1 -0
  96. package/dist/poll/votes/voteTallyHook.js +58 -0
  97. package/dist/poll/votes/voteTallyHook.js.map +1 -0
  98. package/dist/poll/votes/votesCollection.d.ts +19 -0
  99. package/dist/poll/votes/votesCollection.js +89 -0
  100. package/dist/poll/votes/votesCollection.js.map +1 -0
  101. package/dist/react/Form.d.ts +7 -0
  102. package/dist/react/Form.js +20 -3
  103. package/dist/react/Form.js.map +1 -1
  104. package/dist/react/FormContext.d.ts +8 -1
  105. package/dist/react/FormContext.js.map +1 -1
  106. package/dist/react/primitives/Checkbox.d.ts +4 -2
  107. package/dist/react/primitives/Checkbox.js +3 -2
  108. package/dist/react/primitives/Checkbox.js.map +1 -1
  109. package/dist/react/primitives/ChoiceGroup.d.ts +40 -0
  110. package/dist/react/primitives/ChoiceGroup.js +33 -0
  111. package/dist/react/primitives/ChoiceGroup.js.map +1 -0
  112. package/dist/react/primitives/FieldShell.d.ts +11 -1
  113. package/dist/react/primitives/FieldShell.js +43 -33
  114. package/dist/react/primitives/FieldShell.js.map +1 -1
  115. package/dist/react/primitives/Input.d.ts +3 -1
  116. package/dist/react/primitives/Input.js +2 -1
  117. package/dist/react/primitives/Input.js.map +1 -1
  118. package/dist/react/renderers/calculation.js +6 -1
  119. package/dist/react/renderers/calculation.js.map +1 -1
  120. package/dist/react/renderers/checkbox.js +2 -1
  121. package/dist/react/renderers/checkbox.js.map +1 -1
  122. package/dist/react/renderers/email.js +3 -1
  123. package/dist/react/renderers/email.js.map +1 -1
  124. package/dist/react/renderers/select.js +20 -2
  125. package/dist/react/renderers/select.js.map +1 -1
  126. package/dist/react/renderers/text.js +3 -1
  127. package/dist/react/renderers/text.js.map +1 -1
  128. package/dist/react/useCalcValues.d.ts +10 -0
  129. package/dist/react/useCalcValues.js +13 -0
  130. package/dist/react/useCalcValues.js.map +1 -0
  131. package/dist/recall/resolver.js +1 -1
  132. package/dist/recall/resolver.js.map +1 -1
  133. package/dist/submissions/formIdOf.js +13 -0
  134. package/dist/submissions/formIdOf.js.map +1 -0
  135. package/dist/submissions/runSubmission.js +3 -3
  136. package/dist/submissions/runSubmission.js.map +1 -1
  137. package/dist/submissions/validateSubmission.js +26 -2
  138. package/dist/submissions/validateSubmission.js.map +1 -1
  139. package/dist/translations/de.js +58 -3
  140. package/dist/translations/de.js.map +1 -1
  141. package/dist/translations/en.js +58 -3
  142. package/dist/translations/en.js.map +1 -1
  143. package/dist/translations/keys.d.ts +56 -1
  144. package/dist/translations/keys.js +56 -1
  145. package/dist/translations/keys.js.map +1 -1
  146. package/dist/validation/builtin/index.js +2 -0
  147. package/dist/validation/builtin/index.js.map +1 -1
  148. package/dist/validation/builtin/integer.js +15 -0
  149. package/dist/validation/builtin/integer.js.map +1 -0
  150. package/package.json +10 -4
  151. package/styles/form-builder.css +84 -0
@@ -1,3 +1,4 @@
1
+ import { CalcExpression } from "../calc/types.js";
1
2
  import { FormFieldInstance, SubmissionValue } from "../submissions/types.js";
2
3
  import { de } from "../translations/de.js";
3
4
  import { en } from "../translations/en.js";
@@ -7,9 +8,10 @@ import { BodyConverter, BodyConverterArgs, BodyRender, sanitizeUrl } from "../ac
7
8
  import { BodyContext, serializeBody } from "../actions/body/serializeBody.js";
8
9
  import { textOfBody } from "../actions/body/textOfBody.js";
9
10
  import { AggregationBucket, FieldAggregation } from "../aggregation/types.js";
10
- import { CalcExpression } from "../calc/types.js";
11
+ import { CalcResolved, evaluateCalc } from "../calc/evaluate.js";
11
12
  import { computeCalcFields } from "../calc/computeCalcFields.js";
12
- import { evaluateCalc } from "../calc/evaluate.js";
13
+ import { formatCalc } from "../calc/formatCalc.js";
14
+ import { CalcDisplayConfig, formatCalcValue } from "../calc/formatCalcValue.js";
13
15
  import { evaluateCondition } from "../conditions/evaluate.js";
14
16
  import { ConsentStatement, ConsentStatements } from "../consent/resolveConsentStatements.js";
15
17
  import { COUNTRIES, US_STATES } from "../fields/data/regions.js";
@@ -47,12 +49,14 @@ import { UseDismissOptions, useDismiss } from "../react/presentation/useDismiss.
47
49
  import { useFocusTrap } from "../react/presentation/useFocusTrap.js";
48
50
  import { useScrollLock } from "../react/presentation/useScrollLock.js";
49
51
  import { Checkbox, CheckboxProps } from "../react/primitives/Checkbox.js";
52
+ import { ChoiceGroup, ChoiceGroupProps, ChoiceOption } from "../react/primitives/ChoiceGroup.js";
50
53
  import { FieldShell, FieldShellProps } from "../react/primitives/FieldShell.js";
51
54
  import { Input, InputProps } from "../react/primitives/Input.js";
52
55
  import { Select, SelectOption, SelectProps } from "../react/primitives/Select.js";
53
56
  import { Textarea, TextareaProps } from "../react/primitives/Textarea.js";
54
57
  import { defaultRenderers } from "../react/renderers/index.js";
55
58
  import { UploadFileInput, UploadFileResult, uploadFile } from "../react/uploadFile.js";
59
+ import { useCalcValues } from "../react/useCalcValues.js";
56
60
  import { UseFieldResult, useField } from "../react/useField.js";
57
61
  import { useFormState } from "../react/useFormState.js";
58
62
  import { useFormStep } from "../react/useFormStep.js";
@@ -60,4 +64,4 @@ import { interpolate } from "../recall/interpolate.js";
60
64
  import { CAPTCHA_TOKEN_KEY, DEFAULT_HONEYPOT_FIELD } from "../spam/constants.js";
61
65
  import { makeTranslate } from "../translations/makeTranslate.js";
62
66
  import { formatBytes } from "../uploads/formatBytes.js";
63
- export { type AggregationBucket, type BackButtonRenderProps, Backdrop, type BackdropProps, type BodyContext, type BodyConverter, type BodyConverterArgs, type BodyRender, CAPTCHA_TOKEN_KEY, COUNTRIES, type CalcExpression, type CaptchaWidgetHandle, Checkbox, type CheckboxProps, type ConsentStatement, type ConsentStatements, DEFAULT_HONEYPOT_FIELD, DialogSurface, type DialogSurfaceProps, type FetchResultsInput, type FetchResultsResult, type FieldAggregation, type FieldErrors, type FieldRenderer, type FieldRendererProps, FieldShell, type FieldShellProps, type FieldWidth, Form, type FormAction, type FormButtonSettings, type FormContextValue, type FormControlLabels, FormControls, type FormControlsProps, type FormDocument, type FormFieldInstance, FormFields, type FormFieldsProps, FormLayout, type FormLayoutProps, type FormPollSettings, type FormPresentation, type FormProps, type FormResponseSettings, FormResults, type FormResultsProps, type FormState, type FormStepInfo, FormSteps, type FormStepsProps, type FormSuccessResponse, type FormSuccessResult, HCAPTCHA_SCRIPT_URL, HcaptchaCaptcha, type HcaptchaCaptchaProps, Honeypot, type HoneypotProps, Input, type InputProps, type NextButtonRenderProps, Poll, type PollProps, type PrefillOptions, type PresentationOption, type PresentationRegistry, type PresentationWrapperProps, type PresentationsConfig, RECAPTCHA_SCRIPT_URL, type RecallResolver, RecaptchaCaptcha, type RecaptchaCaptchaHandle, type RecaptchaCaptchaProps, type RendererOption, type RendererRegistry, type RendererTranslate, type RenderersConfig, Select, type SelectOption, type SelectProps, type SubmissionValue, type SubmitButtonRenderProps, type SubmitFormResult, type SubmitHandler, TURNSTILE_SCRIPT_URL, Textarea, type TextareaProps, type ToFormDocumentOptions, type TranslationBundle, TurnstileCaptcha, type TurnstileCaptchaProps, US_STATES, type UploadFileInput, type UploadFileResult, type UseDismissOptions, type UseFieldResult, buildRecallResolver, bundles, clientRuntimeKeys, cn, computeCalcFields, de, defaultPresentations, defaultRenderers, defineFieldRenderer, en, evaluateCalc, evaluateCondition, fetchFormResults, fieldKey, firstStepId, formatBytes, interpolate, isTerminalStepId, makeTranslate, resolveNextStepId, resolvePresentations, resolveRenderers, sanitizeUrl, serializeBody, stepFieldNames, submitForm, textOfBody, toFormDocument, uploadFile, useDismiss, useField, useFocusTrap, useFormContext, useFormState, useFormStep, useScrollLock, valuesFromSearchParams, widthProps };
67
+ export { type AggregationBucket, type BackButtonRenderProps, Backdrop, type BackdropProps, type BodyContext, type BodyConverter, type BodyConverterArgs, type BodyRender, CAPTCHA_TOKEN_KEY, COUNTRIES, type CalcDisplayConfig, type CalcExpression, type CalcResolved, type CaptchaWidgetHandle, Checkbox, type CheckboxProps, ChoiceGroup, type ChoiceGroupProps, type ChoiceOption, type ConsentStatement, type ConsentStatements, DEFAULT_HONEYPOT_FIELD, DialogSurface, type DialogSurfaceProps, type FetchResultsInput, type FetchResultsResult, type FieldAggregation, type FieldErrors, type FieldRenderer, type FieldRendererProps, FieldShell, type FieldShellProps, type FieldWidth, Form, type FormAction, type FormButtonSettings, type FormContextValue, type FormControlLabels, FormControls, type FormControlsProps, type FormDocument, type FormFieldInstance, FormFields, type FormFieldsProps, FormLayout, type FormLayoutProps, type FormPollSettings, type FormPresentation, type FormProps, type FormResponseSettings, FormResults, type FormResultsProps, type FormState, type FormStepInfo, FormSteps, type FormStepsProps, type FormSuccessResponse, type FormSuccessResult, HCAPTCHA_SCRIPT_URL, HcaptchaCaptcha, type HcaptchaCaptchaProps, Honeypot, type HoneypotProps, Input, type InputProps, type NextButtonRenderProps, Poll, type PollProps, type PrefillOptions, type PresentationOption, type PresentationRegistry, type PresentationWrapperProps, type PresentationsConfig, RECAPTCHA_SCRIPT_URL, type RecallResolver, RecaptchaCaptcha, type RecaptchaCaptchaHandle, type RecaptchaCaptchaProps, type RendererOption, type RendererRegistry, type RendererTranslate, type RenderersConfig, Select, type SelectOption, type SelectProps, type SubmissionValue, type SubmitButtonRenderProps, type SubmitFormResult, type SubmitHandler, TURNSTILE_SCRIPT_URL, Textarea, type TextareaProps, type ToFormDocumentOptions, type TranslationBundle, TurnstileCaptcha, type TurnstileCaptchaProps, US_STATES, type UploadFileInput, type UploadFileResult, type UseDismissOptions, type UseFieldResult, buildRecallResolver, bundles, clientRuntimeKeys, cn, computeCalcFields, de, defaultPresentations, defaultRenderers, defineFieldRenderer, en, evaluateCalc, evaluateCondition, fetchFormResults, fieldKey, firstStepId, formatBytes, formatCalc, formatCalcValue, interpolate, isTerminalStepId, makeTranslate, resolveNextStepId, resolvePresentations, resolveRenderers, sanitizeUrl, serializeBody, stepFieldNames, submitForm, textOfBody, toFormDocument, uploadFile, useCalcValues, useDismiss, useField, useFocusTrap, useFormContext, useFormState, useFormStep, useScrollLock, valuesFromSearchParams, widthProps };
@@ -2,15 +2,17 @@
2
2
  import { interpolate } from "../recall/interpolate.js";
3
3
  import { sanitizeUrl } from "../actions/body/converters.js";
4
4
  import { serializeBody } from "../actions/body/serializeBody.js";
5
- import { CAPTCHA_TOKEN_KEY, DEFAULT_HONEYPOT_FIELD } from "../spam/constants.js";
5
+ import { formatCalcValue } from "../calc/formatCalcValue.js";
6
6
  import { fieldKey } from "../fields/fieldKey.js";
7
7
  import { evaluateCalc } from "../calc/evaluate.js";
8
8
  import { computeCalcFields } from "../calc/computeCalcFields.js";
9
+ import { CAPTCHA_TOKEN_KEY, DEFAULT_HONEYPOT_FIELD } from "../spam/constants.js";
9
10
  import { evaluateCondition } from "../conditions/evaluate.js";
10
11
  import { textOfBody } from "../actions/body/textOfBody.js";
11
12
  import { de } from "../translations/de.js";
12
13
  import { en } from "../translations/en.js";
13
14
  import { bundles } from "../translations/index.js";
15
+ import { formatCalc } from "../calc/formatCalc.js";
14
16
  import { COUNTRIES, US_STATES } from "../fields/data/regions.js";
15
17
  import { toFormDocument } from "../form/toFormDocument.js";
16
18
  import { valuesFromSearchParams } from "../prefill/valuesFromSearchParams.js";
@@ -42,6 +44,7 @@ import { Checkbox } from "../react/primitives/Checkbox.js";
42
44
  import { Input } from "../react/primitives/Input.js";
43
45
  import { uploadFile } from "../react/uploadFile.js";
44
46
  import { Select } from "../react/primitives/Select.js";
47
+ import { ChoiceGroup } from "../react/primitives/ChoiceGroup.js";
45
48
  import { Textarea } from "../react/primitives/Textarea.js";
46
49
  import { defaultRenderers } from "../react/renderers/index.js";
47
50
  import { submitForm } from "../react/submitForm.js";
@@ -50,7 +53,8 @@ import { FormResults } from "../react/FormResults.js";
50
53
  import { FormSteps } from "../react/FormSteps.js";
51
54
  import { fetchFormResults } from "../react/fetchResults.js";
52
55
  import { Poll } from "../react/Poll.js";
56
+ import { useCalcValues } from "../react/useCalcValues.js";
53
57
  import { useFormState } from "../react/useFormState.js";
54
58
  import { useFormStep } from "../react/useFormStep.js";
55
59
  import { clientRuntimeKeys } from "../translations/clientRuntimeKeys.js";
56
- export { Backdrop, CAPTCHA_TOKEN_KEY, COUNTRIES, Checkbox, DEFAULT_HONEYPOT_FIELD, DialogSurface, FieldShell, Form, FormControls, FormFields, FormLayout, FormResults, FormSteps, HCAPTCHA_SCRIPT_URL, HcaptchaCaptcha, Honeypot, Input, Poll, RECAPTCHA_SCRIPT_URL, RecaptchaCaptcha, Select, TURNSTILE_SCRIPT_URL, Textarea, TurnstileCaptcha, US_STATES, buildRecallResolver, bundles, clientRuntimeKeys, cn, computeCalcFields, de, defaultPresentations, defaultRenderers, defineFieldRenderer, en, evaluateCalc, evaluateCondition, fetchFormResults, fieldKey, firstStepId, formatBytes, interpolate, isTerminalStepId, makeTranslate, resolveNextStepId, resolvePresentations, resolveRenderers, sanitizeUrl, serializeBody, stepFieldNames, submitForm, textOfBody, toFormDocument, uploadFile, useDismiss, useField, useFocusTrap, useFormContext, useFormState, useFormStep, useScrollLock, valuesFromSearchParams, widthProps };
60
+ export { Backdrop, CAPTCHA_TOKEN_KEY, COUNTRIES, Checkbox, ChoiceGroup, DEFAULT_HONEYPOT_FIELD, DialogSurface, FieldShell, Form, FormControls, FormFields, FormLayout, FormResults, FormSteps, HCAPTCHA_SCRIPT_URL, HcaptchaCaptcha, Honeypot, Input, Poll, RECAPTCHA_SCRIPT_URL, RecaptchaCaptcha, Select, TURNSTILE_SCRIPT_URL, Textarea, TurnstileCaptcha, US_STATES, buildRecallResolver, bundles, clientRuntimeKeys, cn, computeCalcFields, de, defaultPresentations, defaultRenderers, defineFieldRenderer, en, evaluateCalc, evaluateCondition, fetchFormResults, fieldKey, firstStepId, formatBytes, formatCalc, formatCalcValue, interpolate, isTerminalStepId, makeTranslate, resolveNextStepId, resolvePresentations, resolveRenderers, sanitizeUrl, serializeBody, stepFieldNames, submitForm, textOfBody, toFormDocument, uploadFile, useCalcValues, useDismiss, useField, useFocusTrap, useFormContext, useFormState, useFormStep, useScrollLock, valuesFromSearchParams, widthProps };
@@ -1,8 +1,8 @@
1
1
  import { resolveConsentStatements } from "../consent/resolveConsentStatements.js";
2
2
  import { isPollClosed } from "../form/pollState.js";
3
3
  import { resolvePollOptions } from "../poll/resolvePollOptions.js";
4
- import { resolvePollOutcome } from "../poll/resolvePollOutcome.js";
5
4
  import { resolveEffectivePollOptions } from "../poll/effectivePollOptions.js";
5
+ import { resolvePollOutcome } from "../poll/resolvePollOutcome.js";
6
6
  import { hasVotedCookie, votedCookieName } from "../submissions/votedCookie.js";
7
7
  import { signFormContext, verifyFormContext } from "../context/formContext.js";
8
8
  import { toFormDocument } from "../form/toFormDocument.js";
@@ -1,9 +1,9 @@
1
+ import { CalcExpression } from "../calc/types.js";
1
2
  import { FormFieldInstance, SubmissionDescriptor, SubmissionFieldError, SubmissionValue, SubmissionWidth } from "../submissions/types.js";
2
3
  import { FileFieldConfig, FileRef, FileRefError } from "../uploads/types.js";
3
4
  import { AnyFormFieldDefinition, FormFieldDefinition, FormFieldFormat, FormFieldValidate, FormFieldValueKind, OmittableSharedField } from "../fields/types.js";
4
5
  import { RichTextBodyOption } from "../actions/body/serializeBody.js";
5
6
  import { AggregationBucket, AggregationRow, FieldAggregation, FieldMeta, SubmissionStatusFilter } from "../aggregation/types.js";
6
- import { CalcExpression } from "../calc/types.js";
7
7
  import { ConsentSourceEntry, ConsentSourcePage, ConsentSourcesResolver } from "../consent/types.js";
8
8
  import { ConsentStatement, ConsentStatements, ResolveConsentStatementsArgs } from "../consent/resolveConsentStatements.js";
9
9
  import { FlowStep, FlowTransition, FormFlow } from "../flow/types.js";
@@ -58,7 +58,8 @@ const buildFieldBlocks = ({ registry, ruleRegistry, localize = true }) => {
58
58
  blocks: buildRuleBlocks(ruleRegistry, definition.type)
59
59
  },
60
60
  localize,
61
- omitShared: definition.omitShared
61
+ omitShared: definition.omitShared,
62
+ advancedConfig: definition.advancedConfig
62
63
  })]
63
64
  });
64
65
  }
@@ -1 +1 @@
1
- {"version":3,"file":"buildFieldBlocks.js","names":[],"sources":["../../src/fields/buildFieldBlocks.ts"],"sourcesContent":["import type { Block, Field, TabsField } from 'payload'\nimport { buildConditionTypeMap } from '../conditions/conditionType'\nimport { keys } from '../translations/keys'\nimport { labelFor } from '../translations/server'\nimport { buildRuleBlocks } from '../validation/buildRuleBlocks'\nimport type { ValidationRuleRegistry } from '../validation/registry'\nimport type { FieldTypeRegistry } from './registry'\nimport { fieldBlockTabs } from './sharedConfig'\n\nconst FIELD_BLOCK_LABEL_REF = '@10x-media/form-builder/client#FieldBlockLabel'\n\n/**\n * Replace Payload's default `blockName` row header (which reads \"Untitled\" until filled) with the\n * field's own `label`, keyed to the type label as fallback. See `FieldBlockLabel`.\n */\nconst blockLabelAdmin = (\n\ttypeLabelKey: string,\n\tref: string = FIELD_BLOCK_LABEL_REF\n): NonNullable<Block['admin']> => ({\n\tcomponents: { Label: { path: ref, clientProps: { typeLabelKey } } },\n})\n\n/** Whether `fields` contains a field named `name`, descending into presentational rows. */\nconst hasNameField = (fields: Field[]): boolean =>\n\tfields.some((f) => {\n\t\tif ('name' in f && f.name === 'name') {\n\t\t\treturn true\n\t\t}\n\t\treturn f.type === 'row' && hasNameField(f.fields)\n\t})\n\n/** The tab whose fields hold the shared basics and type config, found by the `name` field it carries. */\nconst fieldTabOf = (block: Block): Field[] | undefined => {\n\tconst tabsField = block.fields.find((f): f is TabsField => f.type === 'tabs')\n\treturn tabsField?.tabs.find((tab) => hasNameField(tab.fields))?.fields\n}\n\n/**\n * One add-field block per registered type: tabs holding shared config, type config, and\n * validations. Bare definitions (e.g. `message`) skip all of that: their block is the\n * definition's `config` alone, no name/shared basics/tabs. `localize` controls whether the\n * shared content fields carry `localized: true`; per-type config fields carry their own flag\n * from the registry definitions.\n */\ntype BuildFieldBlocksArgs = {\n\tregistry: FieldTypeRegistry\n\truleRegistry: ValidationRuleRegistry\n\tlocalize?: boolean\n}\n\nexport const buildFieldBlocks = ({\n\tregistry,\n\truleRegistry,\n\tlocalize = true,\n}: BuildFieldBlocksArgs): Block[] => {\n\tconst conditionTypes = buildConditionTypeMap(registry)\n\tconst blocks: Block[] = []\n\tconst bareSlugs = new Set<string>()\n\tfor (const definition of registry.values()) {\n\t\tconst typeConfig: Field[] = definition.config ?? []\n\n\t\tif (definition.bare === true) {\n\t\t\tbareSlugs.add(definition.type)\n\t\t\tblocks.push({\n\t\t\t\tslug: definition.type,\n\t\t\t\tlabels: { singular: labelFor(definition.label), plural: labelFor(definition.label) },\n\t\t\t\tadmin: blockLabelAdmin(definition.label, definition.blockLabel),\n\t\t\t\tfields: typeConfig,\n\t\t\t})\n\t\t\tcontinue\n\t\t}\n\n\t\tblocks.push({\n\t\t\tslug: definition.type,\n\t\t\tlabels: { singular: labelFor(definition.label), plural: labelFor(definition.label) },\n\t\t\tadmin: blockLabelAdmin(definition.label, definition.blockLabel),\n\t\t\tfields: [\n\t\t\t\tfieldBlockTabs({\n\t\t\t\t\tconditionTypes,\n\t\t\t\t\ttypeConfig,\n\t\t\t\t\tvalidations: {\n\t\t\t\t\t\tname: 'validations',\n\t\t\t\t\t\ttype: 'blocks',\n\t\t\t\t\t\tlabel: labelFor(keys.validationsLabel),\n\t\t\t\t\t\tblocks: buildRuleBlocks(ruleRegistry, definition.type),\n\t\t\t\t\t},\n\t\t\t\t\tlocalize,\n\t\t\t\t\tomitShared: definition.omitShared,\n\t\t\t\t}),\n\t\t\t],\n\t\t})\n\t}\n\n\t// Second pass: inject subFields into the repeater block using all non-repeater blocks.\n\t// Done after the main loop so every sibling block is already built.\n\t// Repeater-in-repeater is not supported in v1; the repeater block is excluded from subFields.\n\t// Bare blocks are excluded too: repeater row plumbing (values, composite error paths) is name-keyed.\n\tconst repeaterBlock = blocks.find((b) => b.slug === 'repeater')\n\tif (repeaterBlock) {\n\t\tconst subFieldsField: Field = {\n\t\t\tname: 'subFields',\n\t\t\ttype: 'blocks',\n\t\t\tlabel: labelFor(keys.configSubFields),\n\t\t\tblocks: blocks.filter((b) => b.slug !== 'repeater' && !bareSlugs.has(b.slug)),\n\t\t}\n\t\tconst fieldTabFields = fieldTabOf(repeaterBlock)\n\t\t;(fieldTabFields ?? (repeaterBlock.fields as Field[])).push(subFieldsField)\n\t}\n\n\treturn blocks\n}\n"],"mappings":";;;;;;AASA,MAAM,wBAAwB;;;;;AAM9B,MAAM,mBACL,cACA,MAAc,2BACoB,EAClC,YAAY,EAAE,OAAO;CAAE,MAAM;CAAK,aAAa,EAAE,aAAa;AAAE,EAAE,EACnE;;AAGA,MAAM,gBAAgB,WACrB,OAAO,MAAM,MAAM;CAClB,IAAI,UAAU,KAAK,EAAE,SAAS,QAC7B,OAAO;CAER,OAAO,EAAE,SAAS,SAAS,aAAa,EAAE,MAAM;AACjD,CAAC;;AAGF,MAAM,cAAc,UAAsC;CAEzD,OADkB,MAAM,OAAO,MAAM,MAAsB,EAAE,SAAS,MACvD,GAAG,KAAK,MAAM,QAAQ,aAAa,IAAI,MAAM,CAAC,GAAG;AACjE;AAeA,MAAa,oBAAoB,EAChC,UACA,cACA,WAAW,WACyB;CACpC,MAAM,iBAAiB,sBAAsB,QAAQ;CACrD,MAAM,SAAkB,CAAC;CACzB,MAAM,4BAAY,IAAI,IAAY;CAClC,KAAK,MAAM,cAAc,SAAS,OAAO,GAAG;EAC3C,MAAM,aAAsB,WAAW,UAAU,CAAC;EAElD,IAAI,WAAW,SAAS,MAAM;GAC7B,UAAU,IAAI,WAAW,IAAI;GAC7B,OAAO,KAAK;IACX,MAAM,WAAW;IACjB,QAAQ;KAAE,UAAU,SAAS,WAAW,KAAK;KAAG,QAAQ,SAAS,WAAW,KAAK;IAAE;IACnF,OAAO,gBAAgB,WAAW,OAAO,WAAW,UAAU;IAC9D,QAAQ;GACT,CAAC;GACD;EACD;EAEA,OAAO,KAAK;GACX,MAAM,WAAW;GACjB,QAAQ;IAAE,UAAU,SAAS,WAAW,KAAK;IAAG,QAAQ,SAAS,WAAW,KAAK;GAAE;GACnF,OAAO,gBAAgB,WAAW,OAAO,WAAW,UAAU;GAC9D,QAAQ,CACP,eAAe;IACd;IACA;IACA,aAAa;KACZ,MAAM;KACN,MAAM;KACN,OAAO,SAAS,KAAK,gBAAgB;KACrC,QAAQ,gBAAgB,cAAc,WAAW,IAAI;IACtD;IACA;IACA,YAAY,WAAW;GACxB,CAAC,CACF;EACD,CAAC;CACF;CAMA,MAAM,gBAAgB,OAAO,MAAM,MAAM,EAAE,SAAS,UAAU;CAC9D,IAAI,eAAe;EAClB,MAAM,iBAAwB;GAC7B,MAAM;GACN,MAAM;GACN,OAAO,SAAS,KAAK,eAAe;GACpC,QAAQ,OAAO,QAAQ,MAAM,EAAE,SAAS,cAAc,CAAC,UAAU,IAAI,EAAE,IAAI,CAAC;EAC7E;EAEC,CADsB,WAAW,aACnB,KAAM,cAAc,QAAoB,KAAK,cAAc;CAC3E;CAEA,OAAO;AACR"}
1
+ {"version":3,"file":"buildFieldBlocks.js","names":[],"sources":["../../src/fields/buildFieldBlocks.ts"],"sourcesContent":["import type { Block, Field, TabsField } from 'payload'\nimport { buildConditionTypeMap } from '../conditions/conditionType'\nimport { keys } from '../translations/keys'\nimport { labelFor } from '../translations/server'\nimport { buildRuleBlocks } from '../validation/buildRuleBlocks'\nimport type { ValidationRuleRegistry } from '../validation/registry'\nimport type { FieldTypeRegistry } from './registry'\nimport { fieldBlockTabs } from './sharedConfig'\n\nconst FIELD_BLOCK_LABEL_REF = '@10x-media/form-builder/client#FieldBlockLabel'\n\n/**\n * Replace Payload's default `blockName` row header (which reads \"Untitled\" until filled) with the\n * field's own `label`, keyed to the type label as fallback. See `FieldBlockLabel`.\n */\nconst blockLabelAdmin = (\n\ttypeLabelKey: string,\n\tref: string = FIELD_BLOCK_LABEL_REF\n): NonNullable<Block['admin']> => ({\n\tcomponents: { Label: { path: ref, clientProps: { typeLabelKey } } },\n})\n\n/** Whether `fields` contains a field named `name`, descending into presentational rows. */\nconst hasNameField = (fields: Field[]): boolean =>\n\tfields.some((f) => {\n\t\tif ('name' in f && f.name === 'name') {\n\t\t\treturn true\n\t\t}\n\t\treturn f.type === 'row' && hasNameField(f.fields)\n\t})\n\n/** The tab whose fields hold the shared basics and type config, found by the `name` field it carries. */\nconst fieldTabOf = (block: Block): Field[] | undefined => {\n\tconst tabsField = block.fields.find((f): f is TabsField => f.type === 'tabs')\n\treturn tabsField?.tabs.find((tab) => hasNameField(tab.fields))?.fields\n}\n\n/**\n * One add-field block per registered type: tabs holding shared config, type config, and\n * validations. Bare definitions (e.g. `message`) skip all of that: their block is the\n * definition's `config` alone, no name/shared basics/tabs. `localize` controls whether the\n * shared content fields carry `localized: true`; per-type config fields carry their own flag\n * from the registry definitions.\n */\ntype BuildFieldBlocksArgs = {\n\tregistry: FieldTypeRegistry\n\truleRegistry: ValidationRuleRegistry\n\tlocalize?: boolean\n}\n\nexport const buildFieldBlocks = ({\n\tregistry,\n\truleRegistry,\n\tlocalize = true,\n}: BuildFieldBlocksArgs): Block[] => {\n\tconst conditionTypes = buildConditionTypeMap(registry)\n\tconst blocks: Block[] = []\n\tconst bareSlugs = new Set<string>()\n\tfor (const definition of registry.values()) {\n\t\tconst typeConfig: Field[] = definition.config ?? []\n\n\t\tif (definition.bare === true) {\n\t\t\tbareSlugs.add(definition.type)\n\t\t\tblocks.push({\n\t\t\t\tslug: definition.type,\n\t\t\t\tlabels: { singular: labelFor(definition.label), plural: labelFor(definition.label) },\n\t\t\t\tadmin: blockLabelAdmin(definition.label, definition.blockLabel),\n\t\t\t\tfields: typeConfig,\n\t\t\t})\n\t\t\tcontinue\n\t\t}\n\n\t\tblocks.push({\n\t\t\tslug: definition.type,\n\t\t\tlabels: { singular: labelFor(definition.label), plural: labelFor(definition.label) },\n\t\t\tadmin: blockLabelAdmin(definition.label, definition.blockLabel),\n\t\t\tfields: [\n\t\t\t\tfieldBlockTabs({\n\t\t\t\t\tconditionTypes,\n\t\t\t\t\ttypeConfig,\n\t\t\t\t\tvalidations: {\n\t\t\t\t\t\tname: 'validations',\n\t\t\t\t\t\ttype: 'blocks',\n\t\t\t\t\t\tlabel: labelFor(keys.validationsLabel),\n\t\t\t\t\t\tblocks: buildRuleBlocks(ruleRegistry, definition.type),\n\t\t\t\t\t},\n\t\t\t\t\tlocalize,\n\t\t\t\t\tomitShared: definition.omitShared,\n\t\t\t\t\tadvancedConfig: definition.advancedConfig,\n\t\t\t\t}),\n\t\t\t],\n\t\t})\n\t}\n\n\t// Second pass: inject subFields into the repeater block using all non-repeater blocks.\n\t// Done after the main loop so every sibling block is already built.\n\t// Repeater-in-repeater is not supported in v1; the repeater block is excluded from subFields.\n\t// Bare blocks are excluded too: repeater row plumbing (values, composite error paths) is name-keyed.\n\tconst repeaterBlock = blocks.find((b) => b.slug === 'repeater')\n\tif (repeaterBlock) {\n\t\tconst subFieldsField: Field = {\n\t\t\tname: 'subFields',\n\t\t\ttype: 'blocks',\n\t\t\tlabel: labelFor(keys.configSubFields),\n\t\t\tblocks: blocks.filter((b) => b.slug !== 'repeater' && !bareSlugs.has(b.slug)),\n\t\t}\n\t\tconst fieldTabFields = fieldTabOf(repeaterBlock)\n\t\t;(fieldTabFields ?? (repeaterBlock.fields as Field[])).push(subFieldsField)\n\t}\n\n\treturn blocks\n}\n"],"mappings":";;;;;;AASA,MAAM,wBAAwB;;;;;AAM9B,MAAM,mBACL,cACA,MAAc,2BACoB,EAClC,YAAY,EAAE,OAAO;CAAE,MAAM;CAAK,aAAa,EAAE,aAAa;AAAE,EAAE,EACnE;;AAGA,MAAM,gBAAgB,WACrB,OAAO,MAAM,MAAM;CAClB,IAAI,UAAU,KAAK,EAAE,SAAS,QAC7B,OAAO;CAER,OAAO,EAAE,SAAS,SAAS,aAAa,EAAE,MAAM;AACjD,CAAC;;AAGF,MAAM,cAAc,UAAsC;CAEzD,OADkB,MAAM,OAAO,MAAM,MAAsB,EAAE,SAAS,MACvD,GAAG,KAAK,MAAM,QAAQ,aAAa,IAAI,MAAM,CAAC,GAAG;AACjE;AAeA,MAAa,oBAAoB,EAChC,UACA,cACA,WAAW,WACyB;CACpC,MAAM,iBAAiB,sBAAsB,QAAQ;CACrD,MAAM,SAAkB,CAAC;CACzB,MAAM,4BAAY,IAAI,IAAY;CAClC,KAAK,MAAM,cAAc,SAAS,OAAO,GAAG;EAC3C,MAAM,aAAsB,WAAW,UAAU,CAAC;EAElD,IAAI,WAAW,SAAS,MAAM;GAC7B,UAAU,IAAI,WAAW,IAAI;GAC7B,OAAO,KAAK;IACX,MAAM,WAAW;IACjB,QAAQ;KAAE,UAAU,SAAS,WAAW,KAAK;KAAG,QAAQ,SAAS,WAAW,KAAK;IAAE;IACnF,OAAO,gBAAgB,WAAW,OAAO,WAAW,UAAU;IAC9D,QAAQ;GACT,CAAC;GACD;EACD;EAEA,OAAO,KAAK;GACX,MAAM,WAAW;GACjB,QAAQ;IAAE,UAAU,SAAS,WAAW,KAAK;IAAG,QAAQ,SAAS,WAAW,KAAK;GAAE;GACnF,OAAO,gBAAgB,WAAW,OAAO,WAAW,UAAU;GAC9D,QAAQ,CACP,eAAe;IACd;IACA;IACA,aAAa;KACZ,MAAM;KACN,MAAM;KACN,OAAO,SAAS,KAAK,gBAAgB;KACrC,QAAQ,gBAAgB,cAAc,WAAW,IAAI;IACtD;IACA;IACA,YAAY,WAAW;IACvB,gBAAgB,WAAW;GAC5B,CAAC,CACF;EACD,CAAC;CACF;CAMA,MAAM,gBAAgB,OAAO,MAAM,MAAM,EAAE,SAAS,UAAU;CAC9D,IAAI,eAAe;EAClB,MAAM,iBAAwB;GAC7B,MAAM;GACN,MAAM;GACN,OAAO,SAAS,KAAK,eAAe;GACpC,QAAQ,OAAO,QAAQ,MAAM,EAAE,SAAS,cAAc,CAAC,UAAU,IAAI,EAAE,IAAI,CAAC;EAC7E;EAEC,CADsB,WAAW,aACnB,KAAM,cAAc,QAAoB,KAAK,cAAc;CAC3E;CAEA,OAAO;AACR"}
@@ -0,0 +1,17 @@
1
+ import { PayloadRequest } from "payload";
2
+
3
+ //#region src/fields/builtin/calculation.d.ts
4
+ /**
5
+ * Serializable calc-source metadata for the admin builder (threaded as clientProps): key, display
6
+ * label, and which modes the source implements (`scalar` = has `resolve`, `weights` = has
7
+ * `resolveWeights`). Derived where the registry is resolved; resolver functions never serialize.
8
+ */
9
+ type CalcSourceClientMeta = {
10
+ key: string;
11
+ label: string | Record<string, string>;
12
+ scalar: boolean;
13
+ weights: boolean;
14
+ };
15
+ //#endregion
16
+ export { CalcSourceClientMeta };
17
+ //# sourceMappingURL=calculation.d.ts.map
@@ -1,144 +1,199 @@
1
1
  import { keys } from "../../translations/keys.js";
2
2
  import { asTranslate, labelFor } from "../../translations/server.js";
3
+ import { localizedIf } from "../localizedIf.js";
3
4
  import { CALC_FNS, CALC_OPS } from "../../calc/types.js";
5
+ import { formatCalcValue } from "../../calc/formatCalcValue.js";
4
6
  import { normalizeCalc } from "../../calc/normalizeCalc.js";
5
7
  import { defineFormField } from "../defineFormField.js";
6
8
  //#region src/fields/builtin/calculation.ts
7
9
  /**
8
10
  * Editor-facing JSON schema for `CalcExpression` (src/calc/types.ts), used by the admin JSON
9
- * field's Monaco editor for autocomplete and inline diagnostics. The real validity gate is
10
- * `validateExpression`/`normalizeCalc`; this schema is a convenience, not the source of truth.
11
+ * field's Monaco editor for autocomplete and inline diagnostics. Built per boot so registered
12
+ * extension names (custom functions, source keys) autocomplete too. The real validity gate is
13
+ * `buildValidateExpression`/`normalizeCalc`; this schema is a convenience, not the source of truth.
11
14
  */
12
- const calcExpressionSchema = {
13
- uri: "https://10xmedia.de/schemas/form-builder/calc-expression.json",
14
- fileMatch: ["https://10xmedia.de/schemas/form-builder/calc-expression.json"],
15
- schema: {
16
- $ref: "#/definitions/expr",
17
- definitions: {
18
- expr: { oneOf: [
19
- { $ref: "#/definitions/lit" },
20
- { $ref: "#/definitions/ref" },
21
- { $ref: "#/definitions/op" },
22
- { $ref: "#/definitions/neg" },
23
- { $ref: "#/definitions/fn" },
24
- { $ref: "#/definitions/weight" }
25
- ] },
26
- lit: {
27
- type: "object",
28
- properties: {
29
- type: { enum: ["lit"] },
30
- value: { type: "number" }
15
+ const buildCalcExpressionSchema = (allowed) => {
16
+ const sourceKeys = [...allowed?.sources ?? []];
17
+ const fnNames = [...CALC_FNS, ...allowed?.functions ?? []];
18
+ return {
19
+ uri: "https://10xmedia.de/schemas/form-builder/calc-expression.json",
20
+ fileMatch: ["https://10xmedia.de/schemas/form-builder/calc-expression.json"],
21
+ schema: {
22
+ $ref: "#/definitions/expr",
23
+ definitions: {
24
+ expr: { oneOf: [
25
+ { $ref: "#/definitions/lit" },
26
+ { $ref: "#/definitions/ref" },
27
+ { $ref: "#/definitions/op" },
28
+ { $ref: "#/definitions/neg" },
29
+ { $ref: "#/definitions/fn" },
30
+ { $ref: "#/definitions/weight" },
31
+ ...sourceKeys.length > 0 ? [{ $ref: "#/definitions/source" }] : []
32
+ ] },
33
+ lit: {
34
+ type: "object",
35
+ properties: {
36
+ type: { enum: ["lit"] },
37
+ value: { type: "number" }
38
+ },
39
+ required: ["type", "value"],
40
+ additionalProperties: false
31
41
  },
32
- required: ["type", "value"],
33
- additionalProperties: false
34
- },
35
- ref: {
36
- type: "object",
37
- properties: {
38
- type: { enum: ["ref"] },
39
- field: { type: "string" }
40
- },
41
- required: ["type", "field"],
42
- additionalProperties: false
43
- },
44
- op: {
45
- type: "object",
46
- properties: {
47
- type: { enum: ["op"] },
48
- op: { enum: [...CALC_OPS] },
49
- left: { $ref: "#/definitions/expr" },
50
- right: { $ref: "#/definitions/expr" }
42
+ ref: {
43
+ type: "object",
44
+ properties: {
45
+ type: { enum: ["ref"] },
46
+ field: { type: "string" }
47
+ },
48
+ required: ["type", "field"],
49
+ additionalProperties: false
51
50
  },
52
- required: [
53
- "type",
54
- "op",
55
- "left",
56
- "right"
57
- ],
58
- additionalProperties: false
59
- },
60
- neg: {
61
- type: "object",
62
- properties: {
63
- type: { enum: ["neg"] },
64
- operand: { $ref: "#/definitions/expr" }
51
+ op: {
52
+ type: "object",
53
+ properties: {
54
+ type: { enum: ["op"] },
55
+ op: { enum: [...CALC_OPS] },
56
+ left: { $ref: "#/definitions/expr" },
57
+ right: { $ref: "#/definitions/expr" }
58
+ },
59
+ required: [
60
+ "type",
61
+ "op",
62
+ "left",
63
+ "right"
64
+ ],
65
+ additionalProperties: false
65
66
  },
66
- required: ["type", "operand"],
67
- additionalProperties: false
68
- },
69
- fn: {
70
- type: "object",
71
- properties: {
72
- type: { enum: ["fn"] },
73
- fn: { enum: [...CALC_FNS] },
74
- args: {
75
- type: "array",
76
- items: { $ref: "#/definitions/expr" }
77
- }
67
+ neg: {
68
+ type: "object",
69
+ properties: {
70
+ type: { enum: ["neg"] },
71
+ operand: { $ref: "#/definitions/expr" }
72
+ },
73
+ required: ["type", "operand"],
74
+ additionalProperties: false
78
75
  },
79
- required: [
80
- "type",
81
- "fn",
82
- "args"
83
- ],
84
- additionalProperties: false
85
- },
86
- weight: {
87
- type: "object",
88
- properties: {
89
- type: { enum: ["weight"] },
90
- field: { type: "string" },
91
- weights: {
92
- type: "object",
93
- additionalProperties: { type: "number" }
94
- }
76
+ fn: {
77
+ type: "object",
78
+ properties: {
79
+ type: { enum: ["fn"] },
80
+ fn: { enum: fnNames },
81
+ args: {
82
+ type: "array",
83
+ items: { $ref: "#/definitions/expr" }
84
+ }
85
+ },
86
+ required: [
87
+ "type",
88
+ "fn",
89
+ "args"
90
+ ],
91
+ additionalProperties: false
95
92
  },
96
- required: [
97
- "type",
98
- "field",
99
- "weights"
100
- ],
101
- additionalProperties: false
93
+ ...sourceKeys.length > 0 ? { source: {
94
+ type: "object",
95
+ properties: {
96
+ type: { enum: ["source"] },
97
+ source: { enum: sourceKeys }
98
+ },
99
+ required: ["type", "source"],
100
+ additionalProperties: false
101
+ } } : {},
102
+ weight: {
103
+ type: "object",
104
+ properties: {
105
+ type: { enum: ["weight"] },
106
+ field: { type: "string" },
107
+ weights: {
108
+ type: "object",
109
+ additionalProperties: { type: "number" }
110
+ },
111
+ ...sourceKeys.length > 0 ? { source: { enum: sourceKeys } } : {}
112
+ },
113
+ required: sourceKeys.length > 0 ? ["type", "field"] : [
114
+ "type",
115
+ "field",
116
+ "weights"
117
+ ],
118
+ additionalProperties: false
119
+ }
102
120
  }
103
121
  }
104
- }
122
+ };
105
123
  };
106
124
  /**
107
- * Validates the calculation field's `expression`: unset/empty is fine, otherwise it must
108
- * normalize into a well-formed `CalcExpression` tree. Exported for unit testing.
125
+ * Validates the calculation field's `expression` against the registered extension names: unset/empty
126
+ * is fine, otherwise it must normalize into a well-formed `CalcExpression` tree.
109
127
  */
110
- const validateExpression = (value, { req }) => {
128
+ const buildValidateExpression = (allowed) => (value, { req }) => {
111
129
  if (value == null || value === "") return true;
112
- return normalizeCalc(value) !== void 0 ? true : asTranslate(req.t)(keys.validationCalcExpressionInvalid);
130
+ return normalizeCalc(value, allowed) !== void 0 ? true : asTranslate(req.t)(keys.validationCalcExpressionInvalid);
113
131
  };
114
132
  /**
115
133
  * A calculation is derived and read-only: it renders disabled with no text affordance (no
116
134
  * `placeholder`), and it is never validated (`runSubmission` stores its computed value and skips
117
135
  * `runValidation` entirely), so an authored `required` could never fire. Both are omitted rather
118
- * than offered as settings that do nothing.
136
+ * than offered as settings that do nothing. `allowed` threads the registered calc extension names
137
+ * (plugin option `calc`) into the expression validate and the editor schema; `extras.sources`
138
+ * carries serializable source metadata to the builder component as clientProps (custom function
139
+ * names travel too, so the client-side normalize accepts every expression the server accepts).
119
140
  */
120
- const calculationField = defineFormField({
121
- type: "calculation",
122
- label: keys.fieldTypeCalculation,
123
- value: "number",
124
- omitShared: ["placeholder", "required"],
125
- config: [{
126
- name: "expression",
127
- type: "json",
128
- label: labelFor(keys.configExpression),
129
- admin: { description: labelFor(keys.configExpressionDescription) },
130
- jsonSchema: calcExpressionSchema,
131
- typescriptSchema: [() => ({ type: "object" })],
132
- validate: validateExpression
133
- }, {
134
- name: "calcDisplay",
135
- type: "checkbox",
136
- defaultValue: true,
137
- label: labelFor(keys.configCalcDisplay)
138
- }],
139
- format: ({ value }) => value == null ? "" : String(value)
140
- });
141
+ const buildCalculationField = (allowed, extras) => {
142
+ const sources = extras?.sources ?? [];
143
+ const functions = [...allowed?.functions ?? []];
144
+ const builderRef = "@10x-media/form-builder/client#CalcExpressionBuilder";
145
+ return defineFormField({
146
+ type: "calculation",
147
+ label: keys.fieldTypeCalculation,
148
+ value: "number",
149
+ omitShared: ["placeholder", "required"],
150
+ config: [
151
+ {
152
+ name: "expression",
153
+ type: "json",
154
+ label: labelFor(keys.configExpression),
155
+ admin: { components: { Field: sources.length > 0 || functions.length > 0 ? {
156
+ path: builderRef,
157
+ clientProps: {
158
+ sources,
159
+ functions
160
+ }
161
+ } : builderRef } },
162
+ jsonSchema: buildCalcExpressionSchema(allowed),
163
+ typescriptSchema: [() => ({ type: "object" })],
164
+ validate: buildValidateExpression(allowed)
165
+ },
166
+ {
167
+ name: "calcDisplay",
168
+ type: "checkbox",
169
+ defaultValue: true,
170
+ label: labelFor(keys.configCalcDisplay)
171
+ },
172
+ {
173
+ name: "decimals",
174
+ type: "number",
175
+ min: 0,
176
+ max: 6,
177
+ label: labelFor(keys.calcConfigDecimals)
178
+ },
179
+ {
180
+ name: "prefix",
181
+ type: "text",
182
+ label: labelFor(keys.calcConfigPrefix),
183
+ ...localizedIf(extras?.localize === true)
184
+ },
185
+ {
186
+ name: "suffix",
187
+ type: "text",
188
+ label: labelFor(keys.calcConfigSuffix),
189
+ ...localizedIf(extras?.localize === true)
190
+ }
191
+ ],
192
+ format: ({ value, config }) => value == null ? "" : formatCalcValue(value, config)
193
+ });
194
+ };
195
+ buildCalculationField();
141
196
  //#endregion
142
- export { calculationField };
197
+ export { buildCalculationField };
143
198
 
144
199
  //# sourceMappingURL=calculation.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"calculation.js","names":[],"sources":["../../../src/fields/builtin/calculation.ts"],"sourcesContent":["import type { JSONField, PayloadRequest } from 'payload'\nimport { normalizeCalc } from '../../calc/normalizeCalc'\nimport { CALC_FNS, CALC_OPS } from '../../calc/types'\nimport { keys } from '../../translations/keys'\nimport { asTranslate, labelFor } from '../../translations/server'\nimport { defineFormField } from '../defineFormField'\n\ntype CalcExpressionSchema = NonNullable<JSONField['jsonSchema']>\n\n/**\n * Editor-facing JSON schema for `CalcExpression` (src/calc/types.ts), used by the admin JSON\n * field's Monaco editor for autocomplete and inline diagnostics. The real validity gate is\n * `validateExpression`/`normalizeCalc`; this schema is a convenience, not the source of truth.\n */\nconst calcExpressionSchema: CalcExpressionSchema = {\n\turi: 'https://10xmedia.de/schemas/form-builder/calc-expression.json',\n\tfileMatch: ['https://10xmedia.de/schemas/form-builder/calc-expression.json'],\n\tschema: {\n\t\t$ref: '#/definitions/expr',\n\t\tdefinitions: {\n\t\t\texpr: {\n\t\t\t\toneOf: [\n\t\t\t\t\t{ $ref: '#/definitions/lit' },\n\t\t\t\t\t{ $ref: '#/definitions/ref' },\n\t\t\t\t\t{ $ref: '#/definitions/op' },\n\t\t\t\t\t{ $ref: '#/definitions/neg' },\n\t\t\t\t\t{ $ref: '#/definitions/fn' },\n\t\t\t\t\t{ $ref: '#/definitions/weight' },\n\t\t\t\t],\n\t\t\t},\n\t\t\tlit: {\n\t\t\t\ttype: 'object',\n\t\t\t\tproperties: { type: { enum: ['lit'] }, value: { type: 'number' } },\n\t\t\t\trequired: ['type', 'value'],\n\t\t\t\tadditionalProperties: false,\n\t\t\t},\n\t\t\tref: {\n\t\t\t\ttype: 'object',\n\t\t\t\tproperties: { type: { enum: ['ref'] }, field: { type: 'string' } },\n\t\t\t\trequired: ['type', 'field'],\n\t\t\t\tadditionalProperties: false,\n\t\t\t},\n\t\t\top: {\n\t\t\t\ttype: 'object',\n\t\t\t\tproperties: {\n\t\t\t\t\ttype: { enum: ['op'] },\n\t\t\t\t\top: { enum: [...CALC_OPS] },\n\t\t\t\t\tleft: { $ref: '#/definitions/expr' },\n\t\t\t\t\tright: { $ref: '#/definitions/expr' },\n\t\t\t\t},\n\t\t\t\trequired: ['type', 'op', 'left', 'right'],\n\t\t\t\tadditionalProperties: false,\n\t\t\t},\n\t\t\tneg: {\n\t\t\t\ttype: 'object',\n\t\t\t\tproperties: { type: { enum: ['neg'] }, operand: { $ref: '#/definitions/expr' } },\n\t\t\t\trequired: ['type', 'operand'],\n\t\t\t\tadditionalProperties: false,\n\t\t\t},\n\t\t\tfn: {\n\t\t\t\ttype: 'object',\n\t\t\t\tproperties: {\n\t\t\t\t\ttype: { enum: ['fn'] },\n\t\t\t\t\tfn: { enum: [...CALC_FNS] },\n\t\t\t\t\targs: { type: 'array', items: { $ref: '#/definitions/expr' } },\n\t\t\t\t},\n\t\t\t\trequired: ['type', 'fn', 'args'],\n\t\t\t\tadditionalProperties: false,\n\t\t\t},\n\t\t\tweight: {\n\t\t\t\ttype: 'object',\n\t\t\t\tproperties: {\n\t\t\t\t\ttype: { enum: ['weight'] },\n\t\t\t\t\tfield: { type: 'string' },\n\t\t\t\t\tweights: { type: 'object', additionalProperties: { type: 'number' } },\n\t\t\t\t},\n\t\t\t\trequired: ['type', 'field', 'weights'],\n\t\t\t\tadditionalProperties: false,\n\t\t\t},\n\t\t},\n\t},\n}\n\n/**\n * Validates the calculation field's `expression`: unset/empty is fine, otherwise it must\n * normalize into a well-formed `CalcExpression` tree. Exported for unit testing.\n */\nexport const validateExpression = (\n\tvalue: unknown,\n\t{ req }: { data?: unknown; req: PayloadRequest }\n): string | true => {\n\tif (value == null || value === '') {\n\t\treturn true\n\t}\n\treturn normalizeCalc(value) !== undefined\n\t\t? true\n\t\t: asTranslate(req.t)(keys.validationCalcExpressionInvalid)\n}\n\n/**\n * A calculation is derived and read-only: it renders disabled with no text affordance (no\n * `placeholder`), and it is never validated (`runSubmission` stores its computed value and skips\n * `runValidation` entirely), so an authored `required` could never fire. Both are omitted rather\n * than offered as settings that do nothing.\n */\nexport const calculationField = defineFormField<'number'>({\n\ttype: 'calculation',\n\tlabel: keys.fieldTypeCalculation,\n\tvalue: 'number',\n\tomitShared: ['placeholder', 'required'],\n\tconfig: [\n\t\t{\n\t\t\tname: 'expression',\n\t\t\ttype: 'json',\n\t\t\tlabel: labelFor(keys.configExpression),\n\t\t\tadmin: { description: labelFor(keys.configExpressionDescription) },\n\t\t\tjsonSchema: calcExpressionSchema,\n\t\t\t// generate:types embeds jsonSchema.schema into the config-level schema, where its\n\t\t\t// document-root-relative $refs cannot resolve; hand type generation a flat shape instead.\n\t\t\ttypescriptSchema: [() => ({ type: 'object' })],\n\t\t\tvalidate: validateExpression,\n\t\t},\n\t\t{\n\t\t\tname: 'calcDisplay',\n\t\t\ttype: 'checkbox',\n\t\t\tdefaultValue: true,\n\t\t\tlabel: labelFor(keys.configCalcDisplay),\n\t\t},\n\t],\n\tformat: ({ value }) => (value == null ? '' : String(value)),\n})\n"],"mappings":";;;;;;;;;;;AAcA,MAAM,uBAA6C;CAClD,KAAK;CACL,WAAW,CAAC,+DAA+D;CAC3E,QAAQ;EACP,MAAM;EACN,aAAa;GACZ,MAAM,EACL,OAAO;IACN,EAAE,MAAM,oBAAoB;IAC5B,EAAE,MAAM,oBAAoB;IAC5B,EAAE,MAAM,mBAAmB;IAC3B,EAAE,MAAM,oBAAoB;IAC5B,EAAE,MAAM,mBAAmB;IAC3B,EAAE,MAAM,uBAAuB;GAChC,EACD;GACA,KAAK;IACJ,MAAM;IACN,YAAY;KAAE,MAAM,EAAE,MAAM,CAAC,KAAK,EAAE;KAAG,OAAO,EAAE,MAAM,SAAS;IAAE;IACjE,UAAU,CAAC,QAAQ,OAAO;IAC1B,sBAAsB;GACvB;GACA,KAAK;IACJ,MAAM;IACN,YAAY;KAAE,MAAM,EAAE,MAAM,CAAC,KAAK,EAAE;KAAG,OAAO,EAAE,MAAM,SAAS;IAAE;IACjE,UAAU,CAAC,QAAQ,OAAO;IAC1B,sBAAsB;GACvB;GACA,IAAI;IACH,MAAM;IACN,YAAY;KACX,MAAM,EAAE,MAAM,CAAC,IAAI,EAAE;KACrB,IAAI,EAAE,MAAM,CAAC,GAAG,QAAQ,EAAE;KAC1B,MAAM,EAAE,MAAM,qBAAqB;KACnC,OAAO,EAAE,MAAM,qBAAqB;IACrC;IACA,UAAU;KAAC;KAAQ;KAAM;KAAQ;IAAO;IACxC,sBAAsB;GACvB;GACA,KAAK;IACJ,MAAM;IACN,YAAY;KAAE,MAAM,EAAE,MAAM,CAAC,KAAK,EAAE;KAAG,SAAS,EAAE,MAAM,qBAAqB;IAAE;IAC/E,UAAU,CAAC,QAAQ,SAAS;IAC5B,sBAAsB;GACvB;GACA,IAAI;IACH,MAAM;IACN,YAAY;KACX,MAAM,EAAE,MAAM,CAAC,IAAI,EAAE;KACrB,IAAI,EAAE,MAAM,CAAC,GAAG,QAAQ,EAAE;KAC1B,MAAM;MAAE,MAAM;MAAS,OAAO,EAAE,MAAM,qBAAqB;KAAE;IAC9D;IACA,UAAU;KAAC;KAAQ;KAAM;IAAM;IAC/B,sBAAsB;GACvB;GACA,QAAQ;IACP,MAAM;IACN,YAAY;KACX,MAAM,EAAE,MAAM,CAAC,QAAQ,EAAE;KACzB,OAAO,EAAE,MAAM,SAAS;KACxB,SAAS;MAAE,MAAM;MAAU,sBAAsB,EAAE,MAAM,SAAS;KAAE;IACrE;IACA,UAAU;KAAC;KAAQ;KAAS;IAAS;IACrC,sBAAsB;GACvB;EACD;CACD;AACD;;;;;AAMA,MAAa,sBACZ,OACA,EAAE,UACiB;CACnB,IAAI,SAAS,QAAQ,UAAU,IAC9B,OAAO;CAER,OAAO,cAAc,KAAK,MAAM,KAAA,IAC7B,OACA,YAAY,IAAI,CAAC,EAAE,KAAK,+BAA+B;AAC3D;;;;;;;AAQA,MAAa,mBAAmB,gBAA0B;CACzD,MAAM;CACN,OAAO,KAAK;CACZ,OAAO;CACP,YAAY,CAAC,eAAe,UAAU;CACtC,QAAQ,CACP;EACC,MAAM;EACN,MAAM;EACN,OAAO,SAAS,KAAK,gBAAgB;EACrC,OAAO,EAAE,aAAa,SAAS,KAAK,2BAA2B,EAAE;EACjE,YAAY;EAGZ,kBAAkB,QAAQ,EAAE,MAAM,SAAS,EAAE;EAC7C,UAAU;CACX,GACA;EACC,MAAM;EACN,MAAM;EACN,cAAc;EACd,OAAO,SAAS,KAAK,iBAAiB;CACvC,CACD;CACA,SAAS,EAAE,YAAa,SAAS,OAAO,KAAK,OAAO,KAAK;AAC1D,CAAC"}
1
+ {"version":3,"file":"calculation.js","names":[],"sources":["../../../src/fields/builtin/calculation.ts"],"sourcesContent":["import type { JSONField, PayloadRequest } from 'payload'\nimport { formatCalcValue } from '../../calc/formatCalcValue'\nimport { type CalcAllowed, normalizeCalc } from '../../calc/normalizeCalc'\nimport { CALC_FNS, CALC_OPS } from '../../calc/types'\nimport { keys } from '../../translations/keys'\nimport { asTranslate, labelFor } from '../../translations/server'\nimport { defineFormField } from '../defineFormField'\nimport { localizedIf } from '../localizedIf'\n\n/**\n * Serializable calc-source metadata for the admin builder (threaded as clientProps): key, display\n * label, and which modes the source implements (`scalar` = has `resolve`, `weights` = has\n * `resolveWeights`). Derived where the registry is resolved; resolver functions never serialize.\n */\nexport type CalcSourceClientMeta = {\n\tkey: string\n\tlabel: string | Record<string, string>\n\tscalar: boolean\n\tweights: boolean\n}\n\ntype BuildCalculationFieldExtras = {\n\t/** Whether content-bearing display config (`prefix`, `suffix`) is localized. */\n\tlocalize?: boolean\n\t/** Registered calc-source metadata for the builder UI. */\n\tsources?: CalcSourceClientMeta[]\n}\n\n/** The calculation field's own config values (display settings; `expression` is handled separately). */\ntype CalculationConfig = {\n\tdecimals?: number\n\tprefix?: string\n\tsuffix?: string\n}\n\ntype CalcExpressionSchema = NonNullable<JSONField['jsonSchema']>\n\n/**\n * Editor-facing JSON schema for `CalcExpression` (src/calc/types.ts), used by the admin JSON\n * field's Monaco editor for autocomplete and inline diagnostics. Built per boot so registered\n * extension names (custom functions, source keys) autocomplete too. The real validity gate is\n * `buildValidateExpression`/`normalizeCalc`; this schema is a convenience, not the source of truth.\n */\nconst buildCalcExpressionSchema = (allowed?: CalcAllowed): CalcExpressionSchema => {\n\tconst sourceKeys = [...(allowed?.sources ?? [])]\n\tconst fnNames = [...CALC_FNS, ...(allowed?.functions ?? [])]\n\treturn {\n\t\turi: 'https://10xmedia.de/schemas/form-builder/calc-expression.json',\n\t\tfileMatch: ['https://10xmedia.de/schemas/form-builder/calc-expression.json'],\n\t\tschema: {\n\t\t\t$ref: '#/definitions/expr',\n\t\t\tdefinitions: {\n\t\t\t\texpr: {\n\t\t\t\t\toneOf: [\n\t\t\t\t\t\t{ $ref: '#/definitions/lit' },\n\t\t\t\t\t\t{ $ref: '#/definitions/ref' },\n\t\t\t\t\t\t{ $ref: '#/definitions/op' },\n\t\t\t\t\t\t{ $ref: '#/definitions/neg' },\n\t\t\t\t\t\t{ $ref: '#/definitions/fn' },\n\t\t\t\t\t\t{ $ref: '#/definitions/weight' },\n\t\t\t\t\t\t...(sourceKeys.length > 0 ? [{ $ref: '#/definitions/source' }] : []),\n\t\t\t\t\t],\n\t\t\t\t},\n\t\t\t\tlit: {\n\t\t\t\t\ttype: 'object',\n\t\t\t\t\tproperties: { type: { enum: ['lit'] }, value: { type: 'number' } },\n\t\t\t\t\trequired: ['type', 'value'],\n\t\t\t\t\tadditionalProperties: false,\n\t\t\t\t},\n\t\t\t\tref: {\n\t\t\t\t\ttype: 'object',\n\t\t\t\t\tproperties: { type: { enum: ['ref'] }, field: { type: 'string' } },\n\t\t\t\t\trequired: ['type', 'field'],\n\t\t\t\t\tadditionalProperties: false,\n\t\t\t\t},\n\t\t\t\top: {\n\t\t\t\t\ttype: 'object',\n\t\t\t\t\tproperties: {\n\t\t\t\t\t\ttype: { enum: ['op'] },\n\t\t\t\t\t\top: { enum: [...CALC_OPS] },\n\t\t\t\t\t\tleft: { $ref: '#/definitions/expr' },\n\t\t\t\t\t\tright: { $ref: '#/definitions/expr' },\n\t\t\t\t\t},\n\t\t\t\t\trequired: ['type', 'op', 'left', 'right'],\n\t\t\t\t\tadditionalProperties: false,\n\t\t\t\t},\n\t\t\t\tneg: {\n\t\t\t\t\ttype: 'object',\n\t\t\t\t\tproperties: { type: { enum: ['neg'] }, operand: { $ref: '#/definitions/expr' } },\n\t\t\t\t\trequired: ['type', 'operand'],\n\t\t\t\t\tadditionalProperties: false,\n\t\t\t\t},\n\t\t\t\tfn: {\n\t\t\t\t\ttype: 'object',\n\t\t\t\t\tproperties: {\n\t\t\t\t\t\ttype: { enum: ['fn'] },\n\t\t\t\t\t\tfn: { enum: fnNames },\n\t\t\t\t\t\targs: { type: 'array', items: { $ref: '#/definitions/expr' } },\n\t\t\t\t\t},\n\t\t\t\t\trequired: ['type', 'fn', 'args'],\n\t\t\t\t\tadditionalProperties: false,\n\t\t\t\t},\n\t\t\t\t...(sourceKeys.length > 0\n\t\t\t\t\t? {\n\t\t\t\t\t\t\tsource: {\n\t\t\t\t\t\t\t\ttype: 'object',\n\t\t\t\t\t\t\t\tproperties: { type: { enum: ['source'] }, source: { enum: sourceKeys } },\n\t\t\t\t\t\t\t\trequired: ['type', 'source'],\n\t\t\t\t\t\t\t\tadditionalProperties: false,\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\tweight: {\n\t\t\t\t\ttype: 'object',\n\t\t\t\t\tproperties: {\n\t\t\t\t\t\ttype: { enum: ['weight'] },\n\t\t\t\t\t\tfield: { type: 'string' },\n\t\t\t\t\t\tweights: { type: 'object', additionalProperties: { type: 'number' } },\n\t\t\t\t\t\t...(sourceKeys.length > 0 ? { source: { enum: sourceKeys } } : {}),\n\t\t\t\t\t},\n\t\t\t\t\t// With sources registered a weight may carry `source` instead of inline weights; the\n\t\t\t\t\t// either-or itself is enforced by normalizeCalc, not this convenience schema.\n\t\t\t\t\trequired: sourceKeys.length > 0 ? ['type', 'field'] : ['type', 'field', 'weights'],\n\t\t\t\t\tadditionalProperties: false,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n}\n\n/**\n * Validates the calculation field's `expression` against the registered extension names: unset/empty\n * is fine, otherwise it must normalize into a well-formed `CalcExpression` tree.\n */\nexport const buildValidateExpression =\n\t(allowed?: CalcAllowed) =>\n\t(value: unknown, { req }: { data?: unknown; req: PayloadRequest }): string | true => {\n\t\tif (value == null || value === '') {\n\t\t\treturn true\n\t\t}\n\t\treturn normalizeCalc(value, allowed) !== undefined\n\t\t\t? true\n\t\t\t: asTranslate(req.t)(keys.validationCalcExpressionInvalid)\n\t}\n\n/** The no-extensions validate (built-in grammar only). Exported for unit testing and spread consumers. */\nexport const validateExpression = buildValidateExpression()\n\n/**\n * A calculation is derived and read-only: it renders disabled with no text affordance (no\n * `placeholder`), and it is never validated (`runSubmission` stores its computed value and skips\n * `runValidation` entirely), so an authored `required` could never fire. Both are omitted rather\n * than offered as settings that do nothing. `allowed` threads the registered calc extension names\n * (plugin option `calc`) into the expression validate and the editor schema; `extras.sources`\n * carries serializable source metadata to the builder component as clientProps (custom function\n * names travel too, so the client-side normalize accepts every expression the server accepts).\n */\nexport const buildCalculationField = (\n\tallowed?: CalcAllowed,\n\textras?: BuildCalculationFieldExtras\n) => {\n\tconst sources = extras?.sources ?? []\n\tconst functions = [...(allowed?.functions ?? [])]\n\tconst builderRef = '@10x-media/form-builder/client#CalcExpressionBuilder'\n\treturn defineFormField<'number', CalculationConfig>({\n\t\ttype: 'calculation',\n\t\tlabel: keys.fieldTypeCalculation,\n\t\tvalue: 'number',\n\t\tomitShared: ['placeholder', 'required'],\n\t\tconfig: [\n\t\t\t{\n\t\t\t\tname: 'expression',\n\t\t\t\ttype: 'json',\n\t\t\t\tlabel: labelFor(keys.configExpression),\n\t\t\t\tadmin: {\n\t\t\t\t\tcomponents: {\n\t\t\t\t\t\tField:\n\t\t\t\t\t\t\tsources.length > 0 || functions.length > 0\n\t\t\t\t\t\t\t\t? { path: builderRef, clientProps: { sources, functions } }\n\t\t\t\t\t\t\t\t: builderRef,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tjsonSchema: buildCalcExpressionSchema(allowed),\n\t\t\t\t// generate:types embeds jsonSchema.schema into the config-level schema, where its\n\t\t\t\t// document-root-relative $refs cannot resolve; hand type generation a flat shape instead.\n\t\t\t\ttypescriptSchema: [() => ({ type: 'object' })],\n\t\t\t\tvalidate: buildValidateExpression(allowed),\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: 'calcDisplay',\n\t\t\t\ttype: 'checkbox',\n\t\t\t\tdefaultValue: true,\n\t\t\t\tlabel: labelFor(keys.configCalcDisplay),\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: 'decimals',\n\t\t\t\ttype: 'number',\n\t\t\t\tmin: 0,\n\t\t\t\tmax: 6,\n\t\t\t\tlabel: labelFor(keys.calcConfigDecimals),\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: 'prefix',\n\t\t\t\ttype: 'text',\n\t\t\t\tlabel: labelFor(keys.calcConfigPrefix),\n\t\t\t\t...localizedIf(extras?.localize === true),\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: 'suffix',\n\t\t\t\ttype: 'text',\n\t\t\t\tlabel: labelFor(keys.calcConfigSuffix),\n\t\t\t\t...localizedIf(extras?.localize === true),\n\t\t\t},\n\t\t],\n\t\tformat: ({ value, config }) => (value == null ? '' : formatCalcValue(value, config)),\n\t})\n}\n\n/** The no-extensions definition, for definition-spread consumers (the `buildSelectField`/`selectField` precedent). */\nexport const calculationField = buildCalculationField()\n"],"mappings":";;;;;;;;;;;;;;AA2CA,MAAM,6BAA6B,YAAgD;CAClF,MAAM,aAAa,CAAC,GAAI,SAAS,WAAW,CAAC,CAAE;CAC/C,MAAM,UAAU,CAAC,GAAG,UAAU,GAAI,SAAS,aAAa,CAAC,CAAE;CAC3D,OAAO;EACN,KAAK;EACL,WAAW,CAAC,+DAA+D;EAC3E,QAAQ;GACP,MAAM;GACN,aAAa;IACZ,MAAM,EACL,OAAO;KACN,EAAE,MAAM,oBAAoB;KAC5B,EAAE,MAAM,oBAAoB;KAC5B,EAAE,MAAM,mBAAmB;KAC3B,EAAE,MAAM,oBAAoB;KAC5B,EAAE,MAAM,mBAAmB;KAC3B,EAAE,MAAM,uBAAuB;KAC/B,GAAI,WAAW,SAAS,IAAI,CAAC,EAAE,MAAM,uBAAuB,CAAC,IAAI,CAAC;IACnE,EACD;IACA,KAAK;KACJ,MAAM;KACN,YAAY;MAAE,MAAM,EAAE,MAAM,CAAC,KAAK,EAAE;MAAG,OAAO,EAAE,MAAM,SAAS;KAAE;KACjE,UAAU,CAAC,QAAQ,OAAO;KAC1B,sBAAsB;IACvB;IACA,KAAK;KACJ,MAAM;KACN,YAAY;MAAE,MAAM,EAAE,MAAM,CAAC,KAAK,EAAE;MAAG,OAAO,EAAE,MAAM,SAAS;KAAE;KACjE,UAAU,CAAC,QAAQ,OAAO;KAC1B,sBAAsB;IACvB;IACA,IAAI;KACH,MAAM;KACN,YAAY;MACX,MAAM,EAAE,MAAM,CAAC,IAAI,EAAE;MACrB,IAAI,EAAE,MAAM,CAAC,GAAG,QAAQ,EAAE;MAC1B,MAAM,EAAE,MAAM,qBAAqB;MACnC,OAAO,EAAE,MAAM,qBAAqB;KACrC;KACA,UAAU;MAAC;MAAQ;MAAM;MAAQ;KAAO;KACxC,sBAAsB;IACvB;IACA,KAAK;KACJ,MAAM;KACN,YAAY;MAAE,MAAM,EAAE,MAAM,CAAC,KAAK,EAAE;MAAG,SAAS,EAAE,MAAM,qBAAqB;KAAE;KAC/E,UAAU,CAAC,QAAQ,SAAS;KAC5B,sBAAsB;IACvB;IACA,IAAI;KACH,MAAM;KACN,YAAY;MACX,MAAM,EAAE,MAAM,CAAC,IAAI,EAAE;MACrB,IAAI,EAAE,MAAM,QAAQ;MACpB,MAAM;OAAE,MAAM;OAAS,OAAO,EAAE,MAAM,qBAAqB;MAAE;KAC9D;KACA,UAAU;MAAC;MAAQ;MAAM;KAAM;KAC/B,sBAAsB;IACvB;IACA,GAAI,WAAW,SAAS,IACrB,EACA,QAAQ;KACP,MAAM;KACN,YAAY;MAAE,MAAM,EAAE,MAAM,CAAC,QAAQ,EAAE;MAAG,QAAQ,EAAE,MAAM,WAAW;KAAE;KACvE,UAAU,CAAC,QAAQ,QAAQ;KAC3B,sBAAsB;IACvB,EACD,IACC,CAAC;IACJ,QAAQ;KACP,MAAM;KACN,YAAY;MACX,MAAM,EAAE,MAAM,CAAC,QAAQ,EAAE;MACzB,OAAO,EAAE,MAAM,SAAS;MACxB,SAAS;OAAE,MAAM;OAAU,sBAAsB,EAAE,MAAM,SAAS;MAAE;MACpE,GAAI,WAAW,SAAS,IAAI,EAAE,QAAQ,EAAE,MAAM,WAAW,EAAE,IAAI,CAAC;KACjE;KAGA,UAAU,WAAW,SAAS,IAAI,CAAC,QAAQ,OAAO,IAAI;MAAC;MAAQ;MAAS;KAAS;KACjF,sBAAsB;IACvB;GACD;EACD;CACD;AACD;;;;;AAMA,MAAa,2BACX,aACA,OAAgB,EAAE,UAAkE;CACpF,IAAI,SAAS,QAAQ,UAAU,IAC9B,OAAO;CAER,OAAO,cAAc,OAAO,OAAO,MAAM,KAAA,IACtC,OACA,YAAY,IAAI,CAAC,EAAE,KAAK,+BAA+B;AAC3D;;;;;;;;;;AAcD,MAAa,yBACZ,SACA,WACI;CACJ,MAAM,UAAU,QAAQ,WAAW,CAAC;CACpC,MAAM,YAAY,CAAC,GAAI,SAAS,aAAa,CAAC,CAAE;CAChD,MAAM,aAAa;CACnB,OAAO,gBAA6C;EACnD,MAAM;EACN,OAAO,KAAK;EACZ,OAAO;EACP,YAAY,CAAC,eAAe,UAAU;EACtC,QAAQ;GACP;IACC,MAAM;IACN,MAAM;IACN,OAAO,SAAS,KAAK,gBAAgB;IACrC,OAAO,EACN,YAAY,EACX,OACC,QAAQ,SAAS,KAAK,UAAU,SAAS,IACtC;KAAE,MAAM;KAAY,aAAa;MAAE;MAAS;KAAU;IAAE,IACxD,WACL,EACD;IACA,YAAY,0BAA0B,OAAO;IAG7C,kBAAkB,QAAQ,EAAE,MAAM,SAAS,EAAE;IAC7C,UAAU,wBAAwB,OAAO;GAC1C;GACA;IACC,MAAM;IACN,MAAM;IACN,cAAc;IACd,OAAO,SAAS,KAAK,iBAAiB;GACvC;GACA;IACC,MAAM;IACN,MAAM;IACN,KAAK;IACL,KAAK;IACL,OAAO,SAAS,KAAK,kBAAkB;GACxC;GACA;IACC,MAAM;IACN,MAAM;IACN,OAAO,SAAS,KAAK,gBAAgB;IACrC,GAAG,YAAY,QAAQ,aAAa,IAAI;GACzC;GACA;IACC,MAAM;IACN,MAAM;IACN,OAAO,SAAS,KAAK,gBAAgB;IACrC,GAAG,YAAY,QAAQ,aAAa,IAAI;GACzC;EACD;EACA,SAAS,EAAE,OAAO,aAAc,SAAS,OAAO,KAAK,gBAAgB,OAAO,MAAM;CACnF,CAAC;AACF;AAGgC,sBAAsB"}
@@ -1,4 +1,5 @@
1
1
  import { keys } from "../../translations/keys.js";
2
+ import { labelFor } from "../../translations/server.js";
2
3
  import { defineFormField } from "../defineFormField.js";
3
4
  //#region src/fields/builtin/checkbox.ts
4
5
  /**
@@ -12,6 +13,20 @@ const checkboxField = defineFormField({
12
13
  label: keys.fieldTypeCheckbox,
13
14
  value: "boolean",
14
15
  omitShared: ["placeholder"],
16
+ config: [{
17
+ name: "display",
18
+ type: "select",
19
+ defaultValue: "checkbox",
20
+ label: labelFor(keys.configCheckboxDisplay),
21
+ admin: { isClearable: false },
22
+ options: [{
23
+ label: labelFor(keys.checkboxDisplayCheckbox),
24
+ value: "checkbox"
25
+ }, {
26
+ label: labelFor(keys.checkboxDisplaySwitch),
27
+ value: "switch"
28
+ }]
29
+ }],
15
30
  validate: ({ value, config, t }) => config.required === true && value !== true ? t(keys.validationRequired) : true,
16
31
  format: ({ value, t }) => value ? t(keys.formatYes) : t(keys.formatNo)
17
32
  });
@@ -1 +1 @@
1
- {"version":3,"file":"checkbox.js","names":[],"sources":["../../../src/fields/builtin/checkbox.ts"],"sourcesContent":["import { keys } from '../../translations/keys'\nimport { defineFormField } from '../defineFormField'\n\ntype CheckboxConfig = { required?: boolean }\n\n/**\n * A checkbox renders as a lone box with no free-text affordance, so `placeholder` is never read.\n * The intrinsic validator owns `required`: the engine's shared required guard only fires on an\n * empty value, and `false` (checked, then unchecked) is a present one, so without this a required\n * checkbox would accept an explicit refusal.\n */\nexport const checkboxField = defineFormField<'boolean', CheckboxConfig>({\n\ttype: 'checkbox',\n\tlabel: keys.fieldTypeCheckbox,\n\tvalue: 'boolean',\n\tomitShared: ['placeholder'],\n\tvalidate: ({ value, config, t }) =>\n\t\tconfig.required === true && value !== true ? t(keys.validationRequired) : true,\n\tformat: ({ value, t }) => (value ? t(keys.formatYes) : t(keys.formatNo)),\n})\n"],"mappings":";;;;;;;;;AAWA,MAAa,gBAAgB,gBAA2C;CACvE,MAAM;CACN,OAAO,KAAK;CACZ,OAAO;CACP,YAAY,CAAC,aAAa;CAC1B,WAAW,EAAE,OAAO,QAAQ,QAC3B,OAAO,aAAa,QAAQ,UAAU,OAAO,EAAE,KAAK,kBAAkB,IAAI;CAC3E,SAAS,EAAE,OAAO,QAAS,QAAQ,EAAE,KAAK,SAAS,IAAI,EAAE,KAAK,QAAQ;AACvE,CAAC"}
1
+ {"version":3,"file":"checkbox.js","names":[],"sources":["../../../src/fields/builtin/checkbox.ts"],"sourcesContent":["import { keys } from '../../translations/keys'\nimport { labelFor } from '../../translations/server'\nimport { defineFormField } from '../defineFormField'\n\ntype CheckboxConfig = { required?: boolean; display?: 'checkbox' | 'switch' }\n\n/**\n * A checkbox renders as a lone box with no free-text affordance, so `placeholder` is never read.\n * The intrinsic validator owns `required`: the engine's shared required guard only fires on an\n * empty value, and `false` (checked, then unchecked) is a present one, so without this a required\n * checkbox would accept an explicit refusal.\n */\nexport const checkboxField = defineFormField<'boolean', CheckboxConfig>({\n\ttype: 'checkbox',\n\tlabel: keys.fieldTypeCheckbox,\n\tvalue: 'boolean',\n\tomitShared: ['placeholder'],\n\tconfig: [\n\t\t{\n\t\t\tname: 'display',\n\t\t\ttype: 'select',\n\t\t\tdefaultValue: 'checkbox',\n\t\t\tlabel: labelFor(keys.configCheckboxDisplay),\n\t\t\tadmin: { isClearable: false },\n\t\t\toptions: [\n\t\t\t\t{ label: labelFor(keys.checkboxDisplayCheckbox), value: 'checkbox' },\n\t\t\t\t{ label: labelFor(keys.checkboxDisplaySwitch), value: 'switch' },\n\t\t\t],\n\t\t},\n\t],\n\tvalidate: ({ value, config, t }) =>\n\t\tconfig.required === true && value !== true ? t(keys.validationRequired) : true,\n\tformat: ({ value, t }) => (value ? t(keys.formatYes) : t(keys.formatNo)),\n})\n"],"mappings":";;;;;;;;;;AAYA,MAAa,gBAAgB,gBAA2C;CACvE,MAAM;CACN,OAAO,KAAK;CACZ,OAAO;CACP,YAAY,CAAC,aAAa;CAC1B,QAAQ,CACP;EACC,MAAM;EACN,MAAM;EACN,cAAc;EACd,OAAO,SAAS,KAAK,qBAAqB;EAC1C,OAAO,EAAE,aAAa,MAAM;EAC5B,SAAS,CACR;GAAE,OAAO,SAAS,KAAK,uBAAuB;GAAG,OAAO;EAAW,GACnE;GAAE,OAAO,SAAS,KAAK,qBAAqB;GAAG,OAAO;EAAS,CAChE;CACD,CACD;CACA,WAAW,EAAE,OAAO,QAAQ,QAC3B,OAAO,aAAa,QAAQ,UAAU,OAAO,EAAE,KAAK,kBAAkB,IAAI;CAC3E,SAAS,EAAE,OAAO,QAAS,QAAQ,EAAE,KAAK,SAAS,IAAI,EAAE,KAAK,QAAQ;AACvE,CAAC"}
@@ -1,4 +1,5 @@
1
1
  import { keys } from "../../translations/keys.js";
2
+ import { labelFor } from "../../translations/server.js";
2
3
  import { defineFormField } from "../defineFormField.js";
3
4
  import { EMAIL_PATTERN } from "../../validation/emailPattern.js";
4
5
  //#region src/fields/builtin/email.ts
@@ -6,6 +7,12 @@ const emailField = defineFormField({
6
7
  type: "email",
7
8
  label: keys.fieldTypeEmail,
8
9
  value: "text",
10
+ advancedConfig: [{
11
+ name: "autocomplete",
12
+ type: "text",
13
+ label: labelFor(keys.configAutocomplete),
14
+ admin: { description: labelFor(keys.configAutocompleteDescription) }
15
+ }],
9
16
  validate: ({ value, t }) => {
10
17
  if (value == null || value === "") return true;
11
18
  return EMAIL_PATTERN.test(value) ? true : t(keys.validationEmail);
@@ -1 +1 @@
1
- {"version":3,"file":"email.js","names":[],"sources":["../../../src/fields/builtin/email.ts"],"sourcesContent":["import { keys } from '../../translations/keys'\nimport { EMAIL_PATTERN } from '../../validation/emailPattern'\nimport { defineFormField } from '../defineFormField'\n\nexport const emailField = defineFormField<'text'>({\n\ttype: 'email',\n\tlabel: keys.fieldTypeEmail,\n\tvalue: 'text',\n\tvalidate: ({ value, t }) => {\n\t\tif (value == null || value === '') {\n\t\t\treturn true\n\t\t}\n\t\treturn EMAIL_PATTERN.test(value) ? true : t(keys.validationEmail)\n\t},\n\tformat: ({ value }) => (value == null ? '' : String(value)),\n})\n"],"mappings":";;;;AAIA,MAAa,aAAa,gBAAwB;CACjD,MAAM;CACN,OAAO,KAAK;CACZ,OAAO;CACP,WAAW,EAAE,OAAO,QAAQ;EAC3B,IAAI,SAAS,QAAQ,UAAU,IAC9B,OAAO;EAER,OAAO,cAAc,KAAK,KAAK,IAAI,OAAO,EAAE,KAAK,eAAe;CACjE;CACA,SAAS,EAAE,YAAa,SAAS,OAAO,KAAK,OAAO,KAAK;AAC1D,CAAC"}
1
+ {"version":3,"file":"email.js","names":[],"sources":["../../../src/fields/builtin/email.ts"],"sourcesContent":["import { keys } from '../../translations/keys'\nimport { labelFor } from '../../translations/server'\nimport { EMAIL_PATTERN } from '../../validation/emailPattern'\nimport { defineFormField } from '../defineFormField'\n\nexport const emailField = defineFormField<'text'>({\n\ttype: 'email',\n\tlabel: keys.fieldTypeEmail,\n\tvalue: 'text',\n\tadvancedConfig: [\n\t\t{\n\t\t\tname: 'autocomplete',\n\t\t\ttype: 'text',\n\t\t\tlabel: labelFor(keys.configAutocomplete),\n\t\t\tadmin: { description: labelFor(keys.configAutocompleteDescription) },\n\t\t},\n\t],\n\tvalidate: ({ value, t }) => {\n\t\tif (value == null || value === '') {\n\t\t\treturn true\n\t\t}\n\t\treturn EMAIL_PATTERN.test(value) ? true : t(keys.validationEmail)\n\t},\n\tformat: ({ value }) => (value == null ? '' : String(value)),\n})\n"],"mappings":";;;;;AAKA,MAAa,aAAa,gBAAwB;CACjD,MAAM;CACN,OAAO,KAAK;CACZ,OAAO;CACP,gBAAgB,CACf;EACC,MAAM;EACN,MAAM;EACN,OAAO,SAAS,KAAK,kBAAkB;EACvC,OAAO,EAAE,aAAa,SAAS,KAAK,6BAA6B,EAAE;CACpE,CACD;CACA,WAAW,EAAE,OAAO,QAAQ;EAC3B,IAAI,SAAS,QAAQ,UAAU,IAC9B,OAAO;EAER,OAAO,cAAc,KAAK,KAAK,IAAI,OAAO,EAAE,KAAK,eAAe;CACjE;CACA,SAAS,EAAE,YAAa,SAAS,OAAO,KAAK,OAAO,KAAK;AAC1D,CAAC"}
@@ -1,4 +1,6 @@
1
1
  import { AnyFormFieldDefinition } from "../types.js";
2
+ import { CalcAllowed } from "../../calc/normalizeCalc.js";
3
+ import { CalcSourceClientMeta } from "./calculation.js";
2
4
  import { RichTextField } from "payload";
3
5
 
4
6
  //#region src/fields/builtin/index.d.ts
@@ -8,9 +10,11 @@ import { RichTextField } from "payload";
8
10
  * richText editor on the message content field (from the plugin's `richText.editor` option). Field
9
11
  * types without content config are shared static definitions. Definitions are authored with precise
10
12
  * value/config generics; the registry stores them erased (config is re-narrowed per matched type at
11
- * execution), hence one cast per built-in, no `any`.
13
+ * execution), hence one cast per built-in, no `any`. `calcAllowed` threads the registered calc
14
+ * extension names into the calculation field's expression validate and editor schema;
15
+ * `calcSources` carries the serializable source metadata the builder UI renders from.
12
16
  */
13
- declare const buildDefaultFieldDefinitions: (localize: boolean, editor?: RichTextField["editor"], uploadMimeTypes?: string[]) => AnyFormFieldDefinition[];
17
+ declare const buildDefaultFieldDefinitions: (localize: boolean, editor?: RichTextField["editor"], uploadMimeTypes?: string[], calcAllowed?: CalcAllowed, calcSources?: CalcSourceClientMeta[]) => AnyFormFieldDefinition[];
14
18
  declare const defaultFieldDefinitions: AnyFormFieldDefinition[];
15
19
  /**
16
20
  * `defaultFieldDefinitions` indexed by `type`, so a single built-in can be spread and tweaked