@10x-media/form-builder 0.1.0-beta.1 → 0.1.0-beta.3

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 (177) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/README.md +4 -2
  3. package/dist/actions/body/converters.d.ts +20 -0
  4. package/dist/actions/body/converters.js +57 -0
  5. package/dist/actions/body/converters.js.map +1 -0
  6. package/dist/actions/body/escapeHtml.d.ts +6 -0
  7. package/dist/actions/body/escapeHtml.js +14 -0
  8. package/dist/actions/body/escapeHtml.js.map +1 -0
  9. package/dist/actions/body/serializeBody.d.ts +35 -0
  10. package/dist/actions/body/serializeBody.js +76 -0
  11. package/dist/actions/body/serializeBody.js.map +1 -0
  12. package/dist/actions/body/serializeSlate.js +31 -0
  13. package/dist/actions/body/serializeSlate.js.map +1 -0
  14. package/dist/actions/body/wildcards.d.ts +10 -0
  15. package/dist/actions/body/wildcards.js +33 -0
  16. package/dist/actions/body/wildcards.js.map +1 -0
  17. package/dist/actions/builtin/confirmation.js +28 -12
  18. package/dist/actions/builtin/confirmation.js.map +1 -1
  19. package/dist/actions/builtin/emailTeam.js +7 -9
  20. package/dist/actions/builtin/emailTeam.js.map +1 -1
  21. package/dist/actions/builtin/signedWebhook.js +21 -3
  22. package/dist/actions/builtin/signedWebhook.js.map +1 -1
  23. package/dist/actions/defineAction.d.ts +2 -1
  24. package/dist/actions/defineAction.js.map +1 -1
  25. package/dist/actions/dispatch.js +2 -1
  26. package/dist/actions/dispatch.js.map +1 -1
  27. package/dist/actions/runActions.js +8 -1
  28. package/dist/actions/runActions.js.map +1 -1
  29. package/dist/actions/task.js +7 -5
  30. package/dist/actions/task.js.map +1 -1
  31. package/dist/calc/normalizeCalc.js +5 -17
  32. package/dist/calc/normalizeCalc.js.map +1 -1
  33. package/dist/calc/types.d.ts +8 -2
  34. package/dist/calc/types.js +22 -0
  35. package/dist/calc/types.js.map +1 -0
  36. package/dist/client/ByteSizeField.d.ts +21 -0
  37. package/dist/client/ByteSizeField.js +56 -0
  38. package/dist/client/ByteSizeField.js.map +1 -0
  39. package/dist/client/ConditionBuilder.js +2 -1
  40. package/dist/client/ConditionBuilder.js.map +1 -1
  41. package/dist/client/FieldNameSelect.d.ts +20 -0
  42. package/dist/client/FieldNameSelect.js +58 -0
  43. package/dist/client/FieldNameSelect.js.map +1 -0
  44. package/dist/client/FlowBuilder.d.ts +0 -1
  45. package/dist/client/FlowBuilder.js +4 -6
  46. package/dist/client/FlowBuilder.js.map +1 -1
  47. package/dist/client/FormConditionField.js +1 -4
  48. package/dist/client/FormConditionField.js.map +1 -1
  49. package/dist/client/admin.css +192 -0
  50. package/dist/client/toStaticLabel.js +13 -0
  51. package/dist/client/toStaticLabel.js.map +1 -0
  52. package/dist/collections/formSubmissions.js +60 -39
  53. package/dist/collections/formSubmissions.js.map +1 -1
  54. package/dist/collections/forms.js +143 -115
  55. package/dist/collections/forms.js.map +1 -1
  56. package/dist/collections/uploads.d.ts +2 -1
  57. package/dist/collections/uploads.js +22 -13
  58. package/dist/collections/uploads.js.map +1 -1
  59. package/dist/exports/client.d.ts +3 -1
  60. package/dist/exports/client.js +3 -1
  61. package/dist/exports/react.d.ts +7 -2
  62. package/dist/exports/react.js +6 -2
  63. package/dist/exports/types.d.ts +2 -1
  64. package/dist/fields/buildFieldBlocks.js +22 -12
  65. package/dist/fields/buildFieldBlocks.js.map +1 -1
  66. package/dist/fields/builtin/calculation.js +115 -2
  67. package/dist/fields/builtin/calculation.js.map +1 -1
  68. package/dist/fields/builtin/date.js +29 -0
  69. package/dist/fields/builtin/date.js.map +1 -0
  70. package/dist/fields/builtin/file.d.ts +15 -0
  71. package/dist/fields/builtin/file.js +79 -3
  72. package/dist/fields/builtin/file.js.map +1 -1
  73. package/dist/fields/builtin/index.d.ts +14 -0
  74. package/dist/fields/builtin/index.js +13 -2
  75. package/dist/fields/builtin/index.js.map +1 -1
  76. package/dist/fields/builtin/repeater.js +44 -0
  77. package/dist/fields/builtin/repeater.js.map +1 -0
  78. package/dist/fields/fieldNamesOfType.js +25 -0
  79. package/dist/fields/fieldNamesOfType.js.map +1 -0
  80. package/dist/fields/sharedConfig.js +30 -18
  81. package/dist/fields/sharedConfig.js.map +1 -1
  82. package/dist/fields/types.d.ts +2 -1
  83. package/dist/index.d.ts +38 -2
  84. package/dist/index.js +17 -5
  85. package/dist/index.js.map +1 -1
  86. package/dist/plugin/collectionOverrides.d.ts +22 -0
  87. package/dist/plugin/registerCollections.js +39 -10
  88. package/dist/plugin/registerCollections.js.map +1 -1
  89. package/dist/react/Form.d.ts +32 -3
  90. package/dist/react/Form.js +50 -8
  91. package/dist/react/Form.js.map +1 -1
  92. package/dist/react/FormContext.js.map +1 -1
  93. package/dist/react/Poll.js +1 -1
  94. package/dist/react/captcha/HcaptchaCaptcha.d.ts +28 -0
  95. package/dist/react/captcha/HcaptchaCaptcha.js +53 -0
  96. package/dist/react/captcha/HcaptchaCaptcha.js.map +1 -0
  97. package/dist/react/captcha/RecaptchaCaptcha.d.ts +41 -0
  98. package/dist/react/captcha/RecaptchaCaptcha.js +93 -0
  99. package/dist/react/captcha/RecaptchaCaptcha.js.map +1 -0
  100. package/dist/react/captcha/TurnstileCaptcha.d.ts +28 -0
  101. package/dist/react/captcha/TurnstileCaptcha.js +53 -0
  102. package/dist/react/captcha/TurnstileCaptcha.js.map +1 -0
  103. package/dist/react/captcha/types.d.ts +8 -0
  104. package/dist/react/captcha/useCaptchaScript.js +45 -0
  105. package/dist/react/captcha/useCaptchaScript.js.map +1 -0
  106. package/dist/react/captcha/vendors.js +8 -0
  107. package/dist/react/captcha/vendors.js.map +1 -0
  108. package/dist/react/primitives/Input.d.ts +1 -1
  109. package/dist/react/primitives/Input.js.map +1 -1
  110. package/dist/react/renderers/calculation.js +1 -1
  111. package/dist/react/renderers/checkbox.js +1 -1
  112. package/dist/react/renderers/consent.js +1 -1
  113. package/dist/react/renderers/date.js +37 -0
  114. package/dist/react/renderers/date.js.map +1 -0
  115. package/dist/react/renderers/email.js +1 -1
  116. package/dist/react/renderers/file.js +20 -7
  117. package/dist/react/renderers/file.js.map +1 -1
  118. package/dist/react/renderers/index.js +4 -0
  119. package/dist/react/renderers/index.js.map +1 -1
  120. package/dist/react/renderers/number.js +1 -1
  121. package/dist/react/renderers/repeater.js +113 -0
  122. package/dist/react/renderers/repeater.js.map +1 -0
  123. package/dist/react/renderers/select.js +1 -1
  124. package/dist/react/renderers/text.js +1 -1
  125. package/dist/react/renderers/textarea.js +1 -1
  126. package/dist/spam/captcha.d.ts +3 -2
  127. package/dist/spam/captcha.js +3 -2
  128. package/dist/spam/captcha.js.map +1 -1
  129. package/dist/spam/clientIp.js +9 -0
  130. package/dist/spam/clientIp.js.map +1 -0
  131. package/dist/spam/identify.js +3 -6
  132. package/dist/spam/identify.js.map +1 -1
  133. package/dist/spam/providers/hcaptcha.d.ts +17 -0
  134. package/dist/spam/providers/hcaptcha.js +18 -0
  135. package/dist/spam/providers/hcaptcha.js.map +1 -0
  136. package/dist/spam/providers/recaptcha.d.ts +23 -0
  137. package/dist/spam/providers/recaptcha.js +23 -0
  138. package/dist/spam/providers/recaptcha.js.map +1 -0
  139. package/dist/spam/providers/siteverify.js +34 -0
  140. package/dist/spam/providers/siteverify.js.map +1 -0
  141. package/dist/spam/providers/turnstile.d.ts +17 -0
  142. package/dist/spam/providers/turnstile.js +18 -0
  143. package/dist/spam/providers/turnstile.js.map +1 -0
  144. package/dist/spam/spamGuard.js +2 -5
  145. package/dist/spam/spamGuard.js.map +1 -1
  146. package/dist/spam/types.d.ts +2 -2
  147. package/dist/submissions/SubmissionAnswers.d.ts +2 -4
  148. package/dist/submissions/SubmissionAnswers.js +110 -34
  149. package/dist/submissions/SubmissionAnswers.js.map +1 -1
  150. package/dist/submissions/SubmissionAnswersClient.js +142 -0
  151. package/dist/submissions/SubmissionAnswersClient.js.map +1 -0
  152. package/dist/submissions/runSubmission.js +54 -2
  153. package/dist/submissions/runSubmission.js.map +1 -1
  154. package/dist/submissions/types.d.ts +2 -1
  155. package/dist/translations/en.js +52 -5
  156. package/dist/translations/en.js.map +1 -1
  157. package/dist/translations/keys.d.ts +51 -4
  158. package/dist/translations/keys.js +52 -5
  159. package/dist/translations/keys.js.map +1 -1
  160. package/dist/uploads/formatBytes.d.ts +9 -0
  161. package/dist/uploads/formatBytes.js +25 -0
  162. package/dist/uploads/formatBytes.js.map +1 -0
  163. package/dist/uploads/resolveFileRef.js +1 -1
  164. package/dist/uploads/resolveFileRef.js.map +1 -1
  165. package/dist/validation/builtin/index.d.ts +14 -0
  166. package/dist/validation/builtin/index.js +12 -1
  167. package/dist/validation/builtin/index.js.map +1 -1
  168. package/dist/validation/builtin/maxDate.js +23 -0
  169. package/dist/validation/builtin/maxDate.js.map +1 -0
  170. package/dist/validation/builtin/minDate.js +23 -0
  171. package/dist/validation/builtin/minDate.js.map +1 -0
  172. package/dist/validation/builtin/validateDateBound.js +18 -0
  173. package/dist/validation/builtin/validateDateBound.js.map +1 -0
  174. package/dist/validation/runValidation.js +1 -1
  175. package/dist/validation/runValidation.js.map +1 -1
  176. package/package.json +4 -3
  177. package/styles/form-builder.css +0 -190
