@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,4 +1,4 @@
1
- import { calculationField } from "./calculation.js";
1
+ import { buildCalculationField } from "./calculation.js";
2
2
  import { checkboxField } from "./checkbox.js";
3
3
  import { consentField } from "./consent.js";
4
4
  import { dateField } from "./date.js";
@@ -17,16 +17,21 @@ import { textareaField } from "./textarea.js";
17
17
  * richText editor on the message content field (from the plugin's `richText.editor` option). Field
18
18
  * types without content config are shared static definitions. Definitions are authored with precise
19
19
  * value/config generics; the registry stores them erased (config is re-narrowed per matched type at
20
- * execution), hence one cast per built-in, no `any`.
20
+ * execution), hence one cast per built-in, no `any`. `calcAllowed` threads the registered calc
21
+ * extension names into the calculation field's expression validate and editor schema;
22
+ * `calcSources` carries the serializable source metadata the builder UI renders from.
21
23
  */
22
- const buildDefaultFieldDefinitions = (localize, editor, uploadMimeTypes) => [
24
+ const buildDefaultFieldDefinitions = (localize, editor, uploadMimeTypes, calcAllowed, calcSources) => [
23
25
  textField,
24
26
  textareaField,
25
27
  emailField,
26
28
  numberField,
27
29
  buildSelectField(localize),
28
30
  checkboxField,
29
- calculationField,
31
+ buildCalculationField(calcAllowed, {
32
+ localize,
33
+ sources: calcSources
34
+ }),
30
35
  consentField,
31
36
  buildFileField(uploadMimeTypes),
32
37
  buildRepeaterField(localize),
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../src/fields/builtin/index.ts"],"sourcesContent":["import type { RichTextField } from 'payload'\nimport type { AnyFormFieldDefinition } from '../types'\nimport { calculationField } from './calculation'\nimport { checkboxField } from './checkbox'\nimport { consentField } from './consent'\nimport { dateField } from './date'\nimport { emailField } from './email'\nimport { buildFileField } from './file'\nimport { buildMessageField } from './message'\nimport { numberField } from './number'\nimport { buildRepeaterField } from './repeater'\nimport { buildSelectField } from './select'\nimport { textField } from './text'\nimport { textareaField } from './textarea'\n\n/**\n * Built-in field definitions with content-bearing config fields (select option labels, repeater add\n * label) carrying `localized: true` when `localize` is true. `editor`, when given, overrides the\n * richText editor on the message content field (from the plugin's `richText.editor` option). Field\n * types without content config are shared static definitions. Definitions are authored with precise\n * value/config generics; the registry stores them erased (config is re-narrowed per matched type at\n * execution), hence one cast per built-in, no `any`.\n */\nexport const buildDefaultFieldDefinitions = (\n\tlocalize: boolean,\n\teditor?: RichTextField['editor'],\n\tuploadMimeTypes?: string[]\n): AnyFormFieldDefinition[] => [\n\ttextField as AnyFormFieldDefinition,\n\ttextareaField as AnyFormFieldDefinition,\n\temailField as AnyFormFieldDefinition,\n\tnumberField as AnyFormFieldDefinition,\n\tbuildSelectField(localize) as AnyFormFieldDefinition,\n\tcheckboxField as AnyFormFieldDefinition,\n\tcalculationField as AnyFormFieldDefinition,\n\tconsentField as AnyFormFieldDefinition,\n\tbuildFileField(uploadMimeTypes) as AnyFormFieldDefinition,\n\tbuildRepeaterField(localize) as AnyFormFieldDefinition,\n\tdateField as AnyFormFieldDefinition,\n\tbuildMessageField(localize, editor) as AnyFormFieldDefinition,\n]\n\nexport const defaultFieldDefinitions: AnyFormFieldDefinition[] = buildDefaultFieldDefinitions(true)\n\n/**\n * `defaultFieldDefinitions` indexed by `type`, so a single built-in can be spread and tweaked\n * without hand-rolling a `.find()`, e.g.\n * `fields: { text: { ...defaultFieldDefinitionsByType.text, validate: myValidate } }`. The\n * `fields` plugin option replaces a built-in of the same `type`; `false` removes it, `true` keeps it.\n * Prebuilt with content localization on; with `localizeContent: false`, derive overrides from\n * `buildDefaultFieldDefinitions(false)` instead so the spread does not reintroduce `localized`.\n */\nexport const defaultFieldDefinitionsByType: Record<string, AnyFormFieldDefinition> =\n\tObject.fromEntries(defaultFieldDefinitions.map((definition) => [definition.type, definition]))\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAuBA,MAAa,gCACZ,UACA,QACA,oBAC8B;CAC9B;CACA;CACA;CACA;CACA,iBAAiB,QAAQ;CACzB;CACA;CACA;CACA,eAAe,eAAe;CAC9B,mBAAmB,QAAQ;CAC3B;CACA,kBAAkB,UAAU,MAAM;AACnC;AAEA,MAAa,0BAAoD,6BAA6B,IAAI;;;;;;;;;AAUlG,MAAa,gCACZ,OAAO,YAAY,wBAAwB,KAAK,eAAe,CAAC,WAAW,MAAM,UAAU,CAAC,CAAC"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../src/fields/builtin/index.ts"],"sourcesContent":["import type { RichTextField } from 'payload'\nimport type { CalcAllowed } from '../../calc/normalizeCalc'\nimport type { AnyFormFieldDefinition } from '../types'\nimport { buildCalculationField, type CalcSourceClientMeta } from './calculation'\nimport { checkboxField } from './checkbox'\nimport { consentField } from './consent'\nimport { dateField } from './date'\nimport { emailField } from './email'\nimport { buildFileField } from './file'\nimport { buildMessageField } from './message'\nimport { numberField } from './number'\nimport { buildRepeaterField } from './repeater'\nimport { buildSelectField } from './select'\nimport { textField } from './text'\nimport { textareaField } from './textarea'\n\n/**\n * Built-in field definitions with content-bearing config fields (select option labels, repeater add\n * label) carrying `localized: true` when `localize` is true. `editor`, when given, overrides the\n * richText editor on the message content field (from the plugin's `richText.editor` option). Field\n * types without content config are shared static definitions. Definitions are authored with precise\n * value/config generics; the registry stores them erased (config is re-narrowed per matched type at\n * execution), hence one cast per built-in, no `any`. `calcAllowed` threads the registered calc\n * extension names into the calculation field's expression validate and editor schema;\n * `calcSources` carries the serializable source metadata the builder UI renders from.\n */\n// biome-ignore lint/complexity/useMaxParams: the documented positional surface (localize, editor, uploadMimeTypes) plus the calc allowed sets and source metadata; an options object would break existing callers\nexport const buildDefaultFieldDefinitions = (\n\tlocalize: boolean,\n\teditor?: RichTextField['editor'],\n\tuploadMimeTypes?: string[],\n\tcalcAllowed?: CalcAllowed,\n\tcalcSources?: CalcSourceClientMeta[]\n): AnyFormFieldDefinition[] => [\n\ttextField as AnyFormFieldDefinition,\n\ttextareaField as AnyFormFieldDefinition,\n\temailField as AnyFormFieldDefinition,\n\tnumberField as AnyFormFieldDefinition,\n\tbuildSelectField(localize) as AnyFormFieldDefinition,\n\tcheckboxField as AnyFormFieldDefinition,\n\tbuildCalculationField(calcAllowed, { localize, sources: calcSources }) as AnyFormFieldDefinition,\n\tconsentField as AnyFormFieldDefinition,\n\tbuildFileField(uploadMimeTypes) as AnyFormFieldDefinition,\n\tbuildRepeaterField(localize) as AnyFormFieldDefinition,\n\tdateField as AnyFormFieldDefinition,\n\tbuildMessageField(localize, editor) as AnyFormFieldDefinition,\n]\n\nexport const defaultFieldDefinitions: AnyFormFieldDefinition[] = buildDefaultFieldDefinitions(true)\n\n/**\n * `defaultFieldDefinitions` indexed by `type`, so a single built-in can be spread and tweaked\n * without hand-rolling a `.find()`, e.g.\n * `fields: { text: { ...defaultFieldDefinitionsByType.text, validate: myValidate } }`. The\n * `fields` plugin option replaces a built-in of the same `type`; `false` removes it, `true` keeps it.\n * Prebuilt with content localization on; with `localizeContent: false`, derive overrides from\n * `buildDefaultFieldDefinitions(false)` instead so the spread does not reintroduce `localized`.\n */\nexport const defaultFieldDefinitionsByType: Record<string, AnyFormFieldDefinition> =\n\tObject.fromEntries(defaultFieldDefinitions.map((definition) => [definition.type, definition]))\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AA2BA,MAAa,gCACZ,UACA,QACA,iBACA,aACA,gBAC8B;CAC9B;CACA;CACA;CACA;CACA,iBAAiB,QAAQ;CACzB;CACA,sBAAsB,aAAa;EAAE;EAAU,SAAS;CAAY,CAAC;CACrE;CACA,eAAe,eAAe;CAC9B,mBAAmB,QAAQ;CAC3B;CACA,kBAAkB,UAAU,MAAM;AACnC;AAEA,MAAa,0BAAoD,6BAA6B,IAAI;;;;;;;;;AAUlG,MAAa,gCACZ,OAAO,YAAY,wBAAwB,KAAK,eAAe,CAAC,WAAW,MAAM,UAAU,CAAC,CAAC"}
@@ -21,7 +21,6 @@ const buildSelectField = (localize) => defineFormField({
21
21
  fields: [{
22
22
  name: "label",
23
23
  type: "text",
24
- required: true,
25
24
  label: labelFor(keys.configOptionLabel),
26
25
  ...localizedIf(localize)
27
26
  }, {
@@ -30,6 +29,26 @@ const buildSelectField = (localize) => defineFormField({
30
29
  required: true,
31
30
  label: labelFor(keys.configOptionValue)
32
31
  }]
32
+ }, {
33
+ name: "display",
34
+ type: "select",
35
+ defaultValue: "dropdown",
36
+ label: labelFor(keys.configSelectDisplay),
37
+ admin: { isClearable: false },
38
+ options: [
39
+ {
40
+ label: labelFor(keys.selectDisplayDropdown),
41
+ value: "dropdown"
42
+ },
43
+ {
44
+ label: labelFor(keys.selectDisplayRadio),
45
+ value: "radio"
46
+ },
47
+ {
48
+ label: labelFor(keys.selectDisplayButtons),
49
+ value: "buttons"
50
+ }
51
+ ]
33
52
  }],
34
53
  validate: ({ value, config, t }) => {
35
54
  if (value == null || value === "") return true;
@@ -1 +1 @@
1
- {"version":3,"file":"select.js","names":[],"sources":["../../../src/fields/builtin/select.ts"],"sourcesContent":["import { keys } from '../../translations/keys'\nimport { labelFor } from '../../translations/server'\nimport { defineFormField } from '../defineFormField'\nimport { localizedIf } from '../localizedIf'\n\ntype SelectOption = { label: string; value: string }\ntype SelectConfig = { options?: SelectOption[] }\n\n/** Option `label` is author-facing content and follows `localize`; `value` is an identifier and never does. */\nexport const buildSelectField = (localize: boolean) =>\n\tdefineFormField<'text', SelectConfig>({\n\t\ttype: 'select',\n\t\tlabel: keys.fieldTypeSelect,\n\t\tvalue: 'text',\n\t\tconditionType: 'select',\n\t\tpollEligible: true,\n\t\tconfig: [\n\t\t\t{\n\t\t\t\tname: 'options',\n\t\t\t\ttype: 'array',\n\t\t\t\tlabel: labelFor(keys.configOptions),\n\t\t\t\tlabels: { singular: labelFor(keys.configOption), plural: labelFor(keys.configOptions) },\n\t\t\t\tfields: [\n\t\t\t\t\t{\n\t\t\t\t\t\tname: 'label',\n\t\t\t\t\t\ttype: 'text',\n\t\t\t\t\t\trequired: true,\n\t\t\t\t\t\tlabel: labelFor(keys.configOptionLabel),\n\t\t\t\t\t\t...localizedIf(localize),\n\t\t\t\t\t},\n\t\t\t\t\t{ name: 'value', type: 'text', required: true, label: labelFor(keys.configOptionValue) },\n\t\t\t\t],\n\t\t\t},\n\t\t],\n\t\tvalidate: ({ value, config, t }) => {\n\t\t\tif (value == null || value === '') {\n\t\t\t\treturn true\n\t\t\t}\n\t\t\tconst options = config.options ?? []\n\t\t\tif (options.length === 0) {\n\t\t\t\treturn true\n\t\t\t}\n\t\t\treturn options.some((option) => option.value === value) ? true : t(keys.validationSelect)\n\t\t},\n\t\tformat: ({ value, optionLabels }) => {\n\t\t\tif (value == null || value === '') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\treturn optionLabels?.[value] ?? String(value)\n\t\t},\n\t})\n\nexport const selectField = buildSelectField(true)\n"],"mappings":";;;;;;AASA,MAAa,oBAAoB,aAChC,gBAAsC;CACrC,MAAM;CACN,OAAO,KAAK;CACZ,OAAO;CACP,eAAe;CACf,cAAc;CACd,QAAQ,CACP;EACC,MAAM;EACN,MAAM;EACN,OAAO,SAAS,KAAK,aAAa;EAClC,QAAQ;GAAE,UAAU,SAAS,KAAK,YAAY;GAAG,QAAQ,SAAS,KAAK,aAAa;EAAE;EACtF,QAAQ,CACP;GACC,MAAM;GACN,MAAM;GACN,UAAU;GACV,OAAO,SAAS,KAAK,iBAAiB;GACtC,GAAG,YAAY,QAAQ;EACxB,GACA;GAAE,MAAM;GAAS,MAAM;GAAQ,UAAU;GAAM,OAAO,SAAS,KAAK,iBAAiB;EAAE,CACxF;CACD,CACD;CACA,WAAW,EAAE,OAAO,QAAQ,QAAQ;EACnC,IAAI,SAAS,QAAQ,UAAU,IAC9B,OAAO;EAER,MAAM,UAAU,OAAO,WAAW,CAAC;EACnC,IAAI,QAAQ,WAAW,GACtB,OAAO;EAER,OAAO,QAAQ,MAAM,WAAW,OAAO,UAAU,KAAK,IAAI,OAAO,EAAE,KAAK,gBAAgB;CACzF;CACA,SAAS,EAAE,OAAO,mBAAmB;EACpC,IAAI,SAAS,QAAQ,UAAU,IAC9B,OAAO;EAER,OAAO,eAAe,UAAU,OAAO,KAAK;CAC7C;AACD,CAAC;AAEyB,iBAAiB,IAAI"}
1
+ {"version":3,"file":"select.js","names":[],"sources":["../../../src/fields/builtin/select.ts"],"sourcesContent":["import { keys } from '../../translations/keys'\nimport { labelFor } from '../../translations/server'\nimport { defineFormField } from '../defineFormField'\nimport { localizedIf } from '../localizedIf'\n\ntype SelectOption = { label?: string; value: string }\ntype SelectConfig = { options?: SelectOption[]; display?: 'dropdown' | 'radio' | 'buttons' }\n\n/** Option `label` is author-facing content and follows `localize`; `value` is an identifier and never does. */\nexport const buildSelectField = (localize: boolean) =>\n\tdefineFormField<'text', SelectConfig>({\n\t\ttype: 'select',\n\t\tlabel: keys.fieldTypeSelect,\n\t\tvalue: 'text',\n\t\tconditionType: 'select',\n\t\tpollEligible: true,\n\t\tconfig: [\n\t\t\t{\n\t\t\t\tname: 'options',\n\t\t\t\ttype: 'array',\n\t\t\t\tlabel: labelFor(keys.configOptions),\n\t\t\t\tlabels: { singular: labelFor(keys.configOption), plural: labelFor(keys.configOptions) },\n\t\t\t\tfields: [\n\t\t\t\t\t{\n\t\t\t\t\t\tname: 'label',\n\t\t\t\t\t\ttype: 'text',\n\t\t\t\t\t\tlabel: labelFor(keys.configOptionLabel),\n\t\t\t\t\t\t...localizedIf(localize),\n\t\t\t\t\t},\n\t\t\t\t\t{ name: 'value', type: 'text', required: true, label: labelFor(keys.configOptionValue) },\n\t\t\t\t],\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: 'display',\n\t\t\t\ttype: 'select',\n\t\t\t\tdefaultValue: 'dropdown',\n\t\t\t\tlabel: labelFor(keys.configSelectDisplay),\n\t\t\t\tadmin: { isClearable: false },\n\t\t\t\toptions: [\n\t\t\t\t\t{ label: labelFor(keys.selectDisplayDropdown), value: 'dropdown' },\n\t\t\t\t\t{ label: labelFor(keys.selectDisplayRadio), value: 'radio' },\n\t\t\t\t\t{ label: labelFor(keys.selectDisplayButtons), value: 'buttons' },\n\t\t\t\t],\n\t\t\t},\n\t\t],\n\t\tvalidate: ({ value, config, t }) => {\n\t\t\tif (value == null || value === '') {\n\t\t\t\treturn true\n\t\t\t}\n\t\t\tconst options = config.options ?? []\n\t\t\tif (options.length === 0) {\n\t\t\t\treturn true\n\t\t\t}\n\t\t\treturn options.some((option) => option.value === value) ? true : t(keys.validationSelect)\n\t\t},\n\t\tformat: ({ value, optionLabels }) => {\n\t\t\tif (value == null || value === '') {\n\t\t\t\treturn ''\n\t\t\t}\n\t\t\treturn optionLabels?.[value] ?? String(value)\n\t\t},\n\t})\n\nexport const selectField = buildSelectField(true)\n"],"mappings":";;;;;;AASA,MAAa,oBAAoB,aAChC,gBAAsC;CACrC,MAAM;CACN,OAAO,KAAK;CACZ,OAAO;CACP,eAAe;CACf,cAAc;CACd,QAAQ,CACP;EACC,MAAM;EACN,MAAM;EACN,OAAO,SAAS,KAAK,aAAa;EAClC,QAAQ;GAAE,UAAU,SAAS,KAAK,YAAY;GAAG,QAAQ,SAAS,KAAK,aAAa;EAAE;EACtF,QAAQ,CACP;GACC,MAAM;GACN,MAAM;GACN,OAAO,SAAS,KAAK,iBAAiB;GACtC,GAAG,YAAY,QAAQ;EACxB,GACA;GAAE,MAAM;GAAS,MAAM;GAAQ,UAAU;GAAM,OAAO,SAAS,KAAK,iBAAiB;EAAE,CACxF;CACD,GACA;EACC,MAAM;EACN,MAAM;EACN,cAAc;EACd,OAAO,SAAS,KAAK,mBAAmB;EACxC,OAAO,EAAE,aAAa,MAAM;EAC5B,SAAS;GACR;IAAE,OAAO,SAAS,KAAK,qBAAqB;IAAG,OAAO;GAAW;GACjE;IAAE,OAAO,SAAS,KAAK,kBAAkB;IAAG,OAAO;GAAQ;GAC3D;IAAE,OAAO,SAAS,KAAK,oBAAoB;IAAG,OAAO;GAAU;EAChE;CACD,CACD;CACA,WAAW,EAAE,OAAO,QAAQ,QAAQ;EACnC,IAAI,SAAS,QAAQ,UAAU,IAC9B,OAAO;EAER,MAAM,UAAU,OAAO,WAAW,CAAC;EACnC,IAAI,QAAQ,WAAW,GACtB,OAAO;EAER,OAAO,QAAQ,MAAM,WAAW,OAAO,UAAU,KAAK,IAAI,OAAO,EAAE,KAAK,gBAAgB;CACzF;CACA,SAAS,EAAE,OAAO,mBAAmB;EACpC,IAAI,SAAS,QAAQ,UAAU,IAC9B,OAAO;EAER,OAAO,eAAe,UAAU,OAAO,KAAK;CAC7C;AACD,CAAC;AAEyB,iBAAiB,IAAI"}
@@ -1,10 +1,17 @@
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/text.ts
4
5
  const textField = defineFormField({
5
6
  type: "text",
6
7
  label: keys.fieldTypeText,
7
8
  value: "text",
9
+ advancedConfig: [{
10
+ name: "autocomplete",
11
+ type: "text",
12
+ label: labelFor(keys.configAutocomplete),
13
+ admin: { description: labelFor(keys.configAutocompleteDescription) }
14
+ }],
8
15
  format: ({ value }) => value == null ? "" : String(value)
9
16
  });
10
17
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"text.js","names":[],"sources":["../../../src/fields/builtin/text.ts"],"sourcesContent":["import { keys } from '../../translations/keys'\nimport { defineFormField } from '../defineFormField'\n\nexport const textField = defineFormField<'text'>({\n\ttype: 'text',\n\tlabel: keys.fieldTypeText,\n\tvalue: 'text',\n\tformat: ({ value }) => (value == null ? '' : String(value)),\n})\n"],"mappings":";;;AAGA,MAAa,YAAY,gBAAwB;CAChD,MAAM;CACN,OAAO,KAAK;CACZ,OAAO;CACP,SAAS,EAAE,YAAa,SAAS,OAAO,KAAK,OAAO,KAAK;AAC1D,CAAC"}
1
+ {"version":3,"file":"text.js","names":[],"sources":["../../../src/fields/builtin/text.ts"],"sourcesContent":["import { keys } from '../../translations/keys'\nimport { labelFor } from '../../translations/server'\nimport { defineFormField } from '../defineFormField'\n\nexport const textField = defineFormField<'text'>({\n\ttype: 'text',\n\tlabel: keys.fieldTypeText,\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\tformat: ({ value }) => (value == null ? '' : String(value)),\n})\n"],"mappings":";;;;AAIA,MAAa,YAAY,gBAAwB;CAChD,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,SAAS,EAAE,YAAa,SAAS,OAAO,KAAK,OAAO,KAAK;AAC1D,CAAC"}
@@ -10,7 +10,7 @@ const instanceOptionsOf = (field) => {
10
10
  if (!Array.isArray(field.options)) return;
11
11
  const options = field.options.filter((option) => typeof option?.value === "string").map((option) => ({
12
12
  value: String(option.value),
13
- label: option.label ?? String(option.value)
13
+ label: option.label?.trim() ? option.label : String(option.value)
14
14
  }));
15
15
  return options.length > 0 ? options : void 0;
16
16
  };
@@ -1 +1 @@
1
- {"version":3,"file":"instanceOptions.js","names":[],"sources":["../../src/fields/instanceOptions.ts"],"sourcesContent":["import type { FormFieldInstance } from '../submissions/types'\n\n/**\n * Normalize a field instance's authored options to `{ value, label }` pairs, dropping entries\n * without a string value and falling back to the value as label. Returns `undefined` when the\n * instance declares no usable options, so callers can distinguish \"not a choice field\" from an\n * empty choice set. Shared by response aggregation and poll outcome resolution so both read the\n * same choice set from a form document.\n */\nexport const instanceOptionsOf = (\n\tfield: FormFieldInstance\n): { value: string; label: string }[] | undefined => {\n\tif (!Array.isArray(field.options)) {\n\t\treturn undefined\n\t}\n\tconst options = (field.options as Array<{ label?: string; value?: string }>)\n\t\t.filter((option) => typeof option?.value === 'string')\n\t\t.map((option) => ({ value: String(option.value), label: option.label ?? String(option.value) }))\n\treturn options.length > 0 ? options : undefined\n}\n"],"mappings":";;;;;;;;AASA,MAAa,qBACZ,UACoD;CACpD,IAAI,CAAC,MAAM,QAAQ,MAAM,OAAO,GAC/B;CAED,MAAM,UAAW,MAAM,QACrB,QAAQ,WAAW,OAAO,QAAQ,UAAU,QAAQ,EACpD,KAAK,YAAY;EAAE,OAAO,OAAO,OAAO,KAAK;EAAG,OAAO,OAAO,SAAS,OAAO,OAAO,KAAK;CAAE,EAAE;CAChG,OAAO,QAAQ,SAAS,IAAI,UAAU,KAAA;AACvC"}
1
+ {"version":3,"file":"instanceOptions.js","names":[],"sources":["../../src/fields/instanceOptions.ts"],"sourcesContent":["import type { FormFieldInstance } from '../submissions/types'\n\n/**\n * Normalize a field instance's authored options to `{ value, label }` pairs, dropping entries\n * without a string value and falling back to the value as label. Returns `undefined` when the\n * instance declares no usable options, so callers can distinguish \"not a choice field\" from an\n * empty choice set. Shared by response aggregation and poll outcome resolution so both read the\n * same choice set from a form document.\n */\nexport const instanceOptionsOf = (\n\tfield: FormFieldInstance\n): { value: string; label: string }[] | undefined => {\n\tif (!Array.isArray(field.options)) {\n\t\treturn undefined\n\t}\n\tconst options = (field.options as Array<{ label?: string; value?: string }>)\n\t\t.filter((option) => typeof option?.value === 'string')\n\t\t.map((option) => ({\n\t\t\tvalue: String(option.value),\n\t\t\tlabel: option.label?.trim() ? option.label : String(option.value),\n\t\t}))\n\treturn options.length > 0 ? options : undefined\n}\n"],"mappings":";;;;;;;;AASA,MAAa,qBACZ,UACoD;CACpD,IAAI,CAAC,MAAM,QAAQ,MAAM,OAAO,GAC/B;CAED,MAAM,UAAW,MAAM,QACrB,QAAQ,WAAW,OAAO,QAAQ,UAAU,QAAQ,EACpD,KAAK,YAAY;EACjB,OAAO,OAAO,OAAO,KAAK;EAC1B,OAAO,OAAO,OAAO,KAAK,IAAI,OAAO,QAAQ,OAAO,OAAO,KAAK;CACjE,EAAE;CACH,OAAO,QAAQ,SAAS,IAAI,UAAU,KAAA;AACvC"}
@@ -65,7 +65,6 @@ const baseSharedFieldConfig = (localize) => [
65
65
  fields: [{
66
66
  name: "width",
67
67
  type: "select",
68
- required: true,
69
68
  defaultValue: "full",
70
69
  label: labelFor(keys.configWidth),
71
70
  admin: {
@@ -74,19 +73,19 @@ const baseSharedFieldConfig = (localize) => [
74
73
  },
75
74
  options: [
76
75
  {
77
- label: "Full",
76
+ label: labelFor(keys.widthFull),
78
77
  value: "full"
79
78
  },
80
79
  {
81
- label: "Half",
80
+ label: labelFor(keys.widthHalf),
82
81
  value: "half"
83
82
  },
84
83
  {
85
- label: "Third",
84
+ label: labelFor(keys.widthThird),
86
85
  value: "third"
87
86
  },
88
87
  {
89
- label: "Two thirds",
88
+ label: labelFor(keys.widthTwoThirds),
90
89
  value: "twoThirds"
91
90
  }
92
91
  ]
@@ -124,7 +123,7 @@ const sharedFieldConfig = (localize = true, omitShared = []) => {
124
123
  omit.delete("name");
125
124
  return applyOmissions(baseSharedFieldConfig(localize), omit);
126
125
  };
127
- const fieldBlockTabs = ({ conditionTypes, typeConfig, validations, localize = true, omitShared }) => ({
126
+ const fieldBlockTabs = ({ conditionTypes, typeConfig, validations, localize = true, omitShared, advancedConfig }) => ({
128
127
  type: "tabs",
129
128
  tabs: [
130
129
  {
@@ -137,11 +136,16 @@ const fieldBlockTabs = ({ conditionTypes, typeConfig, validations, localize = tr
137
136
  },
138
137
  {
139
138
  label: labelFor(keys.tabAdvanced),
140
- fields: [conditionField("visibleWhen", keys.configVisibleWhen, conditionTypes), {
141
- name: "hidden",
142
- type: "checkbox",
143
- label: labelFor(keys.configHidden)
144
- }]
139
+ fields: [
140
+ conditionField("visibleWhen", keys.configVisibleWhen, conditionTypes),
141
+ {
142
+ name: "hidden",
143
+ type: "checkbox",
144
+ label: labelFor(keys.configHidden),
145
+ admin: { description: labelFor(keys.configHiddenDescription) }
146
+ },
147
+ ...advancedConfig ?? []
148
+ ]
145
149
  }
146
150
  ]
147
151
  });
@@ -1 +1 @@
1
- {"version":3,"file":"sharedConfig.js","names":[],"sources":["../../src/fields/sharedConfig.ts"],"sourcesContent":["import type { Field } from 'payload'\nimport type { ConditionFieldType } from '../conditions/fieldTypes'\nimport { keys } from '../translations/keys'\nimport { labelFor } from '../translations/server'\nimport { localizedIf } from './localizedIf'\nimport type { OmittableSharedField } from './types'\n\nconst CONDITION_FIELD_REF = '@10x-media/form-builder/client#FormConditionField'\n\nconst conditionField = (\n\tname: 'visibleWhen' | 'validateWhen',\n\tlabelKey: string,\n\tconditionTypes: Record<string, ConditionFieldType>\n): Field => ({\n\tname,\n\ttype: 'json',\n\tlabel: labelFor(labelKey),\n\tadmin: {\n\t\tcomponents: {\n\t\t\tField: { path: CONDITION_FIELD_REF, clientProps: { conditionTypes } },\n\t\t},\n\t},\n})\n\n/**\n * Let a lone row survivor span its row: Payload styles a row child with no `admin.width` as\n * `flex: 1 1 auto` (see `mergeFieldStyles`), so dropping the key is the \"fill the row\" signal.\n * Without this, omitting one half of a 50/50 row would strand the other half at 50%.\n */\nconst spanRow = <T extends Field>(field: T): T => {\n\tif (field.admin?.width === undefined) {\n\t\treturn field\n\t}\n\tconst { width: _width, ...admin } = field.admin\n\treturn { ...field, admin }\n}\n\n/**\n * Drop the shared fields a type never uses, descending into the presentational rows so a nested\n * field is reachable. An emptied row is dropped whole; a row pruned down to one field lets that\n * field span it. A row that lost nothing is left exactly as authored, single-child rows included.\n */\nconst applyOmissions = (fields: Field[], omit: ReadonlySet<string>): Field[] =>\n\tfields.flatMap((field): Field[] => {\n\t\tif (field.type === 'row') {\n\t\t\tconst kept = applyOmissions(field.fields, omit)\n\t\t\tif (kept.length === 0) {\n\t\t\t\treturn []\n\t\t\t}\n\t\t\tconst strandsSurvivor = kept.length === 1 && kept.length < field.fields.length\n\t\t\treturn [{ ...field, fields: strandsSurvivor ? kept.map(spanRow) : kept }]\n\t\t}\n\t\treturn 'name' in field && omit.has(field.name) ? [] : [field]\n\t})\n\n/** The full shared config, before a type's `omitShared` prunes it. See `sharedFieldConfig`. */\nconst baseSharedFieldConfig = (localize: boolean): Field[] => [\n\t{\n\t\ttype: 'row',\n\t\tfields: [\n\t\t\t{\n\t\t\t\tname: 'name',\n\t\t\t\ttype: 'text',\n\t\t\t\trequired: true,\n\t\t\t\tlabel: labelFor(keys.configName),\n\t\t\t\tadmin: { width: '50%' },\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: 'label',\n\t\t\t\ttype: 'text',\n\t\t\t\tlabel: labelFor(keys.configLabel),\n\t\t\t\tadmin: { width: '50%' },\n\t\t\t\t...localizedIf(localize),\n\t\t\t},\n\t\t],\n\t},\n\t{\n\t\ttype: 'row',\n\t\tfields: [\n\t\t\t{\n\t\t\t\tname: 'width',\n\t\t\t\ttype: 'select',\n\t\t\t\trequired: true,\n\t\t\t\tdefaultValue: 'full',\n\t\t\t\tlabel: labelFor(keys.configWidth),\n\t\t\t\tadmin: { width: '50%', isClearable: false },\n\t\t\t\toptions: [\n\t\t\t\t\t{ label: 'Full', value: 'full' },\n\t\t\t\t\t{ label: 'Half', value: 'half' },\n\t\t\t\t\t{ label: 'Third', value: 'third' },\n\t\t\t\t\t{ label: 'Two thirds', value: 'twoThirds' },\n\t\t\t\t],\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: 'placeholder',\n\t\t\t\ttype: 'text',\n\t\t\t\tlabel: labelFor(keys.configPlaceholder),\n\t\t\t\tadmin: { width: '50%' },\n\t\t\t\t...localizedIf(localize),\n\t\t\t},\n\t\t],\n\t},\n\t{\n\t\tname: 'description',\n\t\ttype: 'textarea',\n\t\tlabel: labelFor(keys.configDescription),\n\t\t...localizedIf(localize),\n\t},\n\t{ name: 'required', type: 'checkbox', label: labelFor(keys.configRequired) },\n]\n\n/**\n * Config every field instance carries regardless of type. `name` is the machine key written into\n * submissions; `width` is stored for the layout grid. Field types add their own `config` after\n * these inside the Field tab (see `fieldBlockTabs`) and drop the ones they never read via\n * `omitShared`, so an author is never offered a setting the renderer ignores. Content-bearing\n * fields (`label`, `placeholder`, `description`) are localized unless `localize` is false;\n * identifiers and behavior flags never are. The rows are presentational only (unnamed, data paths\n * stay flat); `required` sits last, under `description`, per the admin layout.\n */\nexport const sharedFieldConfig = (\n\tlocalize = true,\n\tomitShared: readonly OmittableSharedField[] = []\n): Field[] => {\n\tconst omit = new Set<string>(omitShared)\n\t// `name` is the storage key every read and write path gates on (`isNamedField`). The type\n\t// already excludes it; dropping it here too keeps an untyped caller from breaking storage.\n\tomit.delete('name')\n\treturn applyOmissions(baseSharedFieldConfig(localize), omit)\n}\n\n/**\n * The single field of every field block: unnamed tabs (presentational only, data paths stay flat).\n * Field tab holds the shared basics plus the type's own config; Validation holds the rule blocks and\n * `validateWhen`; Advanced holds `visibleWhen` and `hidden`. `visibleWhen`/`validateWhen` store a\n * canonical Payload `Where`, edited by the native condition builder.\n */\ntype FieldBlockTabsArgs = {\n\tconditionTypes: Record<string, ConditionFieldType>\n\ttypeConfig: Field[]\n\tvalidations: Field\n\tlocalize?: boolean\n\t/** See `FormFieldDefinition.omitShared`: shared basics this type never uses, left unauthored. */\n\tomitShared?: readonly OmittableSharedField[]\n}\n\nexport const fieldBlockTabs = ({\n\tconditionTypes,\n\ttypeConfig,\n\tvalidations,\n\tlocalize = true,\n\tomitShared,\n}: FieldBlockTabsArgs): Field => ({\n\ttype: 'tabs',\n\ttabs: [\n\t\t{\n\t\t\tlabel: labelFor(keys.tabField),\n\t\t\tfields: [...sharedFieldConfig(localize, omitShared), ...typeConfig],\n\t\t},\n\t\t{\n\t\t\tlabel: labelFor(keys.tabValidation),\n\t\t\tfields: [\n\t\t\t\tvalidations,\n\t\t\t\tconditionField('validateWhen', keys.configValidateWhen, conditionTypes),\n\t\t\t],\n\t\t},\n\t\t{\n\t\t\tlabel: labelFor(keys.tabAdvanced),\n\t\t\tfields: [\n\t\t\t\tconditionField('visibleWhen', keys.configVisibleWhen, conditionTypes),\n\t\t\t\t{ name: 'hidden', type: 'checkbox', label: labelFor(keys.configHidden) },\n\t\t\t],\n\t\t},\n\t],\n})\n"],"mappings":"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"}
1
+ {"version":3,"file":"sharedConfig.js","names":[],"sources":["../../src/fields/sharedConfig.ts"],"sourcesContent":["import type { Field } from 'payload'\nimport type { ConditionFieldType } from '../conditions/fieldTypes'\nimport { keys } from '../translations/keys'\nimport { labelFor } from '../translations/server'\nimport { localizedIf } from './localizedIf'\nimport type { OmittableSharedField } from './types'\n\nconst CONDITION_FIELD_REF = '@10x-media/form-builder/client#FormConditionField'\n\nconst conditionField = (\n\tname: 'visibleWhen' | 'validateWhen',\n\tlabelKey: string,\n\tconditionTypes: Record<string, ConditionFieldType>\n): Field => ({\n\tname,\n\ttype: 'json',\n\tlabel: labelFor(labelKey),\n\tadmin: {\n\t\tcomponents: {\n\t\t\tField: { path: CONDITION_FIELD_REF, clientProps: { conditionTypes } },\n\t\t},\n\t},\n})\n\n/**\n * Let a lone row survivor span its row: Payload styles a row child with no `admin.width` as\n * `flex: 1 1 auto` (see `mergeFieldStyles`), so dropping the key is the \"fill the row\" signal.\n * Without this, omitting one half of a 50/50 row would strand the other half at 50%.\n */\nconst spanRow = <T extends Field>(field: T): T => {\n\tif (field.admin?.width === undefined) {\n\t\treturn field\n\t}\n\tconst { width: _width, ...admin } = field.admin\n\treturn { ...field, admin }\n}\n\n/**\n * Drop the shared fields a type never uses, descending into the presentational rows so a nested\n * field is reachable. An emptied row is dropped whole; a row pruned down to one field lets that\n * field span it. A row that lost nothing is left exactly as authored, single-child rows included.\n */\nconst applyOmissions = (fields: Field[], omit: ReadonlySet<string>): Field[] =>\n\tfields.flatMap((field): Field[] => {\n\t\tif (field.type === 'row') {\n\t\t\tconst kept = applyOmissions(field.fields, omit)\n\t\t\tif (kept.length === 0) {\n\t\t\t\treturn []\n\t\t\t}\n\t\t\tconst strandsSurvivor = kept.length === 1 && kept.length < field.fields.length\n\t\t\treturn [{ ...field, fields: strandsSurvivor ? kept.map(spanRow) : kept }]\n\t\t}\n\t\treturn 'name' in field && omit.has(field.name) ? [] : [field]\n\t})\n\n/** The full shared config, before a type's `omitShared` prunes it. See `sharedFieldConfig`. */\nconst baseSharedFieldConfig = (localize: boolean): Field[] => [\n\t{\n\t\ttype: 'row',\n\t\tfields: [\n\t\t\t{\n\t\t\t\tname: 'name',\n\t\t\t\ttype: 'text',\n\t\t\t\trequired: true,\n\t\t\t\tlabel: labelFor(keys.configName),\n\t\t\t\tadmin: { width: '50%' },\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: 'label',\n\t\t\t\ttype: 'text',\n\t\t\t\tlabel: labelFor(keys.configLabel),\n\t\t\t\tadmin: { width: '50%' },\n\t\t\t\t...localizedIf(localize),\n\t\t\t},\n\t\t],\n\t},\n\t{\n\t\ttype: 'row',\n\t\tfields: [\n\t\t\t{\n\t\t\t\tname: 'width',\n\t\t\t\ttype: 'select',\n\t\t\t\tdefaultValue: 'full',\n\t\t\t\tlabel: labelFor(keys.configWidth),\n\t\t\t\tadmin: { width: '50%', isClearable: false },\n\t\t\t\toptions: [\n\t\t\t\t\t{ label: labelFor(keys.widthFull), value: 'full' },\n\t\t\t\t\t{ label: labelFor(keys.widthHalf), value: 'half' },\n\t\t\t\t\t{ label: labelFor(keys.widthThird), value: 'third' },\n\t\t\t\t\t{ label: labelFor(keys.widthTwoThirds), value: 'twoThirds' },\n\t\t\t\t],\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: 'placeholder',\n\t\t\t\ttype: 'text',\n\t\t\t\tlabel: labelFor(keys.configPlaceholder),\n\t\t\t\tadmin: { width: '50%' },\n\t\t\t\t...localizedIf(localize),\n\t\t\t},\n\t\t],\n\t},\n\t{\n\t\tname: 'description',\n\t\ttype: 'textarea',\n\t\tlabel: labelFor(keys.configDescription),\n\t\t...localizedIf(localize),\n\t},\n\t{ name: 'required', type: 'checkbox', label: labelFor(keys.configRequired) },\n]\n\n/**\n * Config every field instance carries regardless of type. `name` is the machine key written into\n * submissions; `width` is stored for the layout grid. Field types add their own `config` after\n * these inside the Field tab (see `fieldBlockTabs`) and drop the ones they never read via\n * `omitShared`, so an author is never offered a setting the renderer ignores. Content-bearing\n * fields (`label`, `placeholder`, `description`) are localized unless `localize` is false;\n * identifiers and behavior flags never are. The rows are presentational only (unnamed, data paths\n * stay flat); `required` sits last, under `description`, per the admin layout.\n */\nexport const sharedFieldConfig = (\n\tlocalize = true,\n\tomitShared: readonly OmittableSharedField[] = []\n): Field[] => {\n\tconst omit = new Set<string>(omitShared)\n\t// `name` is the storage key every read and write path gates on (`isNamedField`). The type\n\t// already excludes it; dropping it here too keeps an untyped caller from breaking storage.\n\tomit.delete('name')\n\treturn applyOmissions(baseSharedFieldConfig(localize), omit)\n}\n\n/**\n * The single field of every field block: unnamed tabs (presentational only, data paths stay flat).\n * Field tab holds the shared basics plus the type's own config; Validation holds the rule blocks and\n * `validateWhen`; Advanced holds `visibleWhen` and `hidden`. `visibleWhen`/`validateWhen` store a\n * canonical Payload `Where`, edited by the native condition builder.\n */\ntype FieldBlockTabsArgs = {\n\tconditionTypes: Record<string, ConditionFieldType>\n\ttypeConfig: Field[]\n\tvalidations: Field\n\tlocalize?: boolean\n\t/** See `FormFieldDefinition.omitShared`: shared basics this type never uses, left unauthored. */\n\tomitShared?: readonly OmittableSharedField[]\n\t/** See `FormFieldDefinition.advancedConfig`: extra fields appended to the Advanced tab. */\n\tadvancedConfig?: Field[]\n}\n\nexport const fieldBlockTabs = ({\n\tconditionTypes,\n\ttypeConfig,\n\tvalidations,\n\tlocalize = true,\n\tomitShared,\n\tadvancedConfig,\n}: FieldBlockTabsArgs): Field => ({\n\ttype: 'tabs',\n\ttabs: [\n\t\t{\n\t\t\tlabel: labelFor(keys.tabField),\n\t\t\tfields: [...sharedFieldConfig(localize, omitShared), ...typeConfig],\n\t\t},\n\t\t{\n\t\t\tlabel: labelFor(keys.tabValidation),\n\t\t\tfields: [\n\t\t\t\tvalidations,\n\t\t\t\tconditionField('validateWhen', keys.configValidateWhen, conditionTypes),\n\t\t\t],\n\t\t},\n\t\t{\n\t\t\tlabel: labelFor(keys.tabAdvanced),\n\t\t\tfields: [\n\t\t\t\tconditionField('visibleWhen', keys.configVisibleWhen, conditionTypes),\n\t\t\t\t{\n\t\t\t\t\tname: 'hidden',\n\t\t\t\t\ttype: 'checkbox',\n\t\t\t\t\tlabel: labelFor(keys.configHidden),\n\t\t\t\t\tadmin: { description: labelFor(keys.configHiddenDescription) },\n\t\t\t\t},\n\t\t\t\t...(advancedConfig ?? []),\n\t\t\t],\n\t\t},\n\t],\n})\n"],"mappings":"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"}
@@ -1,7 +1,7 @@
1
+ import { ConditionFieldType } from "../conditions/fieldTypes.js";
1
2
  import { PollOption } from "../poll/definePollOptionSource.js";
2
3
  import { FormFieldInstance } from "../submissions/types.js";
3
4
  import { FileRef } from "../uploads/types.js";
4
- import { ConditionFieldType } from "../conditions/fieldTypes.js";
5
5
  import { Field, Payload, PayloadRequest } from "payload";
6
6
  import { StandardSchemaV1 } from "@standard-schema/spec";
7
7
 
@@ -70,6 +70,11 @@ type FormFieldDefinition<K extends FormFieldValueKind = FormFieldValueKind, TCon
70
70
  label: string;
71
71
  value: K;
72
72
  config?: Field[];
73
+ /**
74
+ * Extra per-type fields for the Advanced tab, after `visibleWhen`/`hidden`. Lets a type add
75
+ * behavior settings (e.g. `autocomplete`) without crowding the Field tab.
76
+ */
77
+ advancedConfig?: Field[];
73
78
  validate?: FormFieldValidate<K, TConfig>;
74
79
  format?: FormFieldFormat<K, TConfig>;
75
80
  Field?: string;
@@ -133,7 +138,8 @@ type AnyFormFieldDefinition = {
133
138
  type: string;
134
139
  label: string;
135
140
  value: FormFieldValueKind;
136
- config?: Field[];
141
+ config?: Field[]; /** See `FormFieldDefinition.advancedConfig`: extra per-type fields for the Advanced tab. */
142
+ advancedConfig?: Field[];
137
143
  validate?: AnyFormFieldValidate;
138
144
  format?: AnyFormFieldFormat;
139
145
  Field?: string; /** See `FormFieldDefinition.blockLabel`: import-map ref for a custom block row Label. */
@@ -1,4 +1,5 @@
1
1
  import { PollOption } from "../poll/definePollOptionSource.js";
2
+ import { CalcResolved } from "../calc/evaluate.js";
2
3
  import { ConsentStatements } from "../consent/resolveConsentStatements.js";
3
4
  import { FormDocument } from "./types.js";
4
5
 
@@ -96,6 +97,12 @@ declare function toFormDocument(form: {
96
97
  * An explicit `options.consentStatements` takes precedence when both are present.
97
98
  */
98
99
  consentStatements?: ConsentStatements;
100
+ /**
101
+ * Calc source values resolved onto the doc by the plugin's forms `afterRead` hook (when calc
102
+ * sources are registered and used); passed through so the client's live preview computes with
103
+ * real values. `functions` can never ride a document, hence the Pick.
104
+ */
105
+ calcResolved?: Pick<CalcResolved, 'sources' | 'weights'>;
99
106
  }, options?: ToFormDocumentOptions): FormDocument;
100
107
  //#endregion
101
108
  export { ToFormDocumentOptions, toFormDocument };
@@ -78,7 +78,8 @@ function toFormDocument(form, options) {
78
78
  title: form.title ?? void 0,
79
79
  multistep: form.multistep === true,
80
80
  pollEnabled: form.pollEnabled === true,
81
- poll
81
+ poll,
82
+ calcResolved: form.calcResolved
82
83
  };
83
84
  }
84
85
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"toFormDocument.js","names":[],"sources":["../../src/form/toFormDocument.ts"],"sourcesContent":["import { applyConsentStatements } from '../consent/applyConsentStatements'\nimport type { ConsentStatements } from '../consent/resolveConsentStatements'\nimport type { FormFlow } from '../flow/types'\nimport { applyPollOptions } from '../poll/applyPollOptions'\nimport type { PollOption } from '../poll/definePollOptionSource'\nimport type { FormFieldInstance } from '../submissions/types'\nimport type { FormButtonSettings, FormDocument, FormResponseSettings } from './types'\n\nexport type ToFormDocumentOptions = {\n\t/**\n\t * Source-resolved poll options (from `resolvePollOptions`), injected as the options of the\n\t * field instance named by the form's `poll.resultsField` so the client renders the host's\n\t * current choices instead of hand-authored ones.\n\t */\n\tpollOptions?: PollOption[]\n\t/**\n\t * Source-resolved consent statements (from `resolveConsentStatements`), injected into the\n\t * consent field instances they name. A form stores only a source id, so without these its\n\t * consent fields render with no statement at all.\n\t */\n\tconsentStatements?: ConsentStatements\n\t/**\n\t * Resolve an internal redirect `reference` to a same-site URL. Called only when\n\t * `response.type === 'redirect'`, a `reference` is present, and no `redirect.url` is set. Keep it\n\t * sync: operate on the already-loaded (populated) reference, since resolving a Doc to a URL is host\n\t * routing knowledge the plugin cannot supply. The result is written to `redirect.url`, so `<Form>`\n\t * navigates with no client change.\n\t */\n\tresolveRedirect?: (reference: {\n\t\trelationTo: string\n\t\tvalue: number | string | object\n\t}) => string | null | undefined\n}\n\n/**\n * Reassemble the client button labels from the document's top-level `submitLabel`/`prevLabel`/\n * `nextLabel` fields, keeping only non-empty strings (mirroring the client's own `storedLabel`\n * fallback). Returns `undefined` when the author set no label, so the client uses its defaults.\n */\nconst buttonSettingsOf = (form: {\n\tsubmitLabel?: string | null\n\tprevLabel?: string | null\n\tnextLabel?: string | null\n}): FormButtonSettings | undefined => {\n\tconst label = (value: unknown): string | undefined =>\n\t\ttypeof value === 'string' && value.length > 0 ? value : undefined\n\tconst settings: FormButtonSettings = {}\n\tconst submitLabel = label(form.submitLabel)\n\tconst prevLabel = label(form.prevLabel)\n\tconst nextLabel = label(form.nextLabel)\n\tif (submitLabel !== undefined) settings.submitLabel = submitLabel\n\tif (prevLabel !== undefined) settings.prevLabel = prevLabel\n\tif (nextLabel !== undefined) settings.nextLabel = nextLabel\n\treturn Object.keys(settings).length > 0 ? settings : undefined\n}\n\n/**\n * Narrows a Payload-generated form document (from `getPayload().findByID()` or `fetch`) to\n * `FormDocument` without an unsafe `as` cast. Handles the small structural mismatches between\n * the auto-generated collection types and what `<Form>` expects:\n * - `fields` may be a typed blocks-union array or null; normalized to `FormFieldInstance[]`\n * (nameless bare rows, e.g. message blocks, pass through with their row `id` intact)\n * - `flow` is stored as opaque JSON; typed as `FormFlow | undefined`\n * - `response` may be null; coerced to `undefined`, otherwise passed through wholesale, which\n * includes `response.redirect.reference` (present only when the plugin's `redirectRelationships`\n * option is set): `value` may be a bare id (`depth: 0`) or a populated document, and the host\n * resolves it to a URL either by writing `redirect.url` or by passing `options.resolveRedirect`\n * - the button labels (`submitLabel`/`prevLabel`/`nextLabel`) live at the document root now (there\n * is no `buttons` group); the non-empty ones are reassembled into `FormDocument.buttons`\n * - `title` may be null; coerced to `undefined`\n * - `multistep`/`pollEnabled` are the two top-level form-type flags, coerced to strict booleans\n * - `poll` may be null; coerced to `undefined` (`resultsField`, `optionSource`, and\n * `sourceConfig` are dropped: server-side only; `outcome` passes through `winningValues` only)\n *\n * Unknown keys survive on `response` but not on `poll`, which is deliberate rather than incidental.\n * `response` is a visitor-facing group a host is meant to extend (`overrides.forms.fields`) and read\n * back off `FormDocument` in custom chrome, so it is cast wholesale. `poll` is plugin-owned config\n * that is split between\n * client-safe lifecycle state and server-only members, so it is rebuilt from an allowlist: a\n * passthrough would ship whatever a host put in `sourceConfig` (domain config, ids, credentials)\n * to every anonymous visitor. Adding a client-visible poll member means naming it here.\n *\n * Pure and framework-agnostic (no 'use client'): safe to call from a Server Component or any\n * other server-side code before handing the result to the client `<Form>`.\n */\nexport function toFormDocument(\n\tform: {\n\t\tid: number | string\n\t\tfields?: { blockType: string; name?: string; [key: string]: unknown }[] | null\n\t\tflow?: unknown\n\t\tresponse?: {\n\t\t\ttype?: string | null\n\t\t\tmessage?: unknown\n\t\t\tredirect?: {\n\t\t\t\turl?: string | null\n\t\t\t\treference?: { relationTo?: string | null; value?: number | string | object | null } | null\n\t\t\t} | null\n\t\t} | null\n\t\tsubmitLabel?: string | null\n\t\tprevLabel?: string | null\n\t\tnextLabel?: string | null\n\t\ttitle?: string | null\n\t\tmultistep?: boolean | null\n\t\tpollEnabled?: boolean | null\n\t\tpoll?: {\n\t\t\tresultsField?: string | null\n\t\t\tresultsVisibility?: string | null\n\t\t\tclosesAt?: string | null\n\t\t\toutcome?: { winningValues?: (string | null)[] | null } | null\n\t\t} | null\n\t\t/**\n\t\t * Consent statements resolved onto the doc by the plugin's forms `afterRead` hook (when\n\t\t * `consent.sources` is set), so consent renders on any fetch path (modal/client, not just RSC).\n\t\t * An explicit `options.consentStatements` takes precedence when both are present.\n\t\t */\n\t\tconsentStatements?: ConsentStatements\n\t},\n\toptions?: ToFormDocumentOptions\n): FormDocument {\n\tconst rawWinningValues = form.poll?.outcome?.winningValues\n\tconst winningValues = Array.isArray(rawWinningValues)\n\t\t? rawWinningValues.filter(\n\t\t\t\t(value): value is string => typeof value === 'string' && value.length > 0\n\t\t\t)\n\t\t: []\n\tconst poll = form.poll\n\t\t? {\n\t\t\t\tresultsVisibility: (form.poll.resultsVisibility ?? undefined) as\n\t\t\t\t\t| 'afterVote'\n\t\t\t\t\t| 'afterClose'\n\t\t\t\t\t| undefined,\n\t\t\t\tclosesAt: form.poll.closesAt ?? undefined,\n\t\t\t\t...(winningValues.length > 0 ? { outcome: { winningValues } } : {}),\n\t\t\t}\n\t\t: undefined\n\tlet fields = (form.fields ?? []) as FormFieldInstance[]\n\tif (options?.pollOptions) {\n\t\tfields = applyPollOptions(fields, form.poll?.resultsField, options.pollOptions)\n\t}\n\tconst consentStatements = options?.consentStatements ?? form.consentStatements\n\tif (consentStatements) {\n\t\tfields = applyConsentStatements(fields, consentStatements)\n\t}\n\tlet response = (form.response as FormResponseSettings | null | undefined) ?? undefined\n\t// A host that passes `resolveRedirect` gets internal references turned into `redirect.url` (all\n\t// `<Form>` navigates by), but only when the author set no explicit url. Non-mutating: clone the group.\n\tif (\n\t\toptions?.resolveRedirect &&\n\t\tresponse?.type === 'redirect' &&\n\t\tresponse.redirect?.reference &&\n\t\t!response.redirect.url\n\t) {\n\t\tconst url = options.resolveRedirect(response.redirect.reference)\n\t\tif (url) {\n\t\t\tresponse = { ...response, redirect: { ...response.redirect, url } }\n\t\t}\n\t}\n\treturn {\n\t\tid: form.id,\n\t\tfields,\n\t\tflow: form.flow as FormFlow | undefined,\n\t\tresponse,\n\t\tbuttons: buttonSettingsOf(form),\n\t\ttitle: form.title ?? undefined,\n\t\tmultistep: form.multistep === true,\n\t\tpollEnabled: form.pollEnabled === true,\n\t\tpoll,\n\t}\n}\n"],"mappings":";;;;;;;;AAuCA,MAAM,oBAAoB,SAIY;CACrC,MAAM,SAAS,UACd,OAAO,UAAU,YAAY,MAAM,SAAS,IAAI,QAAQ,KAAA;CACzD,MAAM,WAA+B,CAAC;CACtC,MAAM,cAAc,MAAM,KAAK,WAAW;CAC1C,MAAM,YAAY,MAAM,KAAK,SAAS;CACtC,MAAM,YAAY,MAAM,KAAK,SAAS;CACtC,IAAI,gBAAgB,KAAA,GAAW,SAAS,cAAc;CACtD,IAAI,cAAc,KAAA,GAAW,SAAS,YAAY;CAClD,IAAI,cAAc,KAAA,GAAW,SAAS,YAAY;CAClD,OAAO,OAAO,KAAK,QAAQ,EAAE,SAAS,IAAI,WAAW,KAAA;AACtD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+BA,SAAgB,eACf,MA+BA,SACe;CACf,MAAM,mBAAmB,KAAK,MAAM,SAAS;CAC7C,MAAM,gBAAgB,MAAM,QAAQ,gBAAgB,IACjD,iBAAiB,QAChB,UAA2B,OAAO,UAAU,YAAY,MAAM,SAAS,CACzE,IACC,CAAC;CACJ,MAAM,OAAO,KAAK,OACf;EACA,mBAAoB,KAAK,KAAK,qBAAqB,KAAA;EAInD,UAAU,KAAK,KAAK,YAAY,KAAA;EAChC,GAAI,cAAc,SAAS,IAAI,EAAE,SAAS,EAAE,cAAc,EAAE,IAAI,CAAC;CAClE,IACC,KAAA;CACH,IAAI,SAAU,KAAK,UAAU,CAAC;CAC9B,IAAI,SAAS,aACZ,SAAS,iBAAiB,QAAQ,KAAK,MAAM,cAAc,QAAQ,WAAW;CAE/E,MAAM,oBAAoB,SAAS,qBAAqB,KAAK;CAC7D,IAAI,mBACH,SAAS,uBAAuB,QAAQ,iBAAiB;CAE1D,IAAI,WAAY,KAAK,YAAwD,KAAA;CAG7E,IACC,SAAS,mBACT,UAAU,SAAS,cACnB,SAAS,UAAU,aACnB,CAAC,SAAS,SAAS,KAClB;EACD,MAAM,MAAM,QAAQ,gBAAgB,SAAS,SAAS,SAAS;EAC/D,IAAI,KACH,WAAW;GAAE,GAAG;GAAU,UAAU;IAAE,GAAG,SAAS;IAAU;GAAI;EAAE;CAEpE;CACA,OAAO;EACN,IAAI,KAAK;EACT;EACA,MAAM,KAAK;EACX;EACA,SAAS,iBAAiB,IAAI;EAC9B,OAAO,KAAK,SAAS,KAAA;EACrB,WAAW,KAAK,cAAc;EAC9B,aAAa,KAAK,gBAAgB;EAClC;CACD;AACD"}
1
+ {"version":3,"file":"toFormDocument.js","names":[],"sources":["../../src/form/toFormDocument.ts"],"sourcesContent":["import type { CalcResolved } from '../calc/evaluate'\nimport { applyConsentStatements } from '../consent/applyConsentStatements'\nimport type { ConsentStatements } from '../consent/resolveConsentStatements'\nimport type { FormFlow } from '../flow/types'\nimport { applyPollOptions } from '../poll/applyPollOptions'\nimport type { PollOption } from '../poll/definePollOptionSource'\nimport type { FormFieldInstance } from '../submissions/types'\nimport type { FormButtonSettings, FormDocument, FormResponseSettings } from './types'\n\nexport type ToFormDocumentOptions = {\n\t/**\n\t * Source-resolved poll options (from `resolvePollOptions`), injected as the options of the\n\t * field instance named by the form's `poll.resultsField` so the client renders the host's\n\t * current choices instead of hand-authored ones.\n\t */\n\tpollOptions?: PollOption[]\n\t/**\n\t * Source-resolved consent statements (from `resolveConsentStatements`), injected into the\n\t * consent field instances they name. A form stores only a source id, so without these its\n\t * consent fields render with no statement at all.\n\t */\n\tconsentStatements?: ConsentStatements\n\t/**\n\t * Resolve an internal redirect `reference` to a same-site URL. Called only when\n\t * `response.type === 'redirect'`, a `reference` is present, and no `redirect.url` is set. Keep it\n\t * sync: operate on the already-loaded (populated) reference, since resolving a Doc to a URL is host\n\t * routing knowledge the plugin cannot supply. The result is written to `redirect.url`, so `<Form>`\n\t * navigates with no client change.\n\t */\n\tresolveRedirect?: (reference: {\n\t\trelationTo: string\n\t\tvalue: number | string | object\n\t}) => string | null | undefined\n}\n\n/**\n * Reassemble the client button labels from the document's top-level `submitLabel`/`prevLabel`/\n * `nextLabel` fields, keeping only non-empty strings (mirroring the client's own `storedLabel`\n * fallback). Returns `undefined` when the author set no label, so the client uses its defaults.\n */\nconst buttonSettingsOf = (form: {\n\tsubmitLabel?: string | null\n\tprevLabel?: string | null\n\tnextLabel?: string | null\n}): FormButtonSettings | undefined => {\n\tconst label = (value: unknown): string | undefined =>\n\t\ttypeof value === 'string' && value.length > 0 ? value : undefined\n\tconst settings: FormButtonSettings = {}\n\tconst submitLabel = label(form.submitLabel)\n\tconst prevLabel = label(form.prevLabel)\n\tconst nextLabel = label(form.nextLabel)\n\tif (submitLabel !== undefined) settings.submitLabel = submitLabel\n\tif (prevLabel !== undefined) settings.prevLabel = prevLabel\n\tif (nextLabel !== undefined) settings.nextLabel = nextLabel\n\treturn Object.keys(settings).length > 0 ? settings : undefined\n}\n\n/**\n * Narrows a Payload-generated form document (from `getPayload().findByID()` or `fetch`) to\n * `FormDocument` without an unsafe `as` cast. Handles the small structural mismatches between\n * the auto-generated collection types and what `<Form>` expects:\n * - `fields` may be a typed blocks-union array or null; normalized to `FormFieldInstance[]`\n * (nameless bare rows, e.g. message blocks, pass through with their row `id` intact)\n * - `flow` is stored as opaque JSON; typed as `FormFlow | undefined`\n * - `response` may be null; coerced to `undefined`, otherwise passed through wholesale, which\n * includes `response.redirect.reference` (present only when the plugin's `redirectRelationships`\n * option is set): `value` may be a bare id (`depth: 0`) or a populated document, and the host\n * resolves it to a URL either by writing `redirect.url` or by passing `options.resolveRedirect`\n * - the button labels (`submitLabel`/`prevLabel`/`nextLabel`) live at the document root now (there\n * is no `buttons` group); the non-empty ones are reassembled into `FormDocument.buttons`\n * - `title` may be null; coerced to `undefined`\n * - `multistep`/`pollEnabled` are the two top-level form-type flags, coerced to strict booleans\n * - `poll` may be null; coerced to `undefined` (`resultsField`, `optionSource`, and\n * `sourceConfig` are dropped: server-side only; `outcome` passes through `winningValues` only)\n *\n * Unknown keys survive on `response` but not on `poll`, which is deliberate rather than incidental.\n * `response` is a visitor-facing group a host is meant to extend (`overrides.forms.fields`) and read\n * back off `FormDocument` in custom chrome, so it is cast wholesale. `poll` is plugin-owned config\n * that is split between\n * client-safe lifecycle state and server-only members, so it is rebuilt from an allowlist: a\n * passthrough would ship whatever a host put in `sourceConfig` (domain config, ids, credentials)\n * to every anonymous visitor. Adding a client-visible poll member means naming it here.\n *\n * Pure and framework-agnostic (no 'use client'): safe to call from a Server Component or any\n * other server-side code before handing the result to the client `<Form>`.\n */\nexport function toFormDocument(\n\tform: {\n\t\tid: number | string\n\t\tfields?: { blockType: string; name?: string; [key: string]: unknown }[] | null\n\t\tflow?: unknown\n\t\tresponse?: {\n\t\t\ttype?: string | null\n\t\t\tmessage?: unknown\n\t\t\tredirect?: {\n\t\t\t\turl?: string | null\n\t\t\t\treference?: { relationTo?: string | null; value?: number | string | object | null } | null\n\t\t\t} | null\n\t\t} | null\n\t\tsubmitLabel?: string | null\n\t\tprevLabel?: string | null\n\t\tnextLabel?: string | null\n\t\ttitle?: string | null\n\t\tmultistep?: boolean | null\n\t\tpollEnabled?: boolean | null\n\t\tpoll?: {\n\t\t\tresultsField?: string | null\n\t\t\tresultsVisibility?: string | null\n\t\t\tclosesAt?: string | null\n\t\t\toutcome?: { winningValues?: (string | null)[] | null } | null\n\t\t} | null\n\t\t/**\n\t\t * Consent statements resolved onto the doc by the plugin's forms `afterRead` hook (when\n\t\t * `consent.sources` is set), so consent renders on any fetch path (modal/client, not just RSC).\n\t\t * An explicit `options.consentStatements` takes precedence when both are present.\n\t\t */\n\t\tconsentStatements?: ConsentStatements\n\t\t/**\n\t\t * Calc source values resolved onto the doc by the plugin's forms `afterRead` hook (when calc\n\t\t * sources are registered and used); passed through so the client's live preview computes with\n\t\t * real values. `functions` can never ride a document, hence the Pick.\n\t\t */\n\t\tcalcResolved?: Pick<CalcResolved, 'sources' | 'weights'>\n\t},\n\toptions?: ToFormDocumentOptions\n): FormDocument {\n\tconst rawWinningValues = form.poll?.outcome?.winningValues\n\tconst winningValues = Array.isArray(rawWinningValues)\n\t\t? rawWinningValues.filter(\n\t\t\t\t(value): value is string => typeof value === 'string' && value.length > 0\n\t\t\t)\n\t\t: []\n\tconst poll = form.poll\n\t\t? {\n\t\t\t\tresultsVisibility: (form.poll.resultsVisibility ?? undefined) as\n\t\t\t\t\t| 'afterVote'\n\t\t\t\t\t| 'afterClose'\n\t\t\t\t\t| undefined,\n\t\t\t\tclosesAt: form.poll.closesAt ?? undefined,\n\t\t\t\t...(winningValues.length > 0 ? { outcome: { winningValues } } : {}),\n\t\t\t}\n\t\t: undefined\n\tlet fields = (form.fields ?? []) as FormFieldInstance[]\n\tif (options?.pollOptions) {\n\t\tfields = applyPollOptions(fields, form.poll?.resultsField, options.pollOptions)\n\t}\n\tconst consentStatements = options?.consentStatements ?? form.consentStatements\n\tif (consentStatements) {\n\t\tfields = applyConsentStatements(fields, consentStatements)\n\t}\n\tlet response = (form.response as FormResponseSettings | null | undefined) ?? undefined\n\t// A host that passes `resolveRedirect` gets internal references turned into `redirect.url` (all\n\t// `<Form>` navigates by), but only when the author set no explicit url. Non-mutating: clone the group.\n\tif (\n\t\toptions?.resolveRedirect &&\n\t\tresponse?.type === 'redirect' &&\n\t\tresponse.redirect?.reference &&\n\t\t!response.redirect.url\n\t) {\n\t\tconst url = options.resolveRedirect(response.redirect.reference)\n\t\tif (url) {\n\t\t\tresponse = { ...response, redirect: { ...response.redirect, url } }\n\t\t}\n\t}\n\treturn {\n\t\tid: form.id,\n\t\tfields,\n\t\tflow: form.flow as FormFlow | undefined,\n\t\tresponse,\n\t\tbuttons: buttonSettingsOf(form),\n\t\ttitle: form.title ?? undefined,\n\t\tmultistep: form.multistep === true,\n\t\tpollEnabled: form.pollEnabled === true,\n\t\tpoll,\n\t\tcalcResolved: form.calcResolved,\n\t}\n}\n"],"mappings":";;;;;;;;AAwCA,MAAM,oBAAoB,SAIY;CACrC,MAAM,SAAS,UACd,OAAO,UAAU,YAAY,MAAM,SAAS,IAAI,QAAQ,KAAA;CACzD,MAAM,WAA+B,CAAC;CACtC,MAAM,cAAc,MAAM,KAAK,WAAW;CAC1C,MAAM,YAAY,MAAM,KAAK,SAAS;CACtC,MAAM,YAAY,MAAM,KAAK,SAAS;CACtC,IAAI,gBAAgB,KAAA,GAAW,SAAS,cAAc;CACtD,IAAI,cAAc,KAAA,GAAW,SAAS,YAAY;CAClD,IAAI,cAAc,KAAA,GAAW,SAAS,YAAY;CAClD,OAAO,OAAO,KAAK,QAAQ,EAAE,SAAS,IAAI,WAAW,KAAA;AACtD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+BA,SAAgB,eACf,MAqCA,SACe;CACf,MAAM,mBAAmB,KAAK,MAAM,SAAS;CAC7C,MAAM,gBAAgB,MAAM,QAAQ,gBAAgB,IACjD,iBAAiB,QAChB,UAA2B,OAAO,UAAU,YAAY,MAAM,SAAS,CACzE,IACC,CAAC;CACJ,MAAM,OAAO,KAAK,OACf;EACA,mBAAoB,KAAK,KAAK,qBAAqB,KAAA;EAInD,UAAU,KAAK,KAAK,YAAY,KAAA;EAChC,GAAI,cAAc,SAAS,IAAI,EAAE,SAAS,EAAE,cAAc,EAAE,IAAI,CAAC;CAClE,IACC,KAAA;CACH,IAAI,SAAU,KAAK,UAAU,CAAC;CAC9B,IAAI,SAAS,aACZ,SAAS,iBAAiB,QAAQ,KAAK,MAAM,cAAc,QAAQ,WAAW;CAE/E,MAAM,oBAAoB,SAAS,qBAAqB,KAAK;CAC7D,IAAI,mBACH,SAAS,uBAAuB,QAAQ,iBAAiB;CAE1D,IAAI,WAAY,KAAK,YAAwD,KAAA;CAG7E,IACC,SAAS,mBACT,UAAU,SAAS,cACnB,SAAS,UAAU,aACnB,CAAC,SAAS,SAAS,KAClB;EACD,MAAM,MAAM,QAAQ,gBAAgB,SAAS,SAAS,SAAS;EAC/D,IAAI,KACH,WAAW;GAAE,GAAG;GAAU,UAAU;IAAE,GAAG,SAAS;IAAU;GAAI;EAAE;CAEpE;CACA,OAAO;EACN,IAAI,KAAK;EACT;EACA,MAAM,KAAK;EACX;EACA,SAAS,iBAAiB,IAAI;EAC9B,OAAO,KAAK,SAAS,KAAA;EACrB,WAAW,KAAK,cAAc;EAC9B,aAAa,KAAK,gBAAgB;EAClC;EACA,cAAc,KAAK;CACpB;AACD"}
@@ -1,4 +1,5 @@
1
1
  import { FormFieldInstance } from "../submissions/types.js";
2
+ import { CalcResolved } from "../calc/evaluate.js";
2
3
  import { FormFlow } from "../flow/types.js";
3
4
 
4
5
  //#region src/form/types.d.ts
@@ -59,6 +60,12 @@ type FormDocument = {
59
60
  multistep: boolean; /** Whether this form is a poll. Gates poll rendering and results; the poll config lives under `poll`. */
60
61
  pollEnabled: boolean;
61
62
  poll?: FormPollSettings;
63
+ /**
64
+ * Server-resolved calc source values, stamped by the plugin's forms afterRead hook when calc
65
+ * sources are registered and the form's expressions use them. Only `sources`/`weights` can ride
66
+ * the document, hence the Pick (`functions` cannot serialize; the client supplies those itself).
67
+ */
68
+ calcResolved?: Pick<CalcResolved, 'sources' | 'weights'>;
62
69
  };
63
70
  //#endregion
64
71
  export { FormButtonSettings, FormDocument, FormPollSettings, FormResponseSettings };
package/dist/index.d.ts CHANGED
@@ -1,13 +1,16 @@
1
+ import { CalcExpression } from "./calc/types.js";
1
2
  import { AnyPollOptionSource, PollOption, PollOptionResolveArgs, PollOptionSource, definePollOptionSource } from "./poll/definePollOptionSource.js";
2
3
  import { FileFieldConfig, FileRef, FileRefError } from "./uploads/types.js";
3
4
  import { AnyFormFieldDefinition, FormFieldDefinition, FormFieldFormat, FormFieldValidate, FormFieldValueKind, OmittableSharedField, ResolveFieldOptionsArgs } from "./fields/types.js";
5
+ import { CalcAllowed, normalizeCalc } from "./calc/normalizeCalc.js";
4
6
  import { BodyConverter, BodyConverterArgs, BodyRender, defaultBodyConverters, sanitizeUrl } from "./actions/body/converters.js";
5
7
  import { BodyContext, RichTextBodyOption, SerializeBodyArgs, serializeBody } from "./actions/body/serializeBody.js";
6
8
  import { textOfBody } from "./actions/body/textOfBody.js";
7
9
  import { AggregationBucket, AggregationRow, FieldAggregation, FieldMeta, SubmissionStatusFilter } from "./aggregation/types.js";
8
- import { CalcExpression } from "./calc/types.js";
10
+ import { CalcResolved, calcWeightKey, evaluateCalc } from "./calc/evaluate.js";
9
11
  import { calcExpressionOf, computeCalcFields } from "./calc/computeCalcFields.js";
10
- import { evaluateCalc } from "./calc/evaluate.js";
12
+ import { formatCalc } from "./calc/formatCalc.js";
13
+ import { CalcDisplayConfig, formatCalcValue } from "./calc/formatCalcValue.js";
11
14
  import { evaluateCondition } from "./conditions/evaluate.js";
12
15
  import { ConsentSourceEntry, ConsentSourcePage, ConsentSourcesResolver } from "./consent/types.js";
13
16
  import { ConsentStatement, ConsentStatements, ResolveConsentStatementsArgs, resolveConsentStatements } from "./consent/resolveConsentStatements.js";
@@ -44,7 +47,9 @@ import { ConsentSourceOption, ResolveConsentSourcesRequestArgs, ResolveConsentSo
44
47
  import { ResolvePublishedVersionRefArgs, resolvePublishedVersionRef } from "./consent/resolvePublishedVersionRef.js";
45
48
  import { DepartmentEmailsResolver, DepartmentOption, ResolveDepartmentOptionsArgs, ResolveDepartmentsRequestArgs, ResolveDepartmentsRequestResult, resolveDepartmentOptions } from "./email/departments.js";
46
49
  import { RecipientResolveArgs, RecipientSource, RecipientSourceRegistry } from "./actions/recipientSources.js";
50
+ import { CalcFunction, CalcSource, CalcSourceResolveArgs, CalcWeightResolveArgs, defineCalcFunction, defineCalcSource } from "./calc/registry.js";
47
51
  import { RedirectFieldsOverride, RedirectOption, ResponseOption } from "./collections/redirectFields.js";
52
+ import { DefaultSettingsFields, SettingsFieldsOverride, SettingsOption, buildDefaultSettingsFields } from "./collections/settingsFields.js";
48
53
  import { CaptchaProvider, CaptchaVerifyArgs, IdentifyFn, RateLimitCheckArgs, RateLimitConfig, RateLimitResult, RateLimiter, SpamConfig, SpamMetadataConfig, SpamOption } from "./spam/types.js";
49
54
  import { UploadsOption } from "./plugin/uploadsCollection.js";
50
55
  import { DefaultOutcomeFields, OutcomeFieldsOverride, buildDefaultOutcomeFields, buildResolvedAtField, buildWinningValuesField } from "./poll/outcomeFields.js";
@@ -57,7 +62,7 @@ import { renderAllValues, renderAllValuesTable } from "./actions/body/wildcards.
57
62
  import { buildDefaultActionDefinitions, defaultActionDefinitions } from "./actions/builtin/index.js";
58
63
  import { SIGNATURE_HEADER, signPayload } from "./actions/sign.js";
59
64
  import { aggregateRowForField, aggregateRowsForFields } from "./aggregation/aggregateRows.js";
60
- import { normalizeCalc } from "./calc/normalizeCalc.js";
65
+ import { ResolveCalcContextArgs, calcUsesSources, resolveCalcContext } from "./calc/resolveCalcContext.js";
61
66
  import { applyConsentStatements } from "./consent/applyConsentStatements.js";
62
67
  import { DepartmentsFieldOptions, departmentsField } from "./email/departmentsField.js";
63
68
  import { buildDefaultFieldDefinitions, defaultFieldDefinitions, defaultFieldDefinitionsByType } from "./fields/builtin/index.js";
@@ -68,6 +73,9 @@ import { defineFormField } from "./fields/defineFormField.js";
68
73
  import { localizedIf } from "./fields/localizedIf.js";
69
74
  import { POLL_CLOSE_TASK_SLUG, PollCloseTaskInput, buildPollCloseTask, enqueuePollClose, registerPollCloseTask, runPollClose, shouldAutoResolvePoll } from "./poll/closeJob.js";
70
75
  import { mostVotedStrategy, topBucketValues } from "./poll/mostVoted.js";
76
+ import { aggregateFromVotes } from "./poll/votes/aggregateFromVotes.js";
77
+ import { recountPollVotes } from "./poll/votes/recountPollVotes.js";
78
+ import { POLL_VOTES_SLUG, RESPONDENTS_VALUE, VOTE_SHARDS } from "./poll/votes/votesCollection.js";
71
79
  import { DEFAULT_PRESENTATION_NAME, defaultPresentationDescriptors } from "./presentations/defaults.js";
72
80
  import { defineCaptchaProvider } from "./spam/captcha.js";
73
81
  import { defaultIdentify } from "./spam/identify.js";
@@ -86,5 +94,5 @@ import { FieldTargetParamOptions, fieldTargetParam } from "./validation/fieldTar
86
94
  //#region src/index.d.ts
87
95
  declare const formBuilder: (options: FormBuilderPluginOptions) => import("payload").Plugin;
88
96
  //#endregion
89
- export { type ActionDefinition, type ActionOption, type ActionRegistry, type ActionResult, type ActionRunArgs, type ActionsConfig, type AggregateFieldResponsesArgs, type AggregateFormResponsesArgs, type AggregationBucket, type AggregationRow, type AnyActionDefinition, type AnyFormFieldDefinition, type AnyPollOptionSource, type AnyValidationRuleDefinition, type BodyContext, type BodyConverter, type BodyConverterArgs, type BodyRender, type ButtonFieldsOverride, type ButtonsOption, CAPTCHA_TOKEN_KEY, type CalcExpression, type CaptchaProvider, type CaptchaVerifyArgs, type ConsentProof, type ConsentSnapshotMode, type ConsentSourceEntry, type ConsentSourceOption, type ConsentSourcePage, type ConsentSourcesFieldOptions, type ConsentSourcesResolver, type ConsentStatement, type ConsentStatements, type CreateSubmissionArgs, type CreatedSubmission, DEFAULT_HONEYPOT_FIELD, DEFAULT_PRESENTATION_NAME, type DefaultButtonFields, type DefaultOutcomeFields, type DepartmentEmailsResolver, type DepartmentOption, type DepartmentsFieldOptions, type FieldAggregation, type FieldCondition, type FieldMeta, type FieldTargetParamOptions, type FieldTypeOption, type FieldTypeRegistry, type FieldTypesConfig, type FileFieldConfig, type FileRef, type FileRefError, type FormBuilderPluginOptions, type FormButtonSettings, type FormContextReference, type FormDocument, type FormFieldDefinition, type FormFieldFormat, type FormFieldValidate, type FormFieldValueKind, type FormPollSettings, type FormResponseSettings, type FormResultsAccess, type FormResultsAccessArgs, type FromAddressOption, type FromAddressesResolver, type HcaptchaProviderOptions, type IdentifyFn, type OmittableSharedField, type OutcomeFieldsOverride, POLL_CLOSE_TASK_SLUG, type FormBuilderPluginOptions as PluginOptions, type PollCloseTaskInput, type PollOption, type PollOptionResolveArgs, type PollOptionSource, type PollOptionSourceOption, type PollOptionSourceRegistry, type PollOptionSourcesConfig, type PollOutcomeStrategy, type PollOutcomeStrategyArgs, type PollTypeRegistry, type PollTypesConfig, type PrefillOptions, type PresentationDensity, type PresentationDescriptor, type PresentationSurface, type RateLimitCheckArgs, type RateLimitConfig, type RateLimitResult, type RateLimiter, type RecallResolver, type RecaptchaProviderOptions, type RecipientResolveArgs, type RecipientSource, type RecipientSourceRegistry, type RedirectFieldsOverride, type RedirectOption, type ResolveConsentEntriesArgs, type ResolveConsentSourcesRequestArgs, type ResolveConsentSourcesRequestResult, type ResolveConsentStatementsArgs, type ResolveDepartmentOptionsArgs, type ResolveDepartmentsRequestArgs, type ResolveDepartmentsRequestResult, type ResolveEffectivePollOptionsArgs, type ResolveFieldOptionsArgs, type ResolvePollOptionsArgs, type ResolvePollOutcomeArgs, type ResolvePublishedVersionRefArgs, type ResolveResultsRequestArgs, type ResolveResultsRequestResult, type ResponseOption, type RichTextBodyOption, SIGNATURE_HEADER, type SerializeBodyArgs, type SpamConfig, type SpamMetadataConfig, type SpamOption, type SubmissionStatusFilter, type ToFormDocumentOptions, type TurnstileProviderOptions, type UploadsOption, type ValidationRuleDefinition, type ValidationRuleOption, type ValidationRuleRegistry, type ValidationRuleResult, type ValidationRulesConfig, aggregateFieldResponses, aggregateFormResponses, aggregateRowForField, aggregateRowsForFields, applyConsentStatements, buildDefaultActionDefinitions, buildDefaultButtonFields, buildDefaultFieldDefinitions, buildDefaultOutcomeFields, buildNextLabelField, buildPollCloseTask, buildPrevLabelField, buildRecallResolver, buildResolvedAtField, buildSubmitLabelField, buildWinningValuesField, calcExpressionOf, captureConsent, captureFileRef, computeCalcFields, consentSourcesField, countryField, createKvRateLimiter, createSubmission, defaultActionDefinitions, defaultBodyConverters, defaultFieldDefinitions, defaultFieldDefinitionsByType, defaultIdentify, defaultPresentationDescriptors, defaultValidationRules, defaultValidationRulesByType, defineAction, defineCaptchaProvider, defineFormField, definePollOptionSource, definePollType, defineValidationRule, departmentsField, enqueuePollClose, escapeHtml, evaluateCalc, evaluateCondition, fieldHasOptions, fieldKey, fieldTargetParam, fileMimeTypeOptions, formBuilder, formatBytes, hasVotedCookie, hcaptchaProvider, interpolate, isPollClosed, localizedIf, manualStrategy, mostVotedStrategy, normalizeCalc, optionLabelsFor, pollTypesOf, recaptchaProvider, registerPollCloseTask, renderAllValues, renderAllValuesTable, resolveActions, resolveConsentEntries, resolveConsentSourcesRequest, resolveConsentStatements, resolveDepartmentOptions, resolveEffectivePollOptions, resolveFileRef, resolveFormResultsRequest, resolvePollOptionSources, resolvePollOptions, resolvePollOutcome, resolvePollTypes, resolvePublishedVersionRef, resolveSpamConfig, runPollClose, sanitizeUrl, serializeBody, shouldAutoResolvePoll, signFormContext, signPayload, sourceStrategy, stashPollTypes, stateField, textOfBody, toFormDocument, topBucketValues, turnstileProvider, valuesFromSearchParams, verifyFormContext, votedCookieName };
97
+ export { type ActionDefinition, type ActionOption, type ActionRegistry, type ActionResult, type ActionRunArgs, type ActionsConfig, type AggregateFieldResponsesArgs, type AggregateFormResponsesArgs, type AggregationBucket, type AggregationRow, type AnyActionDefinition, type AnyFormFieldDefinition, type AnyPollOptionSource, type AnyValidationRuleDefinition, type BodyContext, type BodyConverter, type BodyConverterArgs, type BodyRender, type ButtonFieldsOverride, type ButtonsOption, CAPTCHA_TOKEN_KEY, type CalcAllowed, type CalcDisplayConfig, type CalcExpression, type CalcFunction, type CalcResolved, type CalcSource, type CalcSourceResolveArgs, type CalcWeightResolveArgs, type CaptchaProvider, type CaptchaVerifyArgs, type ConsentProof, type ConsentSnapshotMode, type ConsentSourceEntry, type ConsentSourceOption, type ConsentSourcePage, type ConsentSourcesFieldOptions, type ConsentSourcesResolver, type ConsentStatement, type ConsentStatements, type CreateSubmissionArgs, type CreatedSubmission, DEFAULT_HONEYPOT_FIELD, DEFAULT_PRESENTATION_NAME, type DefaultButtonFields, type DefaultOutcomeFields, type DefaultSettingsFields, type DepartmentEmailsResolver, type DepartmentOption, type DepartmentsFieldOptions, type FieldAggregation, type FieldCondition, type FieldMeta, type FieldTargetParamOptions, type FieldTypeOption, type FieldTypeRegistry, type FieldTypesConfig, type FileFieldConfig, type FileRef, type FileRefError, type FormBuilderPluginOptions, type FormButtonSettings, type FormContextReference, type FormDocument, type FormFieldDefinition, type FormFieldFormat, type FormFieldValidate, type FormFieldValueKind, type FormPollSettings, type FormResponseSettings, type FormResultsAccess, type FormResultsAccessArgs, type FromAddressOption, type FromAddressesResolver, type HcaptchaProviderOptions, type IdentifyFn, type OmittableSharedField, type OutcomeFieldsOverride, POLL_CLOSE_TASK_SLUG, POLL_VOTES_SLUG, type FormBuilderPluginOptions as PluginOptions, type PollCloseTaskInput, type PollOption, type PollOptionResolveArgs, type PollOptionSource, type PollOptionSourceOption, type PollOptionSourceRegistry, type PollOptionSourcesConfig, type PollOutcomeStrategy, type PollOutcomeStrategyArgs, type PollTypeRegistry, type PollTypesConfig, type PrefillOptions, type PresentationDensity, type PresentationDescriptor, type PresentationSurface, RESPONDENTS_VALUE, type RateLimitCheckArgs, type RateLimitConfig, type RateLimitResult, type RateLimiter, type RecallResolver, type RecaptchaProviderOptions, type RecipientResolveArgs, type RecipientSource, type RecipientSourceRegistry, type RedirectFieldsOverride, type RedirectOption, type ResolveCalcContextArgs, type ResolveConsentEntriesArgs, type ResolveConsentSourcesRequestArgs, type ResolveConsentSourcesRequestResult, type ResolveConsentStatementsArgs, type ResolveDepartmentOptionsArgs, type ResolveDepartmentsRequestArgs, type ResolveDepartmentsRequestResult, type ResolveEffectivePollOptionsArgs, type ResolveFieldOptionsArgs, type ResolvePollOptionsArgs, type ResolvePollOutcomeArgs, type ResolvePublishedVersionRefArgs, type ResolveResultsRequestArgs, type ResolveResultsRequestResult, type ResponseOption, type RichTextBodyOption, SIGNATURE_HEADER, type SerializeBodyArgs, type SettingsFieldsOverride, type SettingsOption, type SpamConfig, type SpamMetadataConfig, type SpamOption, type SubmissionStatusFilter, type ToFormDocumentOptions, type TurnstileProviderOptions, type UploadsOption, VOTE_SHARDS, type ValidationRuleDefinition, type ValidationRuleOption, type ValidationRuleRegistry, type ValidationRuleResult, type ValidationRulesConfig, aggregateFieldResponses, aggregateFormResponses, aggregateFromVotes, aggregateRowForField, aggregateRowsForFields, applyConsentStatements, buildDefaultActionDefinitions, buildDefaultButtonFields, buildDefaultFieldDefinitions, buildDefaultOutcomeFields, buildDefaultSettingsFields, buildNextLabelField, buildPollCloseTask, buildPrevLabelField, buildRecallResolver, buildResolvedAtField, buildSubmitLabelField, buildWinningValuesField, calcExpressionOf, calcUsesSources, calcWeightKey, captureConsent, captureFileRef, computeCalcFields, consentSourcesField, countryField, createKvRateLimiter, createSubmission, defaultActionDefinitions, defaultBodyConverters, defaultFieldDefinitions, defaultFieldDefinitionsByType, defaultIdentify, defaultPresentationDescriptors, defaultValidationRules, defaultValidationRulesByType, defineAction, defineCalcFunction, defineCalcSource, defineCaptchaProvider, defineFormField, definePollOptionSource, definePollType, defineValidationRule, departmentsField, enqueuePollClose, escapeHtml, evaluateCalc, evaluateCondition, fieldHasOptions, fieldKey, fieldTargetParam, fileMimeTypeOptions, formBuilder, formatBytes, formatCalc, formatCalcValue, hasVotedCookie, hcaptchaProvider, interpolate, isPollClosed, localizedIf, manualStrategy, mostVotedStrategy, normalizeCalc, optionLabelsFor, pollTypesOf, recaptchaProvider, recountPollVotes, registerPollCloseTask, renderAllValues, renderAllValuesTable, resolveActions, resolveCalcContext, resolveConsentEntries, resolveConsentSourcesRequest, resolveConsentStatements, resolveDepartmentOptions, resolveEffectivePollOptions, resolveFileRef, resolveFormResultsRequest, resolvePollOptionSources, resolvePollOptions, resolvePollOutcome, resolvePollTypes, resolvePublishedVersionRef, resolveSpamConfig, runPollClose, sanitizeUrl, serializeBody, shouldAutoResolvePoll, signFormContext, signPayload, sourceStrategy, stashPollTypes, stateField, textOfBody, toFormDocument, topBucketValues, turnstileProvider, valuesFromSearchParams, verifyFormContext, votedCookieName };
90
98
  //# sourceMappingURL=index.d.ts.map
package/dist/index.js CHANGED
@@ -9,33 +9,39 @@ import { defineAction } from "./actions/defineAction.js";
9
9
  import { SIGNATURE_HEADER, signPayload } from "./actions/sign.js";
10
10
  import { buildDefaultActionDefinitions, defaultActionDefinitions } from "./actions/builtin/index.js";
11
11
  import { resolveActions } from "./actions/registry.js";
12
+ import { assertNoCalcFunctionCollision, assertValidCalcSourceKeys, defineCalcFunction, defineCalcSource } from "./calc/registry.js";
12
13
  import { resolveConsentEntries, stashConsentSources } from "./consent/resolveConsentEntries.js";
14
+ import { formatCalcValue } from "./calc/formatCalcValue.js";
13
15
  import { normalizeCalc } from "./calc/normalizeCalc.js";
14
16
  import { defineFormField } from "./fields/defineFormField.js";
15
17
  import { resolveFileRef } from "./uploads/resolveFileRef.js";
16
18
  import { fileMimeTypeOptions } from "./fields/builtin/file.js";
17
19
  import { buildDefaultFieldDefinitions, defaultFieldDefinitions, defaultFieldDefinitionsByType } from "./fields/builtin/index.js";
18
20
  import { resolveFieldTypes, stashFieldTypes } from "./fields/registry.js";
19
- import { CAPTCHA_TOKEN_KEY, DEFAULT_HONEYPOT_FIELD } from "./spam/constants.js";
21
+ import { fieldKey } from "./fields/fieldKey.js";
22
+ import { calcWeightKey, evaluateCalc } from "./calc/evaluate.js";
23
+ import { calcExpressionOf, computeCalcFields } from "./calc/computeCalcFields.js";
24
+ import { calcUsesSources, resolveCalcContext } from "./calc/resolveCalcContext.js";
20
25
  import { resolveConsentStatements } from "./consent/resolveConsentStatements.js";
21
26
  import { isPollClosed } from "./form/pollState.js";
22
- import { fieldKey } from "./fields/fieldKey.js";
23
27
  import { aggregateRowForField, aggregateRowsForFields } from "./aggregation/aggregateRows.js";
24
28
  import { aggregateFieldResponses, aggregateFormResponses, fieldHasOptions } from "./aggregation/aggregateResponses.js";
29
+ import { resolvePollOptions, stashPollOptionSources } from "./poll/resolvePollOptions.js";
30
+ import { resolveEffectivePollOptions } from "./poll/effectivePollOptions.js";
25
31
  import { definePollType } from "./poll/definePollType.js";
26
32
  import { mostVotedStrategy, topBucketValues } from "./poll/mostVoted.js";
27
- import { resolvePollOptions, stashPollOptionSources } from "./poll/resolvePollOptions.js";
28
33
  import { manualStrategy, pollTypesOf, resolvePollTypes, sourceStrategy, stashPollTypes } from "./poll/pollTypeRegistry.js";
34
+ import { POLL_VOTES_SLUG, RESPONDENTS_VALUE, VOTE_SHARDS } from "./poll/votes/votesCollection.js";
35
+ import { aggregateFromVotes } from "./poll/votes/aggregateFromVotes.js";
29
36
  import { resolvePollOutcome } from "./poll/resolvePollOutcome.js";
30
37
  import { POLL_CLOSE_TASK_SLUG, buildPollCloseTask, enqueuePollClose, registerPollCloseTask, runPollClose, shouldAutoResolvePoll } from "./poll/closeJob.js";
31
- import { resolveEffectivePollOptions } from "./poll/effectivePollOptions.js";
32
38
  import { buildDefaultOutcomeFields, buildResolvedAtField, buildWinningValuesField } from "./poll/outcomeFields.js";
33
39
  import { buildDefaultButtonFields, buildNextLabelField, buildPrevLabelField, buildSubmitLabelField } from "./collections/buttonFields.js";
34
40
  import { resolveFormResultsRequest } from "./aggregation/resolveResultsRequest.js";
35
41
  import { resolveConsentSourcesRequest } from "./consent/resolveConsentSourcesRequest.js";
36
42
  import { resolveDepartmentOptions } from "./email/departments.js";
37
- import { evaluateCalc } from "./calc/evaluate.js";
38
- import { calcExpressionOf, computeCalcFields } from "./calc/computeCalcFields.js";
43
+ import { buildDefaultSettingsFields } from "./collections/settingsFields.js";
44
+ import { CAPTCHA_TOKEN_KEY, DEFAULT_HONEYPOT_FIELD } from "./spam/constants.js";
39
45
  import { evaluateCondition } from "./conditions/evaluate.js";
40
46
  import { textOfBody } from "./actions/body/textOfBody.js";
41
47
  import { resolvePublishedVersionRef } from "./consent/resolvePublishedVersionRef.js";
@@ -54,6 +60,7 @@ import { defineValidationRule } from "./validation/defineValidationRule.js";
54
60
  import { fieldTargetParam } from "./validation/fieldTargetParam.js";
55
61
  import { defaultValidationRules, defaultValidationRulesByType } from "./validation/builtin/index.js";
56
62
  import { resolveValidationRules } from "./validation/registry.js";
63
+ import { formatCalc } from "./calc/formatCalc.js";
57
64
  import { applyConsentStatements } from "./consent/applyConsentStatements.js";
58
65
  import { consentSourcesField } from "./consent/consentSourcesField.js";
59
66
  import { departmentsField } from "./email/departmentsField.js";
@@ -61,6 +68,7 @@ import { countryField } from "./fields/builtin/country.js";
61
68
  import { stateField } from "./fields/builtin/state.js";
62
69
  import { toFormDocument } from "./form/toFormDocument.js";
63
70
  import { definePollOptionSource } from "./poll/definePollOptionSource.js";
71
+ import { recountPollVotes } from "./poll/votes/recountPollVotes.js";
64
72
  import { valuesFromSearchParams } from "./prefill/valuesFromSearchParams.js";
65
73
  import { DEFAULT_PRESENTATION_NAME, defaultPresentationDescriptors } from "./presentations/defaults.js";
66
74
  import { buildRecallResolver, optionLabelsFor } from "./recall/resolver.js";
@@ -79,9 +87,23 @@ const formBuilder = definePlugin({
79
87
  if (options.disabled === true) return config;
80
88
  const localizeContent = options.localizeContent !== false;
81
89
  const uploads = options.uploads ?? false;
90
+ const calcSources = options.calc?.sources ?? {};
91
+ const calcFunctions = options.calc?.functions ?? {};
92
+ assertNoCalcFunctionCollision(calcFunctions);
93
+ assertValidCalcSourceKeys(calcSources);
94
+ const calcAllowed = {
95
+ sources: new Set(Object.keys(calcSources)),
96
+ functions: new Set(Object.keys(calcFunctions))
97
+ };
98
+ const calcSourceMeta = Object.entries(calcSources).map(([key, source]) => ({
99
+ key,
100
+ label: source.label,
101
+ scalar: typeof source.resolve === "function",
102
+ weights: typeof source.resolveWeights === "function"
103
+ }));
82
104
  const uploadMimeTypes = uploads === false ? void 0 : uploads.mimeTypes ?? readUploadCollectionMimeTypes(config, uploads.collection);
83
105
  const consentSources = options.consent?.sources;
84
- const registry = resolveFieldTypes(buildDefaultFieldDefinitions(localizeContent, options.richText?.editor, uploadMimeTypes).filter((definition) => (uploads !== false || definition.type !== "file") && (consentSources !== void 0 || definition.type !== "consent")), options.fields);
106
+ const registry = resolveFieldTypes(buildDefaultFieldDefinitions(localizeContent, options.richText?.editor, uploadMimeTypes, calcAllowed, calcSourceMeta).filter((definition) => (uploads !== false || definition.type !== "file") && (consentSources !== void 0 || definition.type !== "consent")), options.fields);
85
107
  const ruleRegistry = resolveValidationRules(defaultValidationRules, options.rules);
86
108
  const fromAddresses = options.email?.fromAddresses;
87
109
  const departments = options.email?.departments;
@@ -106,6 +128,9 @@ const formBuilder = definePlugin({
106
128
  config,
107
129
  registry,
108
130
  ruleRegistry,
131
+ calcAllowed,
132
+ calcSources,
133
+ calcFunctions,
109
134
  consentSources,
110
135
  consentSnapshot: options.consent?.snapshot ?? "both",
111
136
  consentResolveOnRead: options.consent?.resolveOnRead,
@@ -122,7 +147,9 @@ const formBuilder = definePlugin({
122
147
  pollSourceRegistry,
123
148
  pollTypeRegistry,
124
149
  outcomeFields: options.poll?.outcomeFields,
150
+ pollVotes: options.poll?.votes === false ? false : options.poll?.votes ?? {},
125
151
  buttons: options.buttons,
152
+ settings: options.settings,
126
153
  response: options.response,
127
154
  fromAddresses,
128
155
  departments,
@@ -133,6 +160,6 @@ const formBuilder = definePlugin({
133
160
  }
134
161
  });
135
162
  //#endregion
136
- export { CAPTCHA_TOKEN_KEY, DEFAULT_HONEYPOT_FIELD, DEFAULT_PRESENTATION_NAME, POLL_CLOSE_TASK_SLUG, SIGNATURE_HEADER, aggregateFieldResponses, aggregateFormResponses, aggregateRowForField, aggregateRowsForFields, applyConsentStatements, buildDefaultActionDefinitions, buildDefaultButtonFields, buildDefaultFieldDefinitions, buildDefaultOutcomeFields, buildNextLabelField, buildPollCloseTask, buildPrevLabelField, buildRecallResolver, buildResolvedAtField, buildSubmitLabelField, buildWinningValuesField, calcExpressionOf, captureConsent, captureFileRef, computeCalcFields, consentSourcesField, countryField, createKvRateLimiter, createSubmission, defaultActionDefinitions, defaultBodyConverters, defaultFieldDefinitions, defaultFieldDefinitionsByType, defaultIdentify, defaultPresentationDescriptors, defaultValidationRules, defaultValidationRulesByType, defineAction, defineCaptchaProvider, defineFormField, definePollOptionSource, definePollType, defineValidationRule, departmentsField, enqueuePollClose, escapeHtml, evaluateCalc, evaluateCondition, fieldHasOptions, fieldKey, fieldTargetParam, fileMimeTypeOptions, formBuilder, formatBytes, hasVotedCookie, hcaptchaProvider, interpolate, isPollClosed, localizedIf, manualStrategy, mostVotedStrategy, normalizeCalc, optionLabelsFor, pollTypesOf, recaptchaProvider, registerPollCloseTask, renderAllValues, renderAllValuesTable, resolveActions, resolveConsentEntries, resolveConsentSourcesRequest, resolveConsentStatements, resolveDepartmentOptions, resolveEffectivePollOptions, resolveFileRef, resolveFormResultsRequest, resolvePollOptionSources, resolvePollOptions, resolvePollOutcome, resolvePollTypes, resolvePublishedVersionRef, resolveSpamConfig, runPollClose, sanitizeUrl, serializeBody, shouldAutoResolvePoll, signFormContext, signPayload, sourceStrategy, stashPollTypes, stateField, textOfBody, toFormDocument, topBucketValues, turnstileProvider, valuesFromSearchParams, verifyFormContext, votedCookieName };
163
+ export { CAPTCHA_TOKEN_KEY, DEFAULT_HONEYPOT_FIELD, DEFAULT_PRESENTATION_NAME, POLL_CLOSE_TASK_SLUG, POLL_VOTES_SLUG, RESPONDENTS_VALUE, SIGNATURE_HEADER, VOTE_SHARDS, aggregateFieldResponses, aggregateFormResponses, aggregateFromVotes, aggregateRowForField, aggregateRowsForFields, applyConsentStatements, buildDefaultActionDefinitions, buildDefaultButtonFields, buildDefaultFieldDefinitions, buildDefaultOutcomeFields, buildDefaultSettingsFields, buildNextLabelField, buildPollCloseTask, buildPrevLabelField, buildRecallResolver, buildResolvedAtField, buildSubmitLabelField, buildWinningValuesField, calcExpressionOf, calcUsesSources, calcWeightKey, captureConsent, captureFileRef, computeCalcFields, consentSourcesField, countryField, createKvRateLimiter, createSubmission, defaultActionDefinitions, defaultBodyConverters, defaultFieldDefinitions, defaultFieldDefinitionsByType, defaultIdentify, defaultPresentationDescriptors, defaultValidationRules, defaultValidationRulesByType, defineAction, defineCalcFunction, defineCalcSource, defineCaptchaProvider, defineFormField, definePollOptionSource, definePollType, defineValidationRule, departmentsField, enqueuePollClose, escapeHtml, evaluateCalc, evaluateCondition, fieldHasOptions, fieldKey, fieldTargetParam, fileMimeTypeOptions, formBuilder, formatBytes, formatCalc, formatCalcValue, hasVotedCookie, hcaptchaProvider, interpolate, isPollClosed, localizedIf, manualStrategy, mostVotedStrategy, normalizeCalc, optionLabelsFor, pollTypesOf, recaptchaProvider, recountPollVotes, registerPollCloseTask, renderAllValues, renderAllValuesTable, resolveActions, resolveCalcContext, resolveConsentEntries, resolveConsentSourcesRequest, resolveConsentStatements, resolveDepartmentOptions, resolveEffectivePollOptions, resolveFileRef, resolveFormResultsRequest, resolvePollOptionSources, resolvePollOptions, resolvePollOutcome, resolvePollTypes, resolvePublishedVersionRef, resolveSpamConfig, runPollClose, sanitizeUrl, serializeBody, shouldAutoResolvePoll, signFormContext, signPayload, sourceStrategy, stashPollTypes, stateField, textOfBody, toFormDocument, topBucketValues, turnstileProvider, valuesFromSearchParams, verifyFormContext, votedCookieName };
137
164
 
138
165
  //# sourceMappingURL=index.js.map