@@ -1,9 +1,9 @@
1
1
  import { keys } from "../translations/keys.js";
2
2
  import { labelFor, labelForKey } from "../translations/server.js";
3
3
  import { isLoggedIn } from "../plugin/access.js";
4
+ import { normalizeCalc } from "../calc/normalizeCalc.js";
4
5
  import { buildActionBlocks } from "../actions/buildActionBlocks.js";
5
6
  import { resolveFormResultsRequest } from "../aggregation/resolveResultsRequest.js";
6
- import { normalizeCalc } from "../calc/normalizeCalc.js";
7
7
  import { buildConditionTypeMap } from "../conditions/conditionType.js";
8
8
  import { normalizeFormConditions } from "../conditions/normalizeConditions.js";
9
9
  import { buildFieldBlocks } from "../fields/buildFieldBlocks.js";
@@ -36,7 +36,7 @@ const providedFlowStepCount = (raw) => {
36
36
  const steps = raw.steps;
37
37
  return Array.isArray(steps) ? steps.length : 0;
38
38
  };
39
- const buildFormsCollection = ({ registry, ruleRegistry, consentRegistry, presentationRegistry = new Map(Object.entries(defaultPresentationDescriptors)), actionRegistry = /* @__PURE__ */ new Map() }) => {
39
+ const buildFormsCollection = ({ overrides, registry, ruleRegistry, consentRegistry, presentationRegistry = new Map(Object.entries(defaultPresentationDescriptors)), actionRegistry = /* @__PURE__ */ new Map() }) => {
40
40
  const conditionTypes = buildConditionTypeMap(registry);
41
41
  const FLOW_BUILDER_REF = "@10x-media/form-builder/client#FlowBuilder";
42
42
  const beforeValidate = ({ data, req }) => {
@@ -58,127 +58,155 @@ const buildFormsCollection = ({ registry, ruleRegistry, consentRegistry, present
58
58
  }
59
59
  return data;
60
60
  };
61
- return {
62
- slug: FORMS_SLUG,
63
- labels: {
64
- singular: "Form",
65
- plural: "Forms"
66
- },
67
- admin: {
68
- group: "Forms",
69
- useAsTitle: "title"
70
- },
71
- access: { read: () => true },
72
- hooks: { beforeValidate: [beforeValidate] },
73
- fields: [
74
- {
75
- name: "title",
76
- type: "text",
77
- required: true,
78
- label: labelForKey(keys.fieldTitle)
79
- },
80
- {
81
- name: "fields",
82
- type: "blocks",
83
- blocks: buildFieldBlocks(registry, ruleRegistry, consentRegistry)
84
- },
85
- {
86
- name: "flow",
87
- type: "json",
88
- validate: validateFlow,
89
- admin: { components: { Field: {
90
- path: FLOW_BUILDER_REF,
91
- clientProps: { conditionTypes }
92
- } } },
93
- typescriptSchema: [() => ({
61
+ const fieldsField = {
62
+ name: "fields",
63
+ type: "blocks",
64
+ blocks: buildFieldBlocks(registry, ruleRegistry, consentRegistry)
65
+ };
66
+ const flowField = {
67
+ name: "flow",
68
+ type: "json",
69
+ validate: validateFlow,
70
+ admin: { components: { Field: {
71
+ path: FLOW_BUILDER_REF,
72
+ clientProps: { conditionTypes }
73
+ } } },
74
+ typescriptSchema: [() => ({
75
+ type: "object",
76
+ required: ["steps"],
77
+ additionalProperties: false,
78
+ properties: { steps: {
79
+ type: "array",
80
+ items: {
94
81
  type: "object",
95
- required: ["steps"],
96
- additionalProperties: false,
97
- properties: { steps: {
98
- type: "array",
99
- items: {
100
- type: "object",
101
- required: ["id"],
102
- additionalProperties: true,
103
- properties: {
104
- id: { type: "string" },
105
- title: { type: "string" },
106
- fields: {
107
- type: "array",
108
- items: { type: "string" }
109
- },
110
- next: { type: "string" },
111
- transitions: {
112
- type: "array",
113
- items: {
82
+ required: ["id"],
83
+ additionalProperties: true,
84
+ properties: {
85
+ id: { type: "string" },
86
+ title: { type: "string" },
87
+ fields: {
88
+ type: "array",
89
+ items: { type: "string" }
90
+ },
91
+ next: { type: "string" },
92
+ transitions: {
93
+ type: "array",
94
+ items: {
95
+ type: "object",
96
+ required: ["to"],
97
+ additionalProperties: true,
98
+ properties: {
99
+ to: { type: "string" },
100
+ when: {
114
101
  type: "object",
115
- required: ["to"],
116
- additionalProperties: true,
117
- properties: {
118
- to: { type: "string" },
119
- when: {
120
- type: "object",
121
- additionalProperties: true
122
- }
123
- }
102
+ additionalProperties: true
124
103
  }
125
104
  }
126
105
  }
127
106
  }
128
- } }
129
- })]
130
- },
131
- {
132
- name: "actions",
133
- type: "blocks",
134
- blocks: buildActionBlocks(actionRegistry),
135
- label: labelForKey(keys.configActions),
136
- access: { read: isLoggedIn }
137
- },
138
- {
139
- name: "defaultPresentation",
140
- type: "select",
141
- defaultValue: DEFAULT_PRESENTATION_NAME,
142
- options: [...presentationRegistry.values()].map((descriptor) => ({
143
- label: labelFor(descriptor.label),
144
- value: descriptor.name
145
- })),
146
- label: labelForKey(keys.configDefaultPresentation),
147
- admin: { position: "sidebar" }
148
- },
149
- {
150
- name: "showResults",
151
- type: "checkbox",
152
- defaultValue: false,
153
- label: labelForKey(keys.configShowResults),
154
- admin: { position: "sidebar" }
155
- },
156
- {
157
- name: "resultsField",
158
- type: "text",
159
- label: labelForKey(keys.configResultsField),
160
- admin: {
161
- position: "sidebar",
162
- description: "Field whose aggregate results are public when \"Show results publicly\" is on. Use a choice field, never a free-text or PII field.",
163
- condition: (data) => Boolean(data?.showResults)
107
+ }
164
108
  }
109
+ } }
110
+ })]
111
+ };
112
+ const actionsField = {
113
+ name: "actions",
114
+ type: "blocks",
115
+ blocks: buildActionBlocks(actionRegistry),
116
+ label: labelForKey(keys.configActions),
117
+ access: { read: isLoggedIn }
118
+ };
119
+ const defaultFields = [
120
+ {
121
+ name: "title",
122
+ type: "text",
123
+ required: true,
124
+ label: labelForKey(keys.fieldTitle)
125
+ },
126
+ {
127
+ type: "tabs",
128
+ tabs: [
129
+ {
130
+ label: labelForKey(keys.tabFields),
131
+ fields: [fieldsField]
132
+ },
133
+ {
134
+ label: labelForKey(keys.tabFlow),
135
+ fields: [flowField]
136
+ },
137
+ {
138
+ label: labelForKey(keys.tabActions),
139
+ fields: [actionsField]
140
+ }
141
+ ]
142
+ },
143
+ {
144
+ name: "defaultPresentation",
145
+ type: "select",
146
+ defaultValue: DEFAULT_PRESENTATION_NAME,
147
+ options: [...presentationRegistry.values()].map((descriptor) => ({
148
+ label: labelFor(descriptor.label),
149
+ value: descriptor.name
150
+ })),
151
+ label: labelForKey(keys.configDefaultPresentation),
152
+ admin: { position: "sidebar" }
153
+ },
154
+ {
155
+ name: "showResults",
156
+ type: "checkbox",
157
+ defaultValue: false,
158
+ label: labelForKey(keys.configShowResults),
159
+ admin: { position: "sidebar" }
160
+ },
161
+ {
162
+ name: "resultsField",
163
+ type: "text",
164
+ label: labelForKey(keys.configResultsField),
165
+ admin: {
166
+ position: "sidebar",
167
+ description: "Field whose aggregate results are public when \"Show results publicly\" is on. Use a choice field, never a free-text or PII field.",
168
+ condition: (data) => Boolean(data?.showResults)
165
169
  }
166
- ],
167
- endpoints: [{
168
- path: "/:id/results",
169
- method: "get",
170
- handler: async (req) => {
171
- const field = typeof req.query?.field === "string" ? req.query.field : void 0;
172
- const { status, body } = await resolveFormResultsRequest({
173
- payload: req.payload,
174
- formId: req.routeParams?.id,
175
- field,
176
- isAuthed: Boolean(req.user),
177
- req
178
- });
179
- return Response.json(body, { status });
180
- }
181
- }]
170
+ }
171
+ ];
172
+ const defaultEndpoints = [{
173
+ path: "/:id/results",
174
+ method: "get",
175
+ handler: async (req) => {
176
+ const field = typeof req.query?.field === "string" ? req.query.field : void 0;
177
+ const { status, body } = await resolveFormResultsRequest({
178
+ payload: req.payload,
179
+ formId: req.routeParams?.id,
180
+ field,
181
+ isAuthed: Boolean(req.user),
182
+ req
183
+ });
184
+ return Response.json(body, { status });
185
+ }
186
+ }];
187
+ return {
188
+ ...overrides ?? {},
189
+ slug: FORMS_SLUG,
190
+ labels: {
191
+ singular: labelForKey(keys.collectionFormSingular),
192
+ plural: labelForKey(keys.collectionFormPlural),
193
+ ...overrides?.labels ?? {}
194
+ },
195
+ admin: {
196
+ group: "Forms",
197
+ useAsTitle: "title",
198
+ ...overrides?.admin ?? {}
199
+ },
200
+ access: {
201
+ read: () => true,
202
+ ...overrides?.access ?? {}
203
+ },
204
+ hooks: {
205
+ ...overrides?.hooks ?? {},
206
+ beforeValidate: [beforeValidate, ...overrides?.hooks?.beforeValidate ?? []]
207
+ },
208
+ endpoints: [...defaultEndpoints, ...Array.isArray(overrides?.endpoints) ? overrides.endpoints : []],
209
+ fields: overrides?.fields ? overrides.fields({ defaultFields }) : defaultFields
182
210
  };
183
211
  };
184
212
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"forms.js","names":[],"sources":["../../src/collections/forms.ts"],"sourcesContent":["import {\n\ttype CollectionBeforeValidateHook,\n\ttype CollectionConfig,\n\ttype PayloadRequest,\n\tValidationError,\n} from 'payload'\nimport { buildActionBlocks } from '../actions/buildActionBlocks'\nimport type { ActionRegistry } from '../actions/registry'\nimport { resolveFormResultsRequest } from '../aggregation/resolveResultsRequest'\nimport { normalizeCalc } from '../calc/normalizeCalc'\nimport { buildConditionTypeMap } from '../conditions/conditionType'\nimport { type FieldRow, normalizeFormConditions } from '../conditions/normalizeConditions'\nimport type { ConsentSourceRegistry } from '../consent/registry'\nimport { buildFieldBlocks } from '../fields/buildFieldBlocks'\nimport type { FieldTypeRegistry } from '../fields/registry'\nimport { normalizeFlow } from '../flow/normalizeFlow'\nimport { isLoggedIn } from '../plugin/access'\nimport {\n\tDEFAULT_PRESENTATION_NAME,\n\tdefaultPresentationDescriptors,\n} from '../presentations/defaults'\nimport type { PresentationDescriptorRegistry } from '../presentations/registry'\nimport { keys } from '../translations/keys'\nimport { labelFor, labelForKey } from '../translations/server'\nimport type { ValidationRuleRegistry } from '../validation/registry'\n\nexport const FORMS_SLUG = 'forms'\n\nconst validateFlow = (raw: unknown): string | true => {\n\tif (raw === null || raw === undefined) return true\n\tconst r = raw as Record<string, unknown>\n\tif (!Array.isArray(r.steps)) return true\n\tconst steps = r.steps as Array<Record<string, unknown>>\n\tconst emptyIdStep = steps.find((s) => typeof s?.id !== 'string' || s.id.length === 0)\n\tif (emptyIdStep) return 'Flow: every step must have a non-empty ID'\n\tconst ids = steps.map((s) => s.id as string)\n\tif (new Set(ids).size !== ids.length) {\n\t\treturn 'Flow: duplicate step IDs found'\n\t}\n\tconst idSet = new Set(ids)\n\tfor (const step of steps) {\n\t\tconst id = step.id as string\n\t\tif (typeof step.next === 'string' && step.next.length > 0 && !idSet.has(step.next)) {\n\t\t\treturn `Flow: step \"${id}\" references unknown next step \"${step.next}\"`\n\t\t}\n\t\tif (Array.isArray(step.transitions)) {\n\t\t\tfor (const t of step.transitions as Array<Record<string, unknown>>) {\n\t\t\t\tif (typeof t?.to === 'string' && t.to.length > 0 && !idSet.has(t.to)) {\n\t\t\t\t\treturn `Flow: step \"${id}\" has a transition to unknown step \"${t.to}\"`\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn true\n}\n\n/** How many steps the caller actually submitted, before normalization strips/collapses the flow. */\nconst providedFlowStepCount = (raw: unknown): number => {\n\tif (raw === null || typeof raw !== 'object') return 0\n\tconst steps = (raw as { steps?: unknown }).steps\n\treturn Array.isArray(steps) ? steps.length : 0\n}\n\ntype BuildFormsCollectionArgs = {\n\tregistry: FieldTypeRegistry\n\truleRegistry: ValidationRuleRegistry\n\tconsentRegistry?: ConsentSourceRegistry\n\tpresentationRegistry?: PresentationDescriptorRegistry\n\tactionRegistry?: ActionRegistry\n}\n\nexport const buildFormsCollection = ({\n\tregistry,\n\truleRegistry,\n\tconsentRegistry,\n\tpresentationRegistry = new Map(Object.entries(defaultPresentationDescriptors)),\n\tactionRegistry = new Map(),\n}: BuildFormsCollectionArgs): CollectionConfig => {\n\tconst conditionTypes = buildConditionTypeMap(registry)\n\tconst FLOW_BUILDER_REF = '@10x-media/form-builder/client#FlowBuilder'\n\n\tconst beforeValidate: CollectionBeforeValidateHook = ({ data, req }) => {\n\t\tif (\n\t\t\tdata &&\n\t\t\ttypeof data.defaultPresentation === 'string' &&\n\t\t\t!presentationRegistry.has(data.defaultPresentation)\n\t\t) {\n\t\t\tdata.defaultPresentation = DEFAULT_PRESENTATION_NAME\n\t\t}\n\t\tif (data && Array.isArray(data.fields)) {\n\t\t\tconst normalized: FieldRow[] = normalizeFormConditions(\n\t\t\t\tdata.fields as FieldRow[],\n\t\t\t\tconditionTypes\n\t\t\t)\n\t\t\tfor (const field of normalized) {\n\t\t\t\tif ('expression' in field) {\n\t\t\t\t\tfield.expression = normalizeCalc(field.expression)\n\t\t\t\t}\n\t\t\t}\n\t\t\tdata.fields = normalized\n\t\t\tconst fieldNames = normalized\n\t\t\t\t.map((field: FieldRow) => (typeof field.name === 'string' ? field.name : undefined))\n\t\t\t\t.filter((name): name is string => name !== undefined)\n\t\t\tconst normalizedFlow = normalizeFlow(data.flow, fieldNames)\n\t\t\t// A flow the author built but that collapses to fewer than two valid steps would\n\t\t\t// otherwise vanish silently. Surface it instead of discarding their work.\n\t\t\tif (providedFlowStepCount(data.flow) > 0 && normalizedFlow === undefined) {\n\t\t\t\tthrow new ValidationError(\n\t\t\t\t\t{\n\t\t\t\t\t\tcollection: FORMS_SLUG,\n\t\t\t\t\t\terrors: [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tpath: 'flow',\n\t\t\t\t\t\t\t\tmessage:\n\t\t\t\t\t\t\t\t\t'A flow needs at least two steps with unique, non-empty IDs. Add another step or remove the flow.',\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t],\n\t\t\t\t\t},\n\t\t\t\t\treq.t\n\t\t\t\t)\n\t\t\t}\n\t\t\tdata.flow = normalizedFlow\n\t\t}\n\t\treturn data\n\t}\n\n\treturn {\n\t\tslug: FORMS_SLUG,\n\t\tlabels: { singular: 'Form', plural: 'Forms' },\n\t\tadmin: { group: 'Forms', useAsTitle: 'title' },\n\t\taccess: { read: () => true },\n\t\thooks: {\n\t\t\tbeforeValidate: [beforeValidate],\n\t\t},\n\t\tfields: [\n\t\t\t{ name: 'title', type: 'text', required: true, label: labelForKey(keys.fieldTitle) },\n\t\t\t{\n\t\t\t\tname: 'fields',\n\t\t\t\ttype: 'blocks',\n\t\t\t\tblocks: buildFieldBlocks(registry, ruleRegistry, consentRegistry),\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: 'flow',\n\t\t\t\ttype: 'json',\n\t\t\t\tvalidate: validateFlow,\n\t\t\t\tadmin: {\n\t\t\t\t\tcomponents: {\n\t\t\t\t\t\tField: { path: FLOW_BUILDER_REF, clientProps: { conditionTypes } },\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t// Narrows the generated TypeScript type from opaque JSON to FormFlow so callers\n\t\t\t\t// don't need a cast. Keep this in sync with src/flow/types.ts.\n\t\t\t\ttypescriptSchema: [\n\t\t\t\t\t() => ({\n\t\t\t\t\t\ttype: 'object' as const,\n\t\t\t\t\t\trequired: ['steps'],\n\t\t\t\t\t\tadditionalProperties: false,\n\t\t\t\t\t\tproperties: {\n\t\t\t\t\t\t\tsteps: {\n\t\t\t\t\t\t\t\ttype: 'array' as const,\n\t\t\t\t\t\t\t\titems: {\n\t\t\t\t\t\t\t\t\ttype: 'object' as const,\n\t\t\t\t\t\t\t\t\trequired: ['id'],\n\t\t\t\t\t\t\t\t\tadditionalProperties: true,\n\t\t\t\t\t\t\t\t\tproperties: {\n\t\t\t\t\t\t\t\t\t\tid: { type: 'string' as const },\n\t\t\t\t\t\t\t\t\t\ttitle: { type: 'string' as const },\n\t\t\t\t\t\t\t\t\t\tfields: { type: 'array' as const, items: { type: 'string' as const } },\n\t\t\t\t\t\t\t\t\t\tnext: { type: 'string' as const },\n\t\t\t\t\t\t\t\t\t\ttransitions: {\n\t\t\t\t\t\t\t\t\t\t\ttype: 'array' as const,\n\t\t\t\t\t\t\t\t\t\t\titems: {\n\t\t\t\t\t\t\t\t\t\t\t\ttype: 'object' as const,\n\t\t\t\t\t\t\t\t\t\t\t\trequired: ['to'],\n\t\t\t\t\t\t\t\t\t\t\t\tadditionalProperties: true,\n\t\t\t\t\t\t\t\t\t\t\t\tproperties: {\n\t\t\t\t\t\t\t\t\t\t\t\t\tto: { type: 'string' as const },\n\t\t\t\t\t\t\t\t\t\t\t\t\twhen: { type: 'object' as const, additionalProperties: true },\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t}),\n\t\t\t\t],\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: 'actions',\n\t\t\t\ttype: 'blocks',\n\t\t\t\tblocks: buildActionBlocks(actionRegistry),\n\t\t\t\tlabel: labelForKey(keys.configActions),\n\t\t\t\t// Action config can contain secrets (e.g. signedWebhook.secret). The collection\n\t\t\t\t// itself is publicly readable so forms can be rendered by anonymous clients, but\n\t\t\t\t// action config must never be exposed to anonymous callers.\n\t\t\t\taccess: { read: isLoggedIn },\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: 'defaultPresentation',\n\t\t\t\ttype: 'select',\n\t\t\t\tdefaultValue: DEFAULT_PRESENTATION_NAME,\n\t\t\t\toptions: [...presentationRegistry.values()].map((descriptor) => ({\n\t\t\t\t\tlabel: labelFor(descriptor.label),\n\t\t\t\t\tvalue: descriptor.name,\n\t\t\t\t})),\n\t\t\t\tlabel: labelForKey(keys.configDefaultPresentation),\n\t\t\t\tadmin: { position: 'sidebar' },\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: 'showResults',\n\t\t\t\ttype: 'checkbox',\n\t\t\t\tdefaultValue: false,\n\t\t\t\tlabel: labelForKey(keys.configShowResults),\n\t\t\t\tadmin: { position: 'sidebar' },\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: 'resultsField',\n\t\t\t\ttype: 'text',\n\t\t\t\tlabel: labelForKey(keys.configResultsField),\n\t\t\t\tadmin: {\n\t\t\t\t\tposition: 'sidebar',\n\t\t\t\t\tdescription:\n\t\t\t\t\t\t'Field whose aggregate results are public when \"Show results publicly\" is on. Use a choice field, never a free-text or PII field.',\n\t\t\t\t\tcondition: (data) => Boolean(data?.showResults),\n\t\t\t\t},\n\t\t\t},\n\t\t],\n\t\tendpoints: [\n\t\t\t{\n\t\t\t\tpath: '/:id/results',\n\t\t\t\tmethod: 'get',\n\t\t\t\thandler: async (req: PayloadRequest) => {\n\t\t\t\t\tconst field = typeof req.query?.field === 'string' ? req.query.field : undefined\n\t\t\t\t\tconst { status, body } = await resolveFormResultsRequest({\n\t\t\t\t\t\tpayload: req.payload,\n\t\t\t\t\t\tformId: req.routeParams?.id as number | string | undefined,\n\t\t\t\t\t\tfield,\n\t\t\t\t\t\tisAuthed: Boolean(req.user),\n\t\t\t\t\t\treq,\n\t\t\t\t\t})\n\t\t\t\t\treturn Response.json(body, { status })\n\t\t\t\t},\n\t\t\t},\n\t\t],\n\t}\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"forms.js","names":[],"sources":["../../src/collections/forms.ts"],"sourcesContent":["import {\n\ttype CollectionBeforeValidateHook,\n\ttype CollectionConfig,\n\ttype Field,\n\ttype PayloadRequest,\n\tValidationError,\n} from 'payload'\nimport { buildActionBlocks } from '../actions/buildActionBlocks'\nimport type { ActionRegistry } from '../actions/registry'\nimport { resolveFormResultsRequest } from '../aggregation/resolveResultsRequest'\nimport { normalizeCalc } from '../calc/normalizeCalc'\nimport { buildConditionTypeMap } from '../conditions/conditionType'\nimport { type FieldRow, normalizeFormConditions } from '../conditions/normalizeConditions'\nimport type { ConsentSourceRegistry } from '../consent/registry'\nimport { buildFieldBlocks } from '../fields/buildFieldBlocks'\nimport type { FieldTypeRegistry } from '../fields/registry'\nimport { normalizeFlow } from '../flow/normalizeFlow'\nimport { isLoggedIn } from '../plugin/access'\nimport type { CollectionOverrides } from '../plugin/collectionOverrides'\nimport {\n\tDEFAULT_PRESENTATION_NAME,\n\tdefaultPresentationDescriptors,\n} from '../presentations/defaults'\nimport type { PresentationDescriptorRegistry } from '../presentations/registry'\nimport { keys } from '../translations/keys'\nimport { labelFor, labelForKey } from '../translations/server'\nimport type { ValidationRuleRegistry } from '../validation/registry'\n\nexport const FORMS_SLUG = 'forms'\n\nconst validateFlow = (raw: unknown): string | true => {\n\tif (raw === null || raw === undefined) return true\n\tconst r = raw as Record<string, unknown>\n\tif (!Array.isArray(r.steps)) return true\n\tconst steps = r.steps as Array<Record<string, unknown>>\n\tconst emptyIdStep = steps.find((s) => typeof s?.id !== 'string' || s.id.length === 0)\n\tif (emptyIdStep) return 'Flow: every step must have a non-empty ID'\n\tconst ids = steps.map((s) => s.id as string)\n\tif (new Set(ids).size !== ids.length) {\n\t\treturn 'Flow: duplicate step IDs found'\n\t}\n\tconst idSet = new Set(ids)\n\tfor (const step of steps) {\n\t\tconst id = step.id as string\n\t\tif (typeof step.next === 'string' && step.next.length > 0 && !idSet.has(step.next)) {\n\t\t\treturn `Flow: step \"${id}\" references unknown next step \"${step.next}\"`\n\t\t}\n\t\tif (Array.isArray(step.transitions)) {\n\t\t\tfor (const t of step.transitions as Array<Record<string, unknown>>) {\n\t\t\t\tif (typeof t?.to === 'string' && t.to.length > 0 && !idSet.has(t.to)) {\n\t\t\t\t\treturn `Flow: step \"${id}\" has a transition to unknown step \"${t.to}\"`\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn true\n}\n\n/** How many steps the caller actually submitted, before normalization strips/collapses the flow. */\nconst providedFlowStepCount = (raw: unknown): number => {\n\tif (raw === null || typeof raw !== 'object') return 0\n\tconst steps = (raw as { steps?: unknown }).steps\n\treturn Array.isArray(steps) ? steps.length : 0\n}\n\ntype BuildFormsCollectionArgs = {\n\tregistry: FieldTypeRegistry\n\truleRegistry: ValidationRuleRegistry\n\tconsentRegistry?: ConsentSourceRegistry\n\tpresentationRegistry?: PresentationDescriptorRegistry\n\tactionRegistry?: ActionRegistry\n\toverrides?: CollectionOverrides\n}\n\nexport const buildFormsCollection = ({\n\toverrides,\n\tregistry,\n\truleRegistry,\n\tconsentRegistry,\n\tpresentationRegistry = new Map(Object.entries(defaultPresentationDescriptors)),\n\tactionRegistry = new Map(),\n}: BuildFormsCollectionArgs): CollectionConfig => {\n\tconst conditionTypes = buildConditionTypeMap(registry)\n\tconst FLOW_BUILDER_REF = '@10x-media/form-builder/client#FlowBuilder'\n\n\tconst beforeValidate: CollectionBeforeValidateHook = ({ data, req }) => {\n\t\tif (\n\t\t\tdata &&\n\t\t\ttypeof data.defaultPresentation === 'string' &&\n\t\t\t!presentationRegistry.has(data.defaultPresentation)\n\t\t) {\n\t\t\tdata.defaultPresentation = DEFAULT_PRESENTATION_NAME\n\t\t}\n\t\tif (data && Array.isArray(data.fields)) {\n\t\t\tconst normalized: FieldRow[] = normalizeFormConditions(\n\t\t\t\tdata.fields as FieldRow[],\n\t\t\t\tconditionTypes\n\t\t\t)\n\t\t\tfor (const field of normalized) {\n\t\t\t\tif ('expression' in field) {\n\t\t\t\t\tfield.expression = normalizeCalc(field.expression)\n\t\t\t\t}\n\t\t\t}\n\t\t\tdata.fields = normalized\n\t\t\tconst fieldNames = normalized\n\t\t\t\t.map((field: FieldRow) => (typeof field.name === 'string' ? field.name : undefined))\n\t\t\t\t.filter((name): name is string => name !== undefined)\n\t\t\tconst normalizedFlow = normalizeFlow(data.flow, fieldNames)\n\t\t\t// A flow the author built but that collapses to fewer than two valid steps would\n\t\t\t// otherwise vanish silently. Surface it instead of discarding their work.\n\t\t\tif (providedFlowStepCount(data.flow) > 0 && normalizedFlow === undefined) {\n\t\t\t\tthrow new ValidationError(\n\t\t\t\t\t{\n\t\t\t\t\t\tcollection: FORMS_SLUG,\n\t\t\t\t\t\terrors: [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tpath: 'flow',\n\t\t\t\t\t\t\t\tmessage:\n\t\t\t\t\t\t\t\t\t'A flow needs at least two steps with unique, non-empty IDs. Add another step or remove the flow.',\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t],\n\t\t\t\t\t},\n\t\t\t\t\treq.t\n\t\t\t\t)\n\t\t\t}\n\t\t\tdata.flow = normalizedFlow\n\t\t}\n\t\treturn data\n\t}\n\n\tconst fieldsField: Field = {\n\t\tname: 'fields',\n\t\ttype: 'blocks',\n\t\tblocks: buildFieldBlocks(registry, ruleRegistry, consentRegistry),\n\t}\n\n\tconst flowField: Field = {\n\t\tname: 'flow',\n\t\ttype: 'json',\n\t\tvalidate: validateFlow,\n\t\tadmin: {\n\t\t\tcomponents: {\n\t\t\t\tField: { path: FLOW_BUILDER_REF, clientProps: { conditionTypes } },\n\t\t\t},\n\t\t},\n\t\t// Narrows the generated TypeScript type from opaque JSON to FormFlow so callers\n\t\t// don't need a cast. Keep this in sync with src/flow/types.ts.\n\t\ttypescriptSchema: [\n\t\t\t() => ({\n\t\t\t\ttype: 'object' as const,\n\t\t\t\trequired: ['steps'],\n\t\t\t\tadditionalProperties: false,\n\t\t\t\tproperties: {\n\t\t\t\t\tsteps: {\n\t\t\t\t\t\ttype: 'array' as const,\n\t\t\t\t\t\titems: {\n\t\t\t\t\t\t\ttype: 'object' as const,\n\t\t\t\t\t\t\trequired: ['id'],\n\t\t\t\t\t\t\tadditionalProperties: true,\n\t\t\t\t\t\t\tproperties: {\n\t\t\t\t\t\t\t\tid: { type: 'string' as const },\n\t\t\t\t\t\t\t\ttitle: { type: 'string' as const },\n\t\t\t\t\t\t\t\tfields: { type: 'array' as const, items: { type: 'string' as const } },\n\t\t\t\t\t\t\t\tnext: { type: 'string' as const },\n\t\t\t\t\t\t\t\ttransitions: {\n\t\t\t\t\t\t\t\t\ttype: 'array' as const,\n\t\t\t\t\t\t\t\t\titems: {\n\t\t\t\t\t\t\t\t\t\ttype: 'object' as const,\n\t\t\t\t\t\t\t\t\t\trequired: ['to'],\n\t\t\t\t\t\t\t\t\t\tadditionalProperties: true,\n\t\t\t\t\t\t\t\t\t\tproperties: {\n\t\t\t\t\t\t\t\t\t\t\tto: { type: 'string' as const },\n\t\t\t\t\t\t\t\t\t\t\twhen: { type: 'object' as const, additionalProperties: true },\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t}),\n\t\t],\n\t}\n\n\tconst actionsField: Field = {\n\t\tname: 'actions',\n\t\ttype: 'blocks',\n\t\tblocks: buildActionBlocks(actionRegistry),\n\t\tlabel: labelForKey(keys.configActions),\n\t\t// Action config can contain secrets (e.g. signedWebhook.secret). The collection\n\t\t// itself is publicly readable so forms can be rendered by anonymous clients, but\n\t\t// action config must never be exposed to anonymous callers.\n\t\taccess: { read: isLoggedIn },\n\t}\n\n\tconst defaultFields: Field[] = [\n\t\t{ name: 'title', type: 'text', required: true, label: labelForKey(keys.fieldTitle) },\n\t\t// Unnamed tabs are presentational only: fields/flow/actions stay at the document root.\n\t\t{\n\t\t\ttype: 'tabs',\n\t\t\ttabs: [\n\t\t\t\t{ label: labelForKey(keys.tabFields), fields: [fieldsField] },\n\t\t\t\t{ label: labelForKey(keys.tabFlow), fields: [flowField] },\n\t\t\t\t{ label: labelForKey(keys.tabActions), fields: [actionsField] },\n\t\t\t],\n\t\t},\n\t\t{\n\t\t\tname: 'defaultPresentation',\n\t\t\ttype: 'select',\n\t\t\tdefaultValue: DEFAULT_PRESENTATION_NAME,\n\t\t\toptions: [...presentationRegistry.values()].map((descriptor) => ({\n\t\t\t\tlabel: labelFor(descriptor.label),\n\t\t\t\tvalue: descriptor.name,\n\t\t\t})),\n\t\t\tlabel: labelForKey(keys.configDefaultPresentation),\n\t\t\tadmin: { position: 'sidebar' },\n\t\t},\n\t\t{\n\t\t\tname: 'showResults',\n\t\t\ttype: 'checkbox',\n\t\t\tdefaultValue: false,\n\t\t\tlabel: labelForKey(keys.configShowResults),\n\t\t\tadmin: { position: 'sidebar' },\n\t\t},\n\t\t{\n\t\t\tname: 'resultsField',\n\t\t\ttype: 'text',\n\t\t\tlabel: labelForKey(keys.configResultsField),\n\t\t\tadmin: {\n\t\t\t\tposition: 'sidebar',\n\t\t\t\tdescription:\n\t\t\t\t\t'Field whose aggregate results are public when \"Show results publicly\" is on. Use a choice field, never a free-text or PII field.',\n\t\t\t\tcondition: (data) => Boolean(data?.showResults),\n\t\t\t},\n\t\t},\n\t]\n\n\tconst defaultEndpoints: CollectionConfig['endpoints'] = [\n\t\t{\n\t\t\tpath: '/:id/results',\n\t\t\tmethod: 'get',\n\t\t\thandler: async (req: PayloadRequest) => {\n\t\t\t\tconst field = typeof req.query?.field === 'string' ? req.query.field : undefined\n\t\t\t\tconst { status, body } = await resolveFormResultsRequest({\n\t\t\t\t\tpayload: req.payload,\n\t\t\t\t\tformId: req.routeParams?.id as number | string | undefined,\n\t\t\t\t\tfield,\n\t\t\t\t\tisAuthed: Boolean(req.user),\n\t\t\t\t\treq,\n\t\t\t\t})\n\t\t\t\treturn Response.json(body, { status })\n\t\t\t},\n\t\t},\n\t]\n\n\treturn {\n\t\t...(overrides ?? {}),\n\t\tslug: FORMS_SLUG,\n\t\tlabels: {\n\t\t\tsingular: labelForKey(keys.collectionFormSingular),\n\t\t\tplural: labelForKey(keys.collectionFormPlural),\n\t\t\t...(overrides?.labels ?? {}),\n\t\t},\n\t\tadmin: { group: 'Forms', useAsTitle: 'title', ...(overrides?.admin ?? {}) },\n\t\taccess: { read: () => true, ...(overrides?.access ?? {}) },\n\t\thooks: {\n\t\t\t...(overrides?.hooks ?? {}),\n\t\t\t// beforeValidate normalizes conditions and flow; consumer hooks run after\n\t\t\tbeforeValidate: [beforeValidate, ...(overrides?.hooks?.beforeValidate ?? [])],\n\t\t},\n\t\tendpoints: [\n\t\t\t...defaultEndpoints,\n\t\t\t...(Array.isArray(overrides?.endpoints) ? overrides.endpoints : []),\n\t\t],\n\t\tfields: overrides?.fields ? overrides.fields({ defaultFields }) : defaultFields,\n\t}\n}\n"],"mappings":"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"}
@@ -1,3 +1,4 @@
1
+ import { CollectionOverrides } from "../plugin/collectionOverrides.js";
1
2
  import { CollectionConfig } from "payload";
2
3
 
3
4
  //#region src/collections/uploads.d.ts
@@ -17,7 +18,7 @@ type UploadsOption = boolean | UploadsCollectionConfig;
17
18
  * `imageSizes`, so it needs no `sharp`. Projects with their own upload collection set `uploads: false` and
18
19
  * point the file field's `relationTo` at theirs.
19
20
  */
20
- declare const buildUploadsCollection: (config?: UploadsCollectionConfig) => CollectionConfig;
21
+ declare const buildUploadsCollection: (config?: UploadsCollectionConfig, overrides?: CollectionOverrides) => CollectionConfig;
21
22
  /** Resolve the `uploads` plugin option: `false` disables, `true`/object enables the built-in collection. */
22
23
  declare const resolveUploads: (option: UploadsOption | undefined) => {
23
24
  enabled: boolean;
@@ -8,25 +8,34 @@ const FORM_UPLOADS_SLUG = "form-uploads";
8
8
  * `imageSizes`, so it needs no `sharp`. Projects with their own upload collection set `uploads: false` and
9
9
  * point the file field's `relationTo` at theirs.
10
10
  */
11
- const buildUploadsCollection = (config = {}) => ({
12
- slug: config.slug ?? "form-uploads",
13
- access: config.access ?? {
14
- create: () => true,
15
- read: isLoggedIn,
16
- update: isLoggedIn,
17
- delete: isLoggedIn
18
- },
19
- admin: { group: "Forms" },
20
- upload: config.upload && config.upload !== true ? config.upload : true,
21
- fields: [{
11
+ const buildUploadsCollection = (config = {}, overrides) => {
12
+ const defaultFields = [{
22
13
  name: "owner",
23
14
  type: "text",
24
15
  admin: {
25
16
  readOnly: true,
26
17
  hidden: true
27
18
  }
28
- }, ...config.fields ?? []]
29
- });
19
+ }, ...config.fields ?? []];
20
+ return {
21
+ ...overrides ?? {},
22
+ slug: config.slug ?? "form-uploads",
23
+ access: {
24
+ create: () => true,
25
+ read: isLoggedIn,
26
+ update: isLoggedIn,
27
+ delete: isLoggedIn,
28
+ ...config.access ?? {},
29
+ ...overrides?.access ?? {}
30
+ },
31
+ admin: {
32
+ group: "Forms",
33
+ ...overrides?.admin ?? {}
34
+ },
35
+ upload: config.upload && config.upload !== true ? config.upload : true,
36
+ fields: overrides?.fields ? overrides.fields({ defaultFields }) : defaultFields
37
+ };
38
+ };
30
39
  /** Resolve the `uploads` plugin option: `false` disables, `true`/object enables the built-in collection. */
31
40
  const resolveUploads = (option) => {
32
41
  if (option === false) return {
@@ -1 +1 @@
1
- {"version":3,"file":"uploads.js","names":[],"sources":["../../src/collections/uploads.ts"],"sourcesContent":["import type { CollectionConfig } from 'payload'\nimport { isLoggedIn } from '../plugin/access'\n\nexport const FORM_UPLOADS_SLUG = 'form-uploads'\n\n/** Override surface for the built-in upload collection. */\nexport type UploadsCollectionConfig = {\n\tslug?: string\n\t/** Merged onto the collection's `upload` config (e.g. `staticDir`, `mimeTypes`). `true` uses Payload defaults. */\n\tupload?: NonNullable<CollectionConfig['upload']> | true\n\t/** Replace access (defaults: anonymous create, authed read/update/delete). */\n\taccess?: CollectionConfig['access']\n\t/** Append extra fields. */\n\tfields?: CollectionConfig['fields']\n}\n\nexport type UploadsOption = boolean | UploadsCollectionConfig\n\n/**\n * The built-in upload collection backing the `file` field. Anonymous create (public forms upload here),\n * authed read/update/delete (only admins read stored files; submitters cannot enumerate others' uploads).\n * Per-field MIME/size is re-enforced at submit, so the collection stays permissive by default. No\n * `imageSizes`, so it needs no `sharp`. Projects with their own upload collection set `uploads: false` and\n * point the file field's `relationTo` at theirs.\n */\nexport const buildUploadsCollection = (config: UploadsCollectionConfig = {}): CollectionConfig => ({\n\tslug: config.slug ?? FORM_UPLOADS_SLUG,\n\taccess: config.access ?? {\n\t\tcreate: () => true,\n\t\tread: isLoggedIn,\n\t\tupdate: isLoggedIn,\n\t\tdelete: isLoggedIn,\n\t},\n\tadmin: { group: 'Forms' },\n\tupload: config.upload && config.upload !== true ? config.upload : true,\n\tfields: [\n\t\t{ name: 'owner', type: 'text', admin: { readOnly: true, hidden: true } },\n\t\t...(config.fields ?? []),\n\t],\n})\n\n/** Resolve the `uploads` plugin option: `false` disables, `true`/object enables the built-in collection. */\nexport const resolveUploads = (\n\toption: UploadsOption | undefined\n): { enabled: boolean; slug: string; collection?: CollectionConfig } => {\n\tif (option === false) {\n\t\treturn { enabled: false, slug: FORM_UPLOADS_SLUG }\n\t}\n\tconst config = option && option !== true ? option : {}\n\tconst collection = buildUploadsCollection(config)\n\treturn { enabled: true, slug: collection.slug, collection }\n}\n"],"mappings":";;AAGA,MAAa,oBAAoB;;;;;;;;AAsBjC,MAAa,0BAA0B,SAAkC,CAAC,OAAyB;CAClG,MAAM,OAAO,QAAA;CACb,QAAQ,OAAO,UAAU;EACxB,cAAc;EACd,MAAM;EACN,QAAQ;EACR,QAAQ;CACT;CACA,OAAO,EAAE,OAAO,QAAQ;CACxB,QAAQ,OAAO,UAAU,OAAO,WAAW,OAAO,OAAO,SAAS;CAClE,QAAQ,CACP;EAAE,MAAM;EAAS,MAAM;EAAQ,OAAO;GAAE,UAAU;GAAM,QAAQ;EAAK;CAAE,GACvE,GAAI,OAAO,UAAU,CAAC,CACvB;AACD;;AAGA,MAAa,kBACZ,WACuE;CACvE,IAAI,WAAW,OACd,OAAO;EAAE,SAAS;EAAO,MAAM;CAAkB;CAGlD,MAAM,aAAa,uBADJ,UAAU,WAAW,OAAO,SAAS,CAAC,CACL;CAChD,OAAO;EAAE,SAAS;EAAM,MAAM,WAAW;EAAM;CAAW;AAC3D"}
1
+ {"version":3,"file":"uploads.js","names":[],"sources":["../../src/collections/uploads.ts"],"sourcesContent":["import type { CollectionConfig, Field } from 'payload'\nimport { isLoggedIn } from '../plugin/access'\nimport type { CollectionOverrides } from '../plugin/collectionOverrides'\n\nexport const FORM_UPLOADS_SLUG = 'form-uploads'\n\n/** Override surface for the built-in upload collection. */\nexport type UploadsCollectionConfig = {\n\tslug?: string\n\t/** Merged onto the collection's `upload` config (e.g. `staticDir`, `mimeTypes`). `true` uses Payload defaults. */\n\tupload?: NonNullable<CollectionConfig['upload']> | true\n\t/** Replace access (defaults: anonymous create, authed read/update/delete). */\n\taccess?: CollectionConfig['access']\n\t/** Append extra fields. */\n\tfields?: CollectionConfig['fields']\n}\n\nexport type UploadsOption = boolean | UploadsCollectionConfig\n\n/**\n * The built-in upload collection backing the `file` field. Anonymous create (public forms upload here),\n * authed read/update/delete (only admins read stored files; submitters cannot enumerate others' uploads).\n * Per-field MIME/size is re-enforced at submit, so the collection stays permissive by default. No\n * `imageSizes`, so it needs no `sharp`. Projects with their own upload collection set `uploads: false` and\n * point the file field's `relationTo` at theirs.\n */\nexport const buildUploadsCollection = (\n\tconfig: UploadsCollectionConfig = {},\n\toverrides?: CollectionOverrides\n): CollectionConfig => {\n\tconst defaultFields: Field[] = [\n\t\t{ name: 'owner', type: 'text', admin: { readOnly: true, hidden: true } },\n\t\t...(config.fields ?? []),\n\t]\n\n\treturn {\n\t\t...(overrides ?? {}),\n\t\tslug: config.slug ?? FORM_UPLOADS_SLUG,\n\t\taccess: {\n\t\t\tcreate: () => true,\n\t\t\tread: isLoggedIn,\n\t\t\tupdate: isLoggedIn,\n\t\t\tdelete: isLoggedIn,\n\t\t\t...(config.access ?? {}),\n\t\t\t...(overrides?.access ?? {}),\n\t\t},\n\t\tadmin: { group: 'Forms', ...(overrides?.admin ?? {}) },\n\t\tupload: config.upload && config.upload !== true ? config.upload : true,\n\t\tfields: overrides?.fields ? overrides.fields({ defaultFields }) : defaultFields,\n\t}\n}\n\n/** Resolve the `uploads` plugin option: `false` disables, `true`/object enables the built-in collection. */\nexport const resolveUploads = (\n\toption: UploadsOption | undefined\n): { enabled: boolean; slug: string; collection?: CollectionConfig } => {\n\tif (option === false) {\n\t\treturn { enabled: false, slug: FORM_UPLOADS_SLUG }\n\t}\n\tconst config = option && option !== true ? option : {}\n\tconst collection = buildUploadsCollection(config)\n\treturn { enabled: true, slug: collection.slug as string, collection }\n}\n"],"mappings":";;AAIA,MAAa,oBAAoB;;;;;;;;AAsBjC,MAAa,0BACZ,SAAkC,CAAC,GACnC,cACsB;CACtB,MAAM,gBAAyB,CAC9B;EAAE,MAAM;EAAS,MAAM;EAAQ,OAAO;GAAE,UAAU;GAAM,QAAQ;EAAK;CAAE,GACvE,GAAI,OAAO,UAAU,CAAC,CACvB;CAEA,OAAO;EACN,GAAI,aAAa,CAAC;EAClB,MAAM,OAAO,QAAA;EACb,QAAQ;GACP,cAAc;GACd,MAAM;GACN,QAAQ;GACR,QAAQ;GACR,GAAI,OAAO,UAAU,CAAC;GACtB,GAAI,WAAW,UAAU,CAAC;EAC3B;EACA,OAAO;GAAE,OAAO;GAAS,GAAI,WAAW,SAAS,CAAC;EAAG;EACrD,QAAQ,OAAO,UAAU,OAAO,WAAW,OAAO,OAAO,SAAS;EAClE,QAAQ,WAAW,SAAS,UAAU,OAAO,EAAE,cAAc,CAAC,IAAI;CACnE;AACD;;AAGA,MAAa,kBACZ,WACuE;CACvE,IAAI,WAAW,OACd,OAAO;EAAE,SAAS;EAAO,MAAM;CAAkB;CAGlD,MAAM,aAAa,uBADJ,UAAU,WAAW,OAAO,SAAS,CAAC,CACL;CAChD,OAAO;EAAE,SAAS;EAAM,MAAM,WAAW;EAAgB;CAAW;AACrE"}
@@ -1,3 +1,5 @@
1
+ import { ByteSizeField } from "../client/ByteSizeField.js";
2
+ import { FieldNameSelect } from "../client/FieldNameSelect.js";
1
3
  import { FlowBuilder } from "../client/FlowBuilder.js";
2
4
  import { FormConditionField } from "../client/FormConditionField.js";
3
- export { FlowBuilder, FormConditionField };
5
+ export { ByteSizeField, FieldNameSelect, FlowBuilder, FormConditionField };
@@ -1,4 +1,6 @@
1
1
  "use client";
2
+ import { ByteSizeField } from "../client/ByteSizeField.js";
3
+ import { FieldNameSelect } from "../client/FieldNameSelect.js";
2
4
  import { FlowBuilder } from "../client/FlowBuilder.js";
3
5
  import { FormConditionField } from "../client/FormConditionField.js";
4
- export { FlowBuilder, FormConditionField };
6
+ export { ByteSizeField, FieldNameSelect, FlowBuilder, FormConditionField };
@@ -6,13 +6,17 @@ import { evaluateCalc } from "../calc/evaluate.js";
6
6
  import { evaluateCondition } from "../conditions/evaluate.js";
7
7
  import { firstStepId, isTerminalStepId, resolveNextStepId, stepFieldNames } from "../flow/engine.js";
8
8
  import { PrefillOptions, valuesFromSearchParams } from "../prefill/valuesFromSearchParams.js";
9
+ import { CaptchaWidgetHandle } from "../react/captcha/types.js";
10
+ import { HCAPTCHA_SCRIPT_URL, HcaptchaCaptcha, HcaptchaCaptchaProps } from "../react/captcha/HcaptchaCaptcha.js";
11
+ import { RECAPTCHA_SCRIPT_URL, RecaptchaCaptcha, RecaptchaCaptchaHandle, RecaptchaCaptchaProps } from "../react/captcha/RecaptchaCaptcha.js";
12
+ import { TURNSTILE_SCRIPT_URL, TurnstileCaptcha, TurnstileCaptchaProps } from "../react/captcha/TurnstileCaptcha.js";
9
13
  import { cn } from "../react/cn.js";
10
14
  import { FieldRenderer, FieldRendererProps, RendererTranslate, defineFieldRenderer } from "../react/contract.js";
11
15
  import { FormPresentation, PresentationWrapperProps } from "../react/presentation/types.js";
12
16
  import { PresentationOption, PresentationRegistry, PresentationsConfig, resolvePresentations } from "../react/presentation/registry.js";
13
17
  import { RendererOption, RendererRegistry, RenderersConfig, resolveRenderers } from "../react/registry.js";
14
18
  import { SubmitFormResult, SubmitHandler, submitForm } from "../react/submitForm.js";
15
- import { Form, FormDocument, FormProps } from "../react/Form.js";
19
+ import { BackButtonRenderProps, Form, FormDocument, FormProps, NextButtonRenderProps, SubmitButtonRenderProps } from "../react/Form.js";
16
20
  import { FormState } from "../react/state.js";
17
21
  import { FormStepInfo } from "../react/FormContext.js";
18
22
  import { FieldWidth, FormLayout, FormLayoutProps, widthProps } from "../react/FormLayout.js";
@@ -42,4 +46,5 @@ import { RecallResolver, buildRecallResolver } from "../recall/resolver.js";
42
46
  import { CAPTCHA_TOKEN_KEY, DEFAULT_HONEYPOT_FIELD } from "../spam/constants.js";
43
47
  import { en } from "../translations/en.js";
44
48
  import { makeTranslate } from "../translations/makeTranslate.js";
45
- export { type AggregationBucket, Backdrop, type BackdropProps, CAPTCHA_TOKEN_KEY, type CalcExpression, Checkbox, type CheckboxProps, DEFAULT_HONEYPOT_FIELD, DialogSurface, type DialogSurfaceProps, type FetchResultsInput, type FetchResultsResult, type FieldAggregation, type FieldRenderer, type FieldRendererProps, FieldShell, type FieldShellProps, type FieldWidth, Form, type FormDocument, type FormFieldInstance, FormLayout, type FormLayoutProps, type FormPresentation, type FormProps, FormResults, type FormResultsProps, type FormState, type FormStepInfo, Honeypot, type HoneypotProps, Input, type InputProps, Poll, type PollProps, type PrefillOptions, type PresentationOption, type PresentationRegistry, type PresentationWrapperProps, type PresentationsConfig, type RecallResolver, type RendererOption, type RendererRegistry, type RendererTranslate, type RenderersConfig, Select, type SelectOption, type SelectProps, type SubmitFormResult, type SubmitHandler, Textarea, type TextareaProps, type UploadFileInput, type UploadFileResult, type UseDismissOptions, type UseFieldResult, buildRecallResolver, cn, computeCalcFields, defaultPresentations, defaultRenderers, defineFieldRenderer, en, evaluateCalc, evaluateCondition, fetchFormResults, firstStepId, interpolate, isTerminalStepId, makeTranslate, resolveNextStepId, resolvePresentations, resolveRenderers, stepFieldNames, submitForm, toFormDocument, uploadFile, useDismiss, useField, useFocusTrap, useFormState, useFormStep, useScrollLock, valuesFromSearchParams, widthProps };
49
+ import { formatBytes } from "../uploads/formatBytes.js";
50
+ export { type AggregationBucket, type BackButtonRenderProps, Backdrop, type BackdropProps, CAPTCHA_TOKEN_KEY, type CalcExpression, type CaptchaWidgetHandle, Checkbox, type CheckboxProps, DEFAULT_HONEYPOT_FIELD, DialogSurface, type DialogSurfaceProps, type FetchResultsInput, type FetchResultsResult, type FieldAggregation, type FieldRenderer, type FieldRendererProps, FieldShell, type FieldShellProps, type FieldWidth, Form, type FormDocument, type FormFieldInstance, FormLayout, type FormLayoutProps, type FormPresentation, type FormProps, FormResults, type FormResultsProps, type FormState, type FormStepInfo, HCAPTCHA_SCRIPT_URL, HcaptchaCaptcha, type HcaptchaCaptchaProps, Honeypot, type HoneypotProps, Input, type InputProps, type NextButtonRenderProps, Poll, type PollProps, type PrefillOptions, type PresentationOption, type PresentationRegistry, type PresentationWrapperProps, type PresentationsConfig, RECAPTCHA_SCRIPT_URL, type RecallResolver, RecaptchaCaptcha, type RecaptchaCaptchaHandle, type RecaptchaCaptchaProps, type RendererOption, type RendererRegistry, type RendererTranslate, type RenderersConfig, Select, type SelectOption, type SelectProps, type SubmitButtonRenderProps, type SubmitFormResult, type SubmitHandler, TURNSTILE_SCRIPT_URL, Textarea, type TextareaProps, TurnstileCaptcha, type TurnstileCaptchaProps, type UploadFileInput, type UploadFileResult, type UseDismissOptions, type UseFieldResult, buildRecallResolver, cn, computeCalcFields, defaultPresentations, defaultRenderers, defineFieldRenderer, en, evaluateCalc, evaluateCondition, fetchFormResults, firstStepId, formatBytes, interpolate, isTerminalStepId, makeTranslate, resolveNextStepId, resolvePresentations, resolveRenderers, stepFieldNames, submitForm, toFormDocument, uploadFile, useDismiss, useField, useFocusTrap, useFormState, useFormStep, useScrollLock, valuesFromSearchParams, widthProps };
@@ -7,7 +7,11 @@ import { evaluateCondition } from "../conditions/evaluate.js";
7
7
  import { en } from "../translations/en.js";
8
8
  import { valuesFromSearchParams } from "../prefill/valuesFromSearchParams.js";
9
9
  import { buildRecallResolver } from "../recall/resolver.js";
10
+ import { formatBytes } from "../uploads/formatBytes.js";
10
11
  import { firstStepId, isTerminalStepId, resolveNextStepId, stepFieldNames } from "../flow/engine.js";
12
+ import { HCAPTCHA_SCRIPT_URL, HcaptchaCaptcha } from "../react/captcha/HcaptchaCaptcha.js";
13
+ import { RECAPTCHA_SCRIPT_URL, RecaptchaCaptcha } from "../react/captcha/RecaptchaCaptcha.js";
14
+ import { TURNSTILE_SCRIPT_URL, TurnstileCaptcha } from "../react/captcha/TurnstileCaptcha.js";
11
15
  import { cn } from "../react/cn.js";
12
16
  import { defineFieldRenderer } from "../react/contract.js";
13
17
  import { makeTranslate } from "../translations/makeTranslate.js";
@@ -25,11 +29,11 @@ import { FieldShell } from "../react/primitives/FieldShell.js";
25
29
  import { Checkbox } from "../react/primitives/Checkbox.js";
26
30
  import { Input } from "../react/primitives/Input.js";
27
31
  import { uploadFile } from "../react/uploadFile.js";
32
+ import { useField } from "../react/useField.js";
28
33
  import { Select } from "../react/primitives/Select.js";
29
34
  import { Textarea } from "../react/primitives/Textarea.js";
30
35
  import { defaultRenderers } from "../react/renderers/index.js";
31
36
  import { submitForm } from "../react/submitForm.js";
32
- import { useField } from "../react/useField.js";
33
37
  import { Form } from "../react/Form.js";
34
38
  import { FormResults } from "../react/FormResults.js";
35
39
  import { fetchFormResults } from "../react/fetchResults.js";
@@ -37,4 +41,4 @@ import { Poll } from "../react/Poll.js";
37
41
  import { toFormDocument } from "../react/toFormDocument.js";
38
42
  import { useFormState } from "../react/useFormState.js";
39
43
  import { useFormStep } from "../react/useFormStep.js";
40
- export { Backdrop, CAPTCHA_TOKEN_KEY, Checkbox, DEFAULT_HONEYPOT_FIELD, DialogSurface, FieldShell, Form, FormLayout, FormResults, Honeypot, Input, Poll, Select, Textarea, buildRecallResolver, cn, computeCalcFields, defaultPresentations, defaultRenderers, defineFieldRenderer, en, evaluateCalc, evaluateCondition, fetchFormResults, firstStepId, interpolate, isTerminalStepId, makeTranslate, resolveNextStepId, resolvePresentations, resolveRenderers, stepFieldNames, submitForm, toFormDocument, uploadFile, useDismiss, useField, useFocusTrap, useFormState, useFormStep, useScrollLock, valuesFromSearchParams, widthProps };
44
+ export { Backdrop, CAPTCHA_TOKEN_KEY, Checkbox, DEFAULT_HONEYPOT_FIELD, DialogSurface, FieldShell, Form, FormLayout, FormResults, HCAPTCHA_SCRIPT_URL, HcaptchaCaptcha, Honeypot, Input, Poll, RECAPTCHA_SCRIPT_URL, RecaptchaCaptcha, Select, TURNSTILE_SCRIPT_URL, Textarea, TurnstileCaptcha, buildRecallResolver, cn, computeCalcFields, defaultPresentations, defaultRenderers, defineFieldRenderer, en, evaluateCalc, evaluateCondition, fetchFormResults, firstStepId, formatBytes, interpolate, isTerminalStepId, makeTranslate, resolveNextStepId, resolvePresentations, resolveRenderers, stepFieldNames, submitForm, toFormDocument, uploadFile, useDismiss, useField, useFocusTrap, useFormState, useFormStep, useScrollLock, valuesFromSearchParams, widthProps };
@@ -15,6 +15,7 @@ import { ActionOption, ActionRegistry, ActionsConfig } from "../actions/registry
15
15
  import { ActionResult } from "../actions/runActions.js";
16
16
  import { AggregateFieldResponsesArgs, AggregateFormResponsesArgs } from "../aggregation/aggregateResponses.js";
17
17
  import { ResolveResultsRequestArgs, ResolveResultsRequestResult } from "../aggregation/resolveResultsRequest.js";
18
+ import { CollectionOverrides, FieldsOverride } from "../plugin/collectionOverrides.js";
18
19
  import { UploadsCollectionConfig, UploadsOption } from "../collections/uploads.js";
19
20
  import { FieldCondition } from "../conditions/types.js";
20
21
  import { AnyConsentSource, ConsentLink, ConsentResolveArgs, ConsentResolved, ConsentSource } from "../consent/defineConsentSource.js";
@@ -24,4 +25,4 @@ import { PresentationDescriptorOption, PresentationDescriptorRegistry, Presentat
24
25
  import { CaptchaProvider, CaptchaVerifyArgs, IdentifyFn, RateLimitCheckArgs, RateLimitConfig, RateLimitResult, RateLimiter, SpamConfig, SpamMetadataConfig, SpamOption } from "../spam/types.js";
25
26
  import { ValidationRuleOption, ValidationRuleRegistry, ValidationRulesConfig } from "../validation/registry.js";
26
27
  import { FormBuilderPluginOptions } from "../index.js";
27
- export type { ActionDefinition, ActionOption, ActionRegistry, ActionResult, ActionRunArgs, ActionsConfig, AggregateFieldResponsesArgs, AggregateFormResponsesArgs, AggregationBucket, AggregationRow, AnyActionDefinition, AnyConsentSource, AnyFormFieldDefinition, AnyValidationRuleDefinition, CalcExpression, CaptchaProvider, CaptchaVerifyArgs, ConsentLink, ConsentProof, ConsentResolveArgs, ConsentResolved, ConsentSource, ConsentSourceOption, ConsentSourceRegistry, ConsentSourcesConfig, FieldAggregation, FieldCondition, FieldMeta, FieldTypeOption, FieldTypeRegistry, FieldTypesConfig, FileFieldConfig, FileRef, FileRefError, FlowStep, FlowTransition, FormBuilderPluginOptions, FormEvent, FormEventSink, FormFieldDefinition, FormFieldFormat, FormFieldInstance, FormFieldValidate, FormFieldValueKind, FormFlow, IdentifyFn, PrefillOptions, PresentationDensity, PresentationDescriptor, PresentationDescriptorOption, PresentationDescriptorRegistry, PresentationSurface, PresentationsDescriptorConfig, RateLimitCheckArgs, RateLimitConfig, RateLimitResult, RateLimiter, RecallResolver, ResolveResultsRequestArgs, ResolveResultsRequestResult, SpamConfig, SpamMetadataConfig, SpamOption, SubmissionDescriptor, SubmissionFieldError, SubmissionStatusFilter, SubmissionValue, UploadsCollectionConfig, UploadsOption, ValidationRuleDefinition, ValidationRuleOption, ValidationRuleRegistry, ValidationRuleResult, ValidationRulesConfig, ValidationSeverity };
28
+ export type { ActionDefinition, ActionOption, ActionRegistry, ActionResult, ActionRunArgs, ActionsConfig, AggregateFieldResponsesArgs, AggregateFormResponsesArgs, AggregationBucket, AggregationRow, AnyActionDefinition, AnyConsentSource, AnyFormFieldDefinition, AnyValidationRuleDefinition, CalcExpression, CaptchaProvider, CaptchaVerifyArgs, CollectionOverrides, ConsentLink, ConsentProof, ConsentResolveArgs, ConsentResolved, ConsentSource, ConsentSourceOption, ConsentSourceRegistry, ConsentSourcesConfig, FieldAggregation, FieldCondition, FieldMeta, FieldTypeOption, FieldTypeRegistry, FieldTypesConfig, FieldsOverride, FileFieldConfig, FileRef, FileRefError, FlowStep, FlowTransition, FormBuilderPluginOptions, FormEvent, FormEventSink, FormFieldDefinition, FormFieldFormat, FormFieldInstance, FormFieldValidate, FormFieldValueKind, FormFlow, IdentifyFn, PrefillOptions, PresentationDensity, PresentationDescriptor, PresentationDescriptorOption, PresentationDescriptorRegistry, PresentationSurface, PresentationsDescriptorConfig, RateLimitCheckArgs, RateLimitConfig, RateLimitResult, RateLimiter, RecallResolver, ResolveResultsRequestArgs, ResolveResultsRequestResult, SpamConfig, SpamMetadataConfig, SpamOption, SubmissionDescriptor, SubmissionFieldError, SubmissionStatusFilter, SubmissionValue, UploadsCollectionConfig, UploadsOption, ValidationRuleDefinition, ValidationRuleOption, ValidationRuleRegistry, ValidationRuleResult, ValidationRulesConfig, ValidationSeverity };
@@ -3,9 +3,13 @@ import { labelFor } from "../translations/server.js";
3
3
  import { buildConditionTypeMap } from "../conditions/conditionType.js";
4
4
  import { buildConsentSourceConfig } from "../consent/buildConsentSourceConfig.js";
5
5
  import { buildRuleBlocks } from "../validation/buildRuleBlocks.js";
6
- import { sharedFieldConfig } from "./sharedConfig.js";
6
+ import { fieldBlockTabs } from "./sharedConfig.js";
7
7
  //#region src/fields/buildFieldBlocks.ts
8
- /** One add-field block per registered type: shared config, the type's own config, then its validations. */
8
+ /** The tab whose fields hold the shared basics and type config, found by the `name` field it carries. */
9
+ const fieldTabOf = (block) => {
10
+ return block.fields.find((f) => f.type === "tabs")?.tabs.find((tab) => tab.fields.some((f) => "name" in f && f.name === "name"))?.fields;
11
+ };
12
+ /** One add-field block per registered type: tabs holding shared config, type config, and validations. */
9
13
  const buildFieldBlocks = (registry, ruleRegistry, consentRegistry) => {
10
14
  const conditionTypes = buildConditionTypeMap(registry);
11
15
  const blocks = [];
@@ -26,18 +30,24 @@ const buildFieldBlocks = (registry, ruleRegistry, consentRegistry) => {
26
30
  singular: labelFor(definition.label),
27
31
  plural: labelFor(definition.label)
28
32
  },
29
- fields: [
30
- ...sharedFieldConfig(conditionTypes),
31
- ...typeConfig,
32
- {
33
- name: "validations",
34
- type: "blocks",
35
- label: labelFor(keys.validationsLabel),
36
- blocks: buildRuleBlocks(ruleRegistry, definition.type)
37
- }
38
- ]
33
+ fields: [fieldBlockTabs(conditionTypes, typeConfig, {
34
+ name: "validations",
35
+ type: "blocks",
36
+ label: labelFor(keys.validationsLabel),
37
+ blocks: buildRuleBlocks(ruleRegistry, definition.type)
38
+ })]
39
39
  });
40
40
  }
41
+ const repeaterBlock = blocks.find((b) => b.slug === "repeater");
42
+ if (repeaterBlock) {
43
+ const subFieldsField = {
44
+ name: "subFields",
45
+ type: "blocks",
46
+ label: labelFor(keys.configSubFields),
47
+ blocks: blocks.filter((b) => b.slug !== "repeater")
48
+ };
49
+ (fieldTabOf(repeaterBlock) ?? repeaterBlock.fields).push(subFieldsField);
50
+ }
41
51
  return blocks;
42
52
  };
43
53
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"buildFieldBlocks.js","names":[],"sources":["../../src/fields/buildFieldBlocks.ts"],"sourcesContent":["import type { Block, Field } from 'payload'\nimport { buildConditionTypeMap } from '../conditions/conditionType'\nimport { buildConsentSourceConfig } from '../consent/buildConsentSourceConfig'\nimport type { ConsentSourceRegistry } from '../consent/registry'\nimport { keys } from '../translations/keys'\nimport { labelFor } from '../translations/server'\nimport { buildRuleBlocks } from '../validation/buildRuleBlocks'\nimport type { ValidationRuleRegistry } from '../validation/registry'\nimport type { FieldTypeRegistry } from './registry'\nimport { sharedFieldConfig } from './sharedConfig'\n\n/** One add-field block per registered type: shared config, the type's own config, then its validations. */\nexport const buildFieldBlocks = (\n\tregistry: FieldTypeRegistry,\n\truleRegistry: ValidationRuleRegistry,\n\tconsentRegistry?: ConsentSourceRegistry\n): Block[] => {\n\tconst conditionTypes = buildConditionTypeMap(registry)\n\tconst blocks: Block[] = []\n\tfor (const definition of registry.values()) {\n\t\tlet typeConfig: Field[] = definition.config ?? []\n\n\t\t// Inject dynamic source select + conditional sourceConfig group for the consent field.\n\t\t// consent.ts intentionally omits source/sourceConfig; the live registry drives the\n\t\t// select options and per-source field visibility (admin.condition).\n\t\tif (definition.type === 'consent' && consentRegistry) {\n\t\t\t// statement is first; optional is last; source/sourceConfig go in between.\n\t\t\tconst statement = typeConfig.find((f) => (f as { name?: string }).name === 'statement')\n\t\t\tconst optional = typeConfig.find((f) => (f as { name?: string }).name === 'optional')\n\t\t\ttypeConfig = [\n\t\t\t\t...(statement ? [statement] : []),\n\t\t\t\t...buildConsentSourceConfig(consentRegistry),\n\t\t\t\t...(optional ? [optional] : []),\n\t\t\t]\n\t\t}\n\n\t\tblocks.push({\n\t\t\tslug: definition.type,\n\t\t\tlabels: { singular: labelFor(definition.label), plural: labelFor(definition.label) },\n\t\t\tfields: [\n\t\t\t\t...sharedFieldConfig(conditionTypes),\n\t\t\t\t...typeConfig,\n\t\t\t\t{\n\t\t\t\t\tname: 'validations',\n\t\t\t\t\ttype: 'blocks',\n\t\t\t\t\tlabel: labelFor(keys.validationsLabel),\n\t\t\t\t\tblocks: buildRuleBlocks(ruleRegistry, definition.type),\n\t\t\t\t},\n\t\t\t],\n\t\t})\n\t}\n\treturn blocks\n}\n"],"mappings":";;;;;;;;AAYA,MAAa,oBACZ,UACA,cACA,oBACa;CACb,MAAM,iBAAiB,sBAAsB,QAAQ;CACrD,MAAM,SAAkB,CAAC;CACzB,KAAK,MAAM,cAAc,SAAS,OAAO,GAAG;EAC3C,IAAI,aAAsB,WAAW,UAAU,CAAC;EAKhD,IAAI,WAAW,SAAS,aAAa,iBAAiB;GAErD,MAAM,YAAY,WAAW,MAAM,MAAO,EAAwB,SAAS,WAAW;GACtF,MAAM,WAAW,WAAW,MAAM,MAAO,EAAwB,SAAS,UAAU;GACpF,aAAa;IACZ,GAAI,YAAY,CAAC,SAAS,IAAI,CAAC;IAC/B,GAAG,yBAAyB,eAAe;IAC3C,GAAI,WAAW,CAAC,QAAQ,IAAI,CAAC;GAC9B;EACD;EAEA,OAAO,KAAK;GACX,MAAM,WAAW;GACjB,QAAQ;IAAE,UAAU,SAAS,WAAW,KAAK;IAAG,QAAQ,SAAS,WAAW,KAAK;GAAE;GACnF,QAAQ;IACP,GAAG,kBAAkB,cAAc;IACnC,GAAG;IACH;KACC,MAAM;KACN,MAAM;KACN,OAAO,SAAS,KAAK,gBAAgB;KACrC,QAAQ,gBAAgB,cAAc,WAAW,IAAI;IACtD;GACD;EACD,CAAC;CACF;CACA,OAAO;AACR"}
1
+ {"version":3,"file":"buildFieldBlocks.js","names":[],"sources":["../../src/fields/buildFieldBlocks.ts"],"sourcesContent":["import type { Block, Field, TabsField } from 'payload'\nimport { buildConditionTypeMap } from '../conditions/conditionType'\nimport { buildConsentSourceConfig } from '../consent/buildConsentSourceConfig'\nimport type { ConsentSourceRegistry } from '../consent/registry'\nimport { keys } from '../translations/keys'\nimport { labelFor } from '../translations/server'\nimport { buildRuleBlocks } from '../validation/buildRuleBlocks'\nimport type { ValidationRuleRegistry } from '../validation/registry'\nimport type { FieldTypeRegistry } from './registry'\nimport { fieldBlockTabs } from './sharedConfig'\n\n/** The tab whose fields hold the shared basics and type config, found by the `name` field it carries. */\nconst fieldTabOf = (block: Block): Field[] | undefined => {\n\tconst tabsField = block.fields.find((f): f is TabsField => f.type === 'tabs')\n\treturn tabsField?.tabs.find((tab) => tab.fields.some((f) => 'name' in f && f.name === 'name'))\n\t\t?.fields\n}\n\n/** One add-field block per registered type: tabs holding shared config, type config, and validations. */\nexport const buildFieldBlocks = (\n\tregistry: FieldTypeRegistry,\n\truleRegistry: ValidationRuleRegistry,\n\tconsentRegistry?: ConsentSourceRegistry\n): Block[] => {\n\tconst conditionTypes = buildConditionTypeMap(registry)\n\tconst blocks: Block[] = []\n\tfor (const definition of registry.values()) {\n\t\tlet typeConfig: Field[] = definition.config ?? []\n\n\t\t// Inject dynamic source select + conditional sourceConfig group for the consent field.\n\t\t// consent.ts intentionally omits source/sourceConfig; the live registry drives the\n\t\t// select options and per-source field visibility (admin.condition).\n\t\tif (definition.type === 'consent' && consentRegistry) {\n\t\t\t// statement is first; optional is last; source/sourceConfig go in between.\n\t\t\tconst statement = typeConfig.find((f) => (f as { name?: string }).name === 'statement')\n\t\t\tconst optional = typeConfig.find((f) => (f as { name?: string }).name === 'optional')\n\t\t\ttypeConfig = [\n\t\t\t\t...(statement ? [statement] : []),\n\t\t\t\t...buildConsentSourceConfig(consentRegistry),\n\t\t\t\t...(optional ? [optional] : []),\n\t\t\t]\n\t\t}\n\n\t\tblocks.push({\n\t\t\tslug: definition.type,\n\t\t\tlabels: { singular: labelFor(definition.label), plural: labelFor(definition.label) },\n\t\t\tfields: [\n\t\t\t\tfieldBlockTabs(conditionTypes, typeConfig, {\n\t\t\t\t\tname: 'validations',\n\t\t\t\t\ttype: 'blocks',\n\t\t\t\t\tlabel: labelFor(keys.validationsLabel),\n\t\t\t\t\tblocks: buildRuleBlocks(ruleRegistry, definition.type),\n\t\t\t\t}),\n\t\t\t],\n\t\t})\n\t}\n\n\t// Second pass: inject subFields into the repeater block using all non-repeater blocks.\n\t// Done after the main loop so every sibling block is already built.\n\t// Repeater-in-repeater is not supported in v1; the repeater block is excluded from subFields.\n\tconst repeaterBlock = blocks.find((b) => b.slug === 'repeater')\n\tif (repeaterBlock) {\n\t\tconst subFieldsField: Field = {\n\t\t\tname: 'subFields',\n\t\t\ttype: 'blocks',\n\t\t\tlabel: labelFor(keys.configSubFields),\n\t\t\tblocks: blocks.filter((b) => b.slug !== 'repeater'),\n\t\t}\n\t\tconst fieldTabFields = fieldTabOf(repeaterBlock)\n\t\t;(fieldTabFields ?? (repeaterBlock.fields as Field[])).push(subFieldsField)\n\t}\n\n\treturn blocks\n}\n"],"mappings":";;;;;;;;AAYA,MAAM,cAAc,UAAsC;CAEzD,OADkB,MAAM,OAAO,MAAM,MAAsB,EAAE,SAAS,MACvD,GAAG,KAAK,MAAM,QAAQ,IAAI,OAAO,MAAM,MAAM,UAAU,KAAK,EAAE,SAAS,MAAM,CAAC,GAC1F;AACJ;;AAGA,MAAa,oBACZ,UACA,cACA,oBACa;CACb,MAAM,iBAAiB,sBAAsB,QAAQ;CACrD,MAAM,SAAkB,CAAC;CACzB,KAAK,MAAM,cAAc,SAAS,OAAO,GAAG;EAC3C,IAAI,aAAsB,WAAW,UAAU,CAAC;EAKhD,IAAI,WAAW,SAAS,aAAa,iBAAiB;GAErD,MAAM,YAAY,WAAW,MAAM,MAAO,EAAwB,SAAS,WAAW;GACtF,MAAM,WAAW,WAAW,MAAM,MAAO,EAAwB,SAAS,UAAU;GACpF,aAAa;IACZ,GAAI,YAAY,CAAC,SAAS,IAAI,CAAC;IAC/B,GAAG,yBAAyB,eAAe;IAC3C,GAAI,WAAW,CAAC,QAAQ,IAAI,CAAC;GAC9B;EACD;EAEA,OAAO,KAAK;GACX,MAAM,WAAW;GACjB,QAAQ;IAAE,UAAU,SAAS,WAAW,KAAK;IAAG,QAAQ,SAAS,WAAW,KAAK;GAAE;GACnF,QAAQ,CACP,eAAe,gBAAgB,YAAY;IAC1C,MAAM;IACN,MAAM;IACN,OAAO,SAAS,KAAK,gBAAgB;IACrC,QAAQ,gBAAgB,cAAc,WAAW,IAAI;GACtD,CAAC,CACF;EACD,CAAC;CACF;CAKA,MAAM,gBAAgB,OAAO,MAAM,MAAM,EAAE,SAAS,UAAU;CAC9D,IAAI,eAAe;EAClB,MAAM,iBAAwB;GAC7B,MAAM;GACN,MAAM;GACN,OAAO,SAAS,KAAK,eAAe;GACpC,QAAQ,OAAO,QAAQ,MAAM,EAAE,SAAS,UAAU;EACnD;EAEC,CADsB,WAAW,aACnB,KAAM,cAAc,QAAoB,KAAK,cAAc;CAC3E;CAEA,OAAO;AACR"}