@nextlyhq/plugin-form-builder 0.0.2-alpha.6 → 0.0.2-alpha.62
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -5
- package/dist/admin/index.d.ts +139 -331
- package/dist/admin/index.js +4410 -3532
- package/dist/admin/index.js.map +1 -1
- package/dist/chunk-H5X3FKOZ.js +689 -0
- package/dist/chunk-H5X3FKOZ.js.map +1 -0
- package/dist/index.d.ts +13 -27
- package/dist/index.js +1187 -814
- package/dist/index.js.map +1 -1
- package/dist/{index-C0kBvYjm.d.ts → types-hLfLe81K.d.ts} +269 -203
- package/package.json +33 -31
- package/dist/CheckboxFieldEditor-K4T6QX52.js +0 -121
- package/dist/CheckboxFieldEditor-K4T6QX52.js.map +0 -1
- package/dist/DateFieldEditor-JFJFAVOH.js +0 -187
- package/dist/DateFieldEditor-JFJFAVOH.js.map +0 -1
- package/dist/EmailFieldEditor-MMOXXL7P.js +0 -138
- package/dist/EmailFieldEditor-MMOXXL7P.js.map +0 -1
- package/dist/NumberFieldEditor-UISAYR6Z.js +0 -175
- package/dist/NumberFieldEditor-UISAYR6Z.js.map +0 -1
- package/dist/RadioFieldEditor-6UQFH4WT.js +0 -165
- package/dist/RadioFieldEditor-6UQFH4WT.js.map +0 -1
- package/dist/SelectFieldEditor-PSO4KHV4.js +0 -213
- package/dist/SelectFieldEditor-PSO4KHV4.js.map +0 -1
- package/dist/TextFieldEditor-5EU64EA5.js +0 -187
- package/dist/TextFieldEditor-5EU64EA5.js.map +0 -1
- package/dist/TextareaFieldEditor-773G3LNM.js +0 -190
- package/dist/TextareaFieldEditor-773G3LNM.js.map +0 -1
- package/dist/admin/index.css +0 -934
- package/dist/admin/index.css.map +0 -1
- package/dist/chunk-ABNZFTQK.js +0 -586
- package/dist/chunk-ABNZFTQK.js.map +0 -1
- package/dist/chunk-XTCEPJ7B.js +0 -256
- package/dist/chunk-XTCEPJ7B.js.map +0 -1
- package/dist/components/index.d.ts +0 -3
- package/dist/components/index.js +0 -9
- package/dist/components/index.js.map +0 -1
- package/dist/styles/form-builder.css +0 -1150
- package/dist/styles/submissions-filter.css +0 -75
|
@@ -1,5 +1,29 @@
|
|
|
1
|
-
import React, { ComponentType } from 'react';
|
|
2
1
|
import { RequestContext, CollectionConfig, FieldDefinition } from 'nextly';
|
|
2
|
+
import { ComponentType } from 'react';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Reading the document a form's redirect setting points at.
|
|
6
|
+
*
|
|
7
|
+
* Separate from `redirect-target` because this half has no dependencies and
|
|
8
|
+
* the other half imports `nextly/config`: the admin picker needs to read a
|
|
9
|
+
* stored reference to show what is selected, and pulling the config surface
|
|
10
|
+
* into the browser bundle to do it would be a real cost for no gain.
|
|
11
|
+
*/
|
|
12
|
+
/** A document being turned into a URL. `id` is always present; the rest is the row. */
|
|
13
|
+
interface RedirectTargetDocument {
|
|
14
|
+
id: string;
|
|
15
|
+
[field: string]: unknown;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* How documents in one collection become URLs.
|
|
20
|
+
*
|
|
21
|
+
* A string is a path with `{field}` placeholders filled from the document.
|
|
22
|
+
* A function receives the document and returns the path itself.
|
|
23
|
+
*/
|
|
24
|
+
type RedirectUrlPattern = string | ((document: RedirectTargetDocument) => string | undefined);
|
|
25
|
+
/** The collection-to-pattern map, after the array shorthand is normalised. */
|
|
26
|
+
type RedirectRelationships = Record<string, RedirectUrlPattern>;
|
|
3
27
|
|
|
4
28
|
/**
|
|
5
29
|
* Form Builder Plugin Types
|
|
@@ -34,19 +58,53 @@ interface EmailConfig {
|
|
|
34
58
|
bcc?: string | string[];
|
|
35
59
|
}
|
|
36
60
|
/**
|
|
37
|
-
* A
|
|
38
|
-
*
|
|
61
|
+
* @experimental A resolved outgoing form notification (template-based) as built
|
|
62
|
+
* by the submission handler, before it is sent. This is the value transformed by
|
|
63
|
+
* the `form-builder.beforeEmail` D63 filter seam.
|
|
39
64
|
*/
|
|
40
|
-
interface
|
|
65
|
+
interface FormEmailNotification {
|
|
66
|
+
/** Resolved recipient address. */
|
|
67
|
+
to: string;
|
|
68
|
+
/** Email template slug to render. */
|
|
69
|
+
templateSlug: string;
|
|
70
|
+
/** Template variables (submitted data + form metadata). */
|
|
71
|
+
variables: Record<string, unknown>;
|
|
72
|
+
/** Email provider id; undefined = system default. */
|
|
73
|
+
providerId?: string;
|
|
74
|
+
/**
|
|
75
|
+
* Resolved sender address (rule's senderEmail, else the plugin's
|
|
76
|
+
* defaultFrom); undefined = template/provider default.
|
|
77
|
+
*/
|
|
78
|
+
from?: string;
|
|
79
|
+
/** Resolved Reply-To address, if the rule configured one. */
|
|
80
|
+
replyTo?: string;
|
|
81
|
+
/** CC addresses, if any. */
|
|
82
|
+
cc?: string[];
|
|
83
|
+
/** BCC addresses, if any. */
|
|
84
|
+
bcc?: string[];
|
|
85
|
+
/** Source notification id; undefined for filter-injected emails. */
|
|
86
|
+
notificationId?: string;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* A single email notification rule stored on a form.
|
|
90
|
+
* Matches the shape saved by the form builder admin UI. This is the ONE
|
|
91
|
+
* notification rule type — the admin context re-exports it rather than
|
|
92
|
+
* keeping a parallel copy.
|
|
93
|
+
*/
|
|
94
|
+
interface FormNotification {
|
|
41
95
|
/** Unique ID for this notification */
|
|
42
96
|
id: string;
|
|
43
|
-
/** Display name for this
|
|
97
|
+
/** Display name for this notification rule */
|
|
44
98
|
name: string;
|
|
45
99
|
/** Whether this notification is active */
|
|
46
100
|
enabled: boolean;
|
|
47
101
|
/** ID of the email provider to use; undefined = system default */
|
|
48
102
|
providerId?: string;
|
|
49
|
-
/**
|
|
103
|
+
/**
|
|
104
|
+
* Sender email override. Resolution order at send time:
|
|
105
|
+
* this value, else the plugin's `notifications.defaultFrom` option, else
|
|
106
|
+
* the template/provider default.
|
|
107
|
+
*/
|
|
50
108
|
senderEmail?: string;
|
|
51
109
|
/** How the recipient address is determined */
|
|
52
110
|
recipientType: "static" | "field";
|
|
@@ -56,9 +114,26 @@ interface FormNotificationItem {
|
|
|
56
114
|
cc: string[];
|
|
57
115
|
/** BCC email addresses */
|
|
58
116
|
bcc: string[];
|
|
117
|
+
/**
|
|
118
|
+
* Reply-To address: a `{{fieldName}}` reference to one of the form's
|
|
119
|
+
* email fields (resolved against the submission) or a literal address.
|
|
120
|
+
*/
|
|
121
|
+
replyTo?: string;
|
|
122
|
+
/**
|
|
123
|
+
* Optional send condition evaluated against the submitted data. When set
|
|
124
|
+
* and unmet, the rule is skipped for that submission. A single condition
|
|
125
|
+
* covers the common case; the JSON storage leaves room to grow into a
|
|
126
|
+
* multi-condition tree without a migration.
|
|
127
|
+
*/
|
|
128
|
+
condition?: ConditionalLogicCondition;
|
|
59
129
|
/** Slug of the email template to use */
|
|
60
130
|
templateSlug?: string;
|
|
61
131
|
}
|
|
132
|
+
/**
|
|
133
|
+
* @deprecated Use {@link FormNotification}. Alias kept so existing imports
|
|
134
|
+
* keep compiling during the alpha; will be removed before a stable release.
|
|
135
|
+
*/
|
|
136
|
+
type FormNotificationItem = FormNotification;
|
|
62
137
|
/**
|
|
63
138
|
* Form document structure (stored in database).
|
|
64
139
|
*/
|
|
@@ -66,11 +141,21 @@ interface FormDocument {
|
|
|
66
141
|
id: string;
|
|
67
142
|
slug: string;
|
|
68
143
|
name: string;
|
|
69
|
-
fields:
|
|
144
|
+
fields: AnyFormField[];
|
|
70
145
|
settings: FormSettings;
|
|
71
|
-
notifications:
|
|
146
|
+
notifications: FormNotification[];
|
|
72
147
|
webhooks?: WebhookConfig[];
|
|
73
148
|
status: "draft" | "published" | "closed";
|
|
149
|
+
/**
|
|
150
|
+
* What a closed form tells a visitor who reaches it.
|
|
151
|
+
*
|
|
152
|
+
* Optional because the field is only written once an author has a reason to
|
|
153
|
+
* give, and a row created before it existed has none. A closed form with
|
|
154
|
+
* nothing here falls back to the generic refusal, which is also what a draft
|
|
155
|
+
* gets — a draft has never been public, so there is no author intent to
|
|
156
|
+
* relay.
|
|
157
|
+
*/
|
|
158
|
+
closedMessage?: string;
|
|
74
159
|
createdAt: Date;
|
|
75
160
|
updatedAt: Date;
|
|
76
161
|
}
|
|
@@ -81,9 +166,19 @@ interface SubmissionDocument {
|
|
|
81
166
|
id: string;
|
|
82
167
|
form: string | FormDocument;
|
|
83
168
|
data: Record<string, unknown>;
|
|
84
|
-
|
|
169
|
+
/**
|
|
170
|
+
* Where the submission sits in review.
|
|
171
|
+
*
|
|
172
|
+
* `spam` is one of them, not a separate flag: the stored field offers it, the
|
|
173
|
+
* admin has a Spam tab and filters the other views with `not_equals: "spam"`,
|
|
174
|
+
* the notification hook skips it, and marking something "Not spam" moves it
|
|
175
|
+
* back to `new`. `spamReason` records WHICH check flagged it.
|
|
176
|
+
*/
|
|
177
|
+
status: "new" | "read" | "archived" | "spam";
|
|
85
178
|
ipAddress?: string;
|
|
86
179
|
userAgent?: string;
|
|
180
|
+
/** Which spam check flagged this, when one did. */
|
|
181
|
+
spamReason?: string | null;
|
|
87
182
|
submittedAt: Date;
|
|
88
183
|
createdAt: Date;
|
|
89
184
|
updatedAt: Date;
|
|
@@ -91,6 +186,49 @@ interface SubmissionDocument {
|
|
|
91
186
|
/**
|
|
92
187
|
* Configuration options for the form builder plugin.
|
|
93
188
|
*/
|
|
189
|
+
/**
|
|
190
|
+
* Which field types the builder offers, and how each one is customised.
|
|
191
|
+
*
|
|
192
|
+
* Declared ONCE and viewed twice: the options surface takes
|
|
193
|
+
* `Partial<FormFieldToggles>` and the resolved config takes it whole, because
|
|
194
|
+
* "resolved" means exactly "every toggle now has a value". Written out twice
|
|
195
|
+
* the two lists agree until someone adds a field type to one of them.
|
|
196
|
+
*/
|
|
197
|
+
interface FormFieldToggles {
|
|
198
|
+
text: boolean | Partial<FieldBlockConfig>;
|
|
199
|
+
email: boolean | Partial<FieldBlockConfig>;
|
|
200
|
+
number: boolean | Partial<FieldBlockConfig>;
|
|
201
|
+
phone: boolean | Partial<FieldBlockConfig>;
|
|
202
|
+
url: boolean | Partial<FieldBlockConfig>;
|
|
203
|
+
textarea: boolean | Partial<FieldBlockConfig>;
|
|
204
|
+
select: boolean | Partial<FieldBlockConfig>;
|
|
205
|
+
checkbox: boolean | Partial<FieldBlockConfig>;
|
|
206
|
+
radio: boolean | Partial<FieldBlockConfig>;
|
|
207
|
+
file: boolean | Partial<FieldBlockConfig>;
|
|
208
|
+
date: boolean | Partial<FieldBlockConfig>;
|
|
209
|
+
time: boolean | Partial<FieldBlockConfig>;
|
|
210
|
+
hidden: boolean | Partial<FieldBlockConfig>;
|
|
211
|
+
}
|
|
212
|
+
/** What a host may override on a collection this plugin contributes. */
|
|
213
|
+
type CollectionOverrides = Partial<CollectionConfig> & {
|
|
214
|
+
slug?: string;
|
|
215
|
+
labels?: {
|
|
216
|
+
singular?: string;
|
|
217
|
+
plural?: string;
|
|
218
|
+
};
|
|
219
|
+
/** Fields can be an array or a function receiving defaultFields */
|
|
220
|
+
fields?: FieldDefinition[] | ((args: {
|
|
221
|
+
defaultFields: FieldDefinition[];
|
|
222
|
+
}) => FieldDefinition[]);
|
|
223
|
+
};
|
|
224
|
+
/** The same, once the plugin's defaults have filled in what a host omitted. */
|
|
225
|
+
type ResolvedCollectionOverrides = {
|
|
226
|
+
slug: string;
|
|
227
|
+
labels: {
|
|
228
|
+
singular: string;
|
|
229
|
+
plural: string;
|
|
230
|
+
};
|
|
231
|
+
} & Partial<CollectionConfig>;
|
|
94
232
|
interface FormBuilderPluginOptions {
|
|
95
233
|
/**
|
|
96
234
|
* Override the default Forms collection configuration.
|
|
@@ -133,17 +271,7 @@ interface FormBuilderPluginOptions {
|
|
|
133
271
|
* }
|
|
134
272
|
* ```
|
|
135
273
|
*/
|
|
136
|
-
formOverrides?:
|
|
137
|
-
slug?: string;
|
|
138
|
-
labels?: {
|
|
139
|
-
singular?: string;
|
|
140
|
-
plural?: string;
|
|
141
|
-
};
|
|
142
|
-
/** Fields can be an array or a function receiving defaultFields */
|
|
143
|
-
fields?: FieldDefinition[] | ((args: {
|
|
144
|
-
defaultFields: FieldDefinition[];
|
|
145
|
-
}) => FieldDefinition[]);
|
|
146
|
-
};
|
|
274
|
+
formOverrides?: CollectionOverrides;
|
|
147
275
|
/**
|
|
148
276
|
* Override the default Form Submissions collection configuration.
|
|
149
277
|
*
|
|
@@ -189,37 +317,7 @@ interface FormBuilderPluginOptions {
|
|
|
189
317
|
* }
|
|
190
318
|
* ```
|
|
191
319
|
*/
|
|
192
|
-
formSubmissionOverrides?:
|
|
193
|
-
slug?: string;
|
|
194
|
-
labels?: {
|
|
195
|
-
singular?: string;
|
|
196
|
-
plural?: string;
|
|
197
|
-
};
|
|
198
|
-
/** Fields can be an array or a function receiving defaultFields */
|
|
199
|
-
fields?: FieldDefinition[] | ((args: {
|
|
200
|
-
defaultFields: FieldDefinition[];
|
|
201
|
-
}) => FieldDefinition[]);
|
|
202
|
-
};
|
|
203
|
-
/**
|
|
204
|
-
* @deprecated Use `formOverrides` and `formSubmissionOverrides` instead.
|
|
205
|
-
* This option is kept for backward compatibility.
|
|
206
|
-
*/
|
|
207
|
-
collections?: {
|
|
208
|
-
forms?: Partial<CollectionConfig> & {
|
|
209
|
-
slug?: string;
|
|
210
|
-
labels?: {
|
|
211
|
-
singular?: string;
|
|
212
|
-
plural?: string;
|
|
213
|
-
};
|
|
214
|
-
};
|
|
215
|
-
submissions?: Partial<CollectionConfig> & {
|
|
216
|
-
slug?: string;
|
|
217
|
-
labels?: {
|
|
218
|
-
singular?: string;
|
|
219
|
-
plural?: string;
|
|
220
|
-
};
|
|
221
|
-
};
|
|
222
|
-
};
|
|
320
|
+
formSubmissionOverrides?: CollectionOverrides;
|
|
223
321
|
/**
|
|
224
322
|
* Configure which field types are available in the form builder.
|
|
225
323
|
*
|
|
@@ -242,55 +340,51 @@ interface FormBuilderPluginOptions {
|
|
|
242
340
|
* }
|
|
243
341
|
* ```
|
|
244
342
|
*/
|
|
245
|
-
fields?:
|
|
246
|
-
text?: boolean | Partial<FieldBlockConfig>;
|
|
247
|
-
email?: boolean | Partial<FieldBlockConfig>;
|
|
248
|
-
number?: boolean | Partial<FieldBlockConfig>;
|
|
249
|
-
phone?: boolean | Partial<FieldBlockConfig>;
|
|
250
|
-
url?: boolean | Partial<FieldBlockConfig>;
|
|
251
|
-
textarea?: boolean | Partial<FieldBlockConfig>;
|
|
252
|
-
select?: boolean | Partial<FieldBlockConfig>;
|
|
253
|
-
checkbox?: boolean | Partial<FieldBlockConfig>;
|
|
254
|
-
radio?: boolean | Partial<FieldBlockConfig>;
|
|
255
|
-
file?: boolean | Partial<FieldBlockConfig>;
|
|
256
|
-
date?: boolean | Partial<FieldBlockConfig>;
|
|
257
|
-
time?: boolean | Partial<FieldBlockConfig>;
|
|
258
|
-
hidden?: boolean | Partial<FieldBlockConfig>;
|
|
259
|
-
};
|
|
343
|
+
fields?: Partial<FormFieldToggles>;
|
|
260
344
|
/**
|
|
261
|
-
* Collections
|
|
345
|
+
* Collections whose documents a form may redirect to after submission, and
|
|
346
|
+
* how each one's documents become URLs.
|
|
262
347
|
*
|
|
263
|
-
*
|
|
264
|
-
*
|
|
348
|
+
* The mapping is configuration because it cannot be derived: a site's URL
|
|
349
|
+
* structure belongs to the site. `{field}` placeholders are filled from the
|
|
350
|
+
* document; a function covers a path this package cannot express.
|
|
351
|
+
*
|
|
352
|
+
* The array shorthand names the collections and takes `/{slug}` for all of
|
|
353
|
+
* them, which is the routing the page builder ships.
|
|
265
354
|
*
|
|
266
355
|
* @example
|
|
267
356
|
* ```typescript
|
|
268
|
-
* redirectRelationships: ['pages'
|
|
357
|
+
* redirectRelationships: ['pages']
|
|
358
|
+
*
|
|
359
|
+
* redirectRelationships: {
|
|
360
|
+
* pages: '/{slug}',
|
|
361
|
+
* posts: '/blog/{slug}',
|
|
362
|
+
* docs: page => `/docs/${String(page.section)}/${String(page.slug)}`,
|
|
363
|
+
* }
|
|
269
364
|
* ```
|
|
270
365
|
*/
|
|
271
|
-
redirectRelationships?: string[];
|
|
366
|
+
redirectRelationships?: string[] | RedirectRelationships;
|
|
272
367
|
/**
|
|
273
368
|
* Hook called before sending email notifications.
|
|
274
369
|
*
|
|
275
|
-
*
|
|
276
|
-
*
|
|
370
|
+
* Runs as the `form-builder.beforeEmail` D63 filter: the resolved outgoing
|
|
371
|
+
* notifications (template + recipient + variables) are threaded through this
|
|
372
|
+
* callback before they are sent. Allows modifying, adding, or filtering the
|
|
373
|
+
* outgoing notifications. Return the modified array.
|
|
277
374
|
*
|
|
278
375
|
* @example
|
|
279
376
|
* ```typescript
|
|
280
377
|
* beforeEmail: async ({ emails, form, submission }) => {
|
|
281
|
-
* // Add BCC to all
|
|
282
|
-
* return emails.map(
|
|
283
|
-
* ...email,
|
|
284
|
-
* bcc: ['archive@example.com'],
|
|
285
|
-
* }));
|
|
378
|
+
* // Add BCC to all outgoing notifications
|
|
379
|
+
* return emails.map((e) => ({ ...e, bcc: ['archive@example.com'] }));
|
|
286
380
|
* }
|
|
287
381
|
* ```
|
|
288
382
|
*/
|
|
289
383
|
beforeEmail?: (args: {
|
|
290
|
-
emails:
|
|
384
|
+
emails: FormEmailNotification[];
|
|
291
385
|
form: FormDocument;
|
|
292
386
|
submission: SubmissionDocument;
|
|
293
|
-
}) => Promise<
|
|
387
|
+
}) => Promise<FormEmailNotification[]> | FormEmailNotification[];
|
|
294
388
|
/**
|
|
295
389
|
* Email notification settings.
|
|
296
390
|
*/
|
|
@@ -413,7 +507,7 @@ interface FormConfig {
|
|
|
413
507
|
/**
|
|
414
508
|
* Form fields definition.
|
|
415
509
|
*/
|
|
416
|
-
fields:
|
|
510
|
+
fields: AnyFormField[];
|
|
417
511
|
/**
|
|
418
512
|
* Form settings and behavior.
|
|
419
513
|
*/
|
|
@@ -441,9 +535,32 @@ interface FormConfig {
|
|
|
441
535
|
*/
|
|
442
536
|
type FormField = TextFormField | EmailFormField | NumberFormField | PhoneFormField | UrlFormField | TextareaFormField | SelectFormField | CheckboxFormField | RadioFormField | FileFormField | DateFormField | TimeFormField | HiddenFormField;
|
|
443
537
|
/**
|
|
444
|
-
*
|
|
538
|
+
* A form field of a built-in type OR a plugin-contributed type. Stored form
|
|
539
|
+
* data and the builder work with this; `isKnownFormField` narrows it back to
|
|
540
|
+
* the closed `FormField` union so `switch (field.type)` keeps discriminating
|
|
541
|
+
* the built-ins (a `CustomFormField` in the union itself would collapse that).
|
|
542
|
+
*/
|
|
543
|
+
type AnyFormField = FormField | CustomFormField;
|
|
544
|
+
/**
|
|
545
|
+
* All available built-in form field type identifiers.
|
|
445
546
|
*/
|
|
446
547
|
type FormFieldType = "text" | "email" | "number" | "phone" | "url" | "textarea" | "select" | "checkbox" | "radio" | "file" | "date" | "time" | "hidden";
|
|
548
|
+
/**
|
|
549
|
+
* A form field's type on the wire: a built-in or a plugin-contributed type id
|
|
550
|
+
* that opted into the forms surface. The `(string & {})` arm admits the plugin
|
|
551
|
+
* id while keeping built-in autocomplete. Built-in `case` narrowing still works
|
|
552
|
+
* because every field-type switch keeps a `default` for the custom arm.
|
|
553
|
+
*/
|
|
554
|
+
type FormFieldTypeId = FormFieldType | (string & {});
|
|
555
|
+
/** Every built-in form field type, as a value list (the single source shared
|
|
556
|
+
* by the field-type guard and the config validator). */
|
|
557
|
+
declare const BUILT_IN_FORM_FIELD_TYPES: readonly FormFieldType[];
|
|
558
|
+
/**
|
|
559
|
+
* Narrow an `AnyFormField` to the closed built-in `FormField` union. Returns
|
|
560
|
+
* `false` for a plugin-contributed field, so callers handle it generically
|
|
561
|
+
* before switching on the built-in discriminant.
|
|
562
|
+
*/
|
|
563
|
+
declare function isKnownFormField(field: AnyFormField): field is FormField;
|
|
447
564
|
/**
|
|
448
565
|
* Base form field properties.
|
|
449
566
|
* All form field types extend this interface.
|
|
@@ -475,6 +592,16 @@ interface BaseFormField {
|
|
|
475
592
|
width?: "25%" | "33%" | "50%" | "66%" | "75%" | "100%";
|
|
476
593
|
};
|
|
477
594
|
}
|
|
595
|
+
/**
|
|
596
|
+
* A plugin-contributed form field type (outside the built-in union). Carries
|
|
597
|
+
* only the base properties — the plugin owns its editor component and value
|
|
598
|
+
* semantics — and its `type` is the plugin's registered field-type id. Kept a
|
|
599
|
+
* distinct union member so built-in `case` narrowing is unaffected while a
|
|
600
|
+
* plugin field still type-checks as a `FormField`.
|
|
601
|
+
*/
|
|
602
|
+
interface CustomFormField extends Omit<BaseFormField, "type"> {
|
|
603
|
+
type: string & {};
|
|
604
|
+
}
|
|
478
605
|
/**
|
|
479
606
|
* Text input field.
|
|
480
607
|
*/
|
|
@@ -608,9 +735,6 @@ interface HiddenFormField extends Omit<BaseFormField, "type"> {
|
|
|
608
735
|
type: "hidden";
|
|
609
736
|
defaultValue?: string;
|
|
610
737
|
}
|
|
611
|
-
/**
|
|
612
|
-
* Validation rules for form fields.
|
|
613
|
-
*/
|
|
614
738
|
interface ValidationRules {
|
|
615
739
|
/** Custom error message */
|
|
616
740
|
errorMessage?: string;
|
|
@@ -650,11 +774,19 @@ interface FormSettings {
|
|
|
650
774
|
/**
|
|
651
775
|
* Confirmation type after successful submission.
|
|
652
776
|
* - "message": Display a success message
|
|
653
|
-
* - "redirect": Redirect to a URL
|
|
777
|
+
* - "redirect": Redirect to a URL
|
|
778
|
+
* - "relationship": Redirect to a linked document (requires
|
|
779
|
+
* `redirectRelationships` in the plugin options)
|
|
654
780
|
*
|
|
655
781
|
* @default "message"
|
|
656
782
|
*/
|
|
657
|
-
confirmationType?: "message" | "redirect";
|
|
783
|
+
confirmationType?: "message" | "redirect" | "relationship";
|
|
784
|
+
/**
|
|
785
|
+
* Linked document for relationship-based redirects (the collection's
|
|
786
|
+
* `redirectPage` relationship value). Preserved verbatim — resolution
|
|
787
|
+
* happens where the relationship is rendered.
|
|
788
|
+
*/
|
|
789
|
+
redirectPage?: unknown;
|
|
658
790
|
/** Success message (supports HTML) - used when confirmationType is "message" */
|
|
659
791
|
successMessage?: string;
|
|
660
792
|
/** Redirect URL after successful submission - used when confirmationType is "redirect" */
|
|
@@ -667,13 +799,20 @@ interface FormSettings {
|
|
|
667
799
|
relationTo: string;
|
|
668
800
|
value: string;
|
|
669
801
|
};
|
|
670
|
-
/** Allow multiple submissions from same
|
|
802
|
+
/** Allow multiple submissions from same IP (default true) */
|
|
671
803
|
allowMultipleSubmissions?: boolean;
|
|
672
|
-
/**
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
804
|
+
/**
|
|
805
|
+
* Per-form honeypot override. Unset inherits the plugin's
|
|
806
|
+
* `spamProtection.honeypot`; the form wins where set.
|
|
807
|
+
*/
|
|
808
|
+
honeypotEnabled?: boolean;
|
|
809
|
+
/**
|
|
810
|
+
* Per-form reCAPTCHA override. Unset inherits the plugin's
|
|
811
|
+
* `spamProtection.recaptcha.enabled`; the form wins where set.
|
|
812
|
+
*/
|
|
813
|
+
captchaEnabled?: boolean;
|
|
814
|
+
/** reCAPTCHA site key (client-facing) when captcha is enabled per-form */
|
|
815
|
+
captchaSiteKey?: string;
|
|
677
816
|
}
|
|
678
817
|
/**
|
|
679
818
|
* Email notification configuration for a form.
|
|
@@ -826,8 +965,16 @@ interface FormSubmission {
|
|
|
826
965
|
formSlug: string;
|
|
827
966
|
/** Submission data (JSON) */
|
|
828
967
|
data: Record<string, unknown>;
|
|
829
|
-
/**
|
|
830
|
-
|
|
968
|
+
/**
|
|
969
|
+
* Submission status.
|
|
970
|
+
*
|
|
971
|
+
* `spam` is one of them, not a separate flag: the stored field offers it, the
|
|
972
|
+
* admin has a Spam tab and filters its other views with `not_equals: "spam"`,
|
|
973
|
+
* and marking something "Not spam" moves it back to `new`.
|
|
974
|
+
*/
|
|
975
|
+
status: "new" | "read" | "archived" | "spam";
|
|
976
|
+
/** Which spam check flagged this, when one did. */
|
|
977
|
+
spamReason?: string | null;
|
|
831
978
|
/** Internal notes (admin only) */
|
|
832
979
|
notes?: string;
|
|
833
980
|
/** Metadata */
|
|
@@ -843,36 +990,32 @@ interface FormSubmission {
|
|
|
843
990
|
* Used internally by the plugin.
|
|
844
991
|
*/
|
|
845
992
|
interface ResolvedFormBuilderConfig {
|
|
846
|
-
formOverrides:
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
time: boolean | Partial<FieldBlockConfig>;
|
|
873
|
-
hidden: boolean | Partial<FieldBlockConfig>;
|
|
874
|
-
};
|
|
875
|
-
redirectRelationships: string[];
|
|
993
|
+
formOverrides: ResolvedCollectionOverrides;
|
|
994
|
+
formSubmissionOverrides: ResolvedCollectionOverrides;
|
|
995
|
+
fields: FormFieldToggles;
|
|
996
|
+
/**
|
|
997
|
+
* The collection-to-URL map, with the array shorthand already expanded.
|
|
998
|
+
*
|
|
999
|
+
* ONE shape, so nothing downstream branches on which spelling was written.
|
|
1000
|
+
* The list of redirect collections is `Object.keys` of this rather than a
|
|
1001
|
+
* second field beside it, which would agree with it today and drift later.
|
|
1002
|
+
*/
|
|
1003
|
+
redirectRelationships: RedirectRelationships;
|
|
1004
|
+
/**
|
|
1005
|
+
* Whether each redirect target collection is localized, keyed by slug.
|
|
1006
|
+
*
|
|
1007
|
+
* Resolved at `init` from the collection's own registered metadata rather
|
|
1008
|
+
* than asked for in options, because the collection already declares it and
|
|
1009
|
+
* a second declaration drifts.
|
|
1010
|
+
*
|
|
1011
|
+
* It decides whether a target's main-row `status` answers for the document:
|
|
1012
|
+
* a localized collection publishes on a locale companion, so the row reads
|
|
1013
|
+
* `draft` while a translation is public. A slug missing here is a collection
|
|
1014
|
+
* whose metadata could not be read — undefined, not false, because reading
|
|
1015
|
+
* an unknown as "not localized" is what marks a reachable translation as a
|
|
1016
|
+
* draft.
|
|
1017
|
+
*/
|
|
1018
|
+
redirectTargetLocalization: Record<string, boolean>;
|
|
876
1019
|
beforeEmail?: FormBuilderPluginOptions["beforeEmail"];
|
|
877
1020
|
notifications: {
|
|
878
1021
|
defaultFrom?: string;
|
|
@@ -932,81 +1075,4 @@ declare function isCheckboxFormField(field: FormField): field is CheckboxFormFie
|
|
|
932
1075
|
*/
|
|
933
1076
|
declare function isFileFormField(field: FormField): field is FileFormField;
|
|
934
1077
|
|
|
935
|
-
|
|
936
|
-
* Props for the SubmissionList component.
|
|
937
|
-
*/
|
|
938
|
-
interface SubmissionListProps {
|
|
939
|
-
/** Form document containing field definitions */
|
|
940
|
-
form: FormDocument;
|
|
941
|
-
/** Array of submission documents to display */
|
|
942
|
-
submissions: SubmissionDocument[];
|
|
943
|
-
/** Whether data is currently loading */
|
|
944
|
-
isLoading?: boolean;
|
|
945
|
-
/** Callback when submission status is changed */
|
|
946
|
-
onStatusChange?: (id: string, status: "new" | "read" | "archived") => Promise<void>;
|
|
947
|
-
/** Callback when submission is deleted */
|
|
948
|
-
onDelete?: (id: string) => Promise<void>;
|
|
949
|
-
/** Callback when bulk delete is triggered */
|
|
950
|
-
onBulkDelete?: (ids: string[]) => Promise<void>;
|
|
951
|
-
/** Callback when bulk status change is triggered */
|
|
952
|
-
onBulkStatusChange?: (ids: string[], status: "new" | "read" | "archived") => Promise<void>;
|
|
953
|
-
/** Callback when export is triggered */
|
|
954
|
-
onExport?: (format: "csv" | "json") => void;
|
|
955
|
-
/** Callback when a submission is clicked for detail view */
|
|
956
|
-
onViewDetail?: (submission: SubmissionDocument) => void;
|
|
957
|
-
}
|
|
958
|
-
/**
|
|
959
|
-
* Submission List Component
|
|
960
|
-
*
|
|
961
|
-
* Displays form submissions in a table with filtering, selection, and actions.
|
|
962
|
-
*
|
|
963
|
-
* @example
|
|
964
|
-
* ```tsx
|
|
965
|
-
* <SubmissionList
|
|
966
|
-
* form={form}
|
|
967
|
-
* submissions={submissions}
|
|
968
|
-
* onStatusChange={handleStatusChange}
|
|
969
|
-
* onDelete={handleDelete}
|
|
970
|
-
* onExport={handleExport}
|
|
971
|
-
* onViewDetail={handleViewDetail}
|
|
972
|
-
* />
|
|
973
|
-
* ```
|
|
974
|
-
*/
|
|
975
|
-
declare function SubmissionList({ form, submissions, isLoading, onStatusChange, onDelete, onBulkDelete, onBulkStatusChange, onExport, onViewDetail, }: SubmissionListProps): React.ReactElement;
|
|
976
|
-
|
|
977
|
-
/**
|
|
978
|
-
* Props for the SubmissionDetail component.
|
|
979
|
-
*/
|
|
980
|
-
interface SubmissionDetailProps {
|
|
981
|
-
/** Form document containing field definitions */
|
|
982
|
-
form: FormDocument;
|
|
983
|
-
/** Submission document to display */
|
|
984
|
-
submission: SubmissionDocument;
|
|
985
|
-
/** Callback when status is changed */
|
|
986
|
-
onStatusChange?: (status: "new" | "read" | "archived") => Promise<void>;
|
|
987
|
-
/** Callback when notes are updated */
|
|
988
|
-
onNotesUpdate?: (notes: string) => Promise<void>;
|
|
989
|
-
/** Callback when back button is clicked */
|
|
990
|
-
onBack?: () => void;
|
|
991
|
-
/** Callback when delete is triggered */
|
|
992
|
-
onDelete?: () => Promise<void>;
|
|
993
|
-
}
|
|
994
|
-
/**
|
|
995
|
-
* Submission Detail Component
|
|
996
|
-
*
|
|
997
|
-
* Displays full submission data with status management and notes.
|
|
998
|
-
*
|
|
999
|
-
* @example
|
|
1000
|
-
* ```tsx
|
|
1001
|
-
* <SubmissionDetail
|
|
1002
|
-
* form={form}
|
|
1003
|
-
* submission={submission}
|
|
1004
|
-
* onStatusChange={handleStatusChange}
|
|
1005
|
-
* onNotesUpdate={handleNotesUpdate}
|
|
1006
|
-
* onBack={handleBack}
|
|
1007
|
-
* />
|
|
1008
|
-
* ```
|
|
1009
|
-
*/
|
|
1010
|
-
declare function SubmissionDetail({ form, submission, onStatusChange, onNotesUpdate, onBack, onDelete, }: SubmissionDetailProps): React.ReactElement;
|
|
1011
|
-
|
|
1012
|
-
export { isFormFieldType as A, type BaseFormField as B, type CheckboxFormField as C, type DateFormField as D, type EmailFormField as E, type FormBuilderPluginOptions as F, isSelectFormField as G, type HiddenFormField as H, isTextFormField as I, SubmissionDetail as J, SubmissionList as K, type NumberFormField as N, type PhoneFormField as P, type ResolvedFormBuilderConfig as R, type SelectFormField as S, type TextFormField as T, type UrlFormField as U, type ValidationRules as V, type WebhookEvent as W, type FormConfig as a, type FormSettings as b, type FormNotifications as c, type FileFormField as d, type RadioFormField as e, type TextareaFormField as f, type TimeFormField as g, type ConditionalLogic as h, type FormField as i, type SubmissionDocument as j, type FormDocument as k, type ConditionalLogicCondition as l, type EmailConfig as m, type FieldBlockConfig as n, type FormAccess as o, type FormFieldType as p, type FormHookContext as q, type FormHooks as r, type FormSubmission as s, type SubmissionDetailProps as t, type SubmissionListProps as u, type WebhookConfig as v, isCheckboxFormField as w, isEmailFormField as x, isFileFormField as y, isFormField as z };
|
|
1078
|
+
export { type AnyFormField as A, BUILT_IN_FORM_FIELD_TYPES as B, type CheckboxFormField as C, type DateFormField as D, type EmailFormField as E, type FormBuilderPluginOptions as F, isEmailFormField as G, type HiddenFormField as H, isFileFormField as I, isFormField as J, isFormFieldType as K, isKnownFormField as L, isSelectFormField as M, type NumberFormField as N, isTextFormField as O, type PhoneFormField as P, type ResolvedFormBuilderConfig as R, type SelectFormField as S, type TextFormField as T, type UrlFormField as U, type ValidationRules as V, type WebhookEvent as W, type FormConfig as a, type FormSettings as b, type FormNotifications as c, type FileFormField as d, type RadioFormField as e, type TextareaFormField as f, type TimeFormField as g, type ConditionalLogic as h, type SubmissionDocument as i, type FormDocument as j, type BaseFormField as k, type ConditionalLogicCondition as l, type CustomFormField as m, type EmailConfig as n, type FieldBlockConfig as o, type FormAccess as p, type FormField as q, type FormFieldType as r, type FormFieldTypeId as s, type FormHookContext as t, type FormHooks as u, type FormNotification as v, type FormNotificationItem as w, type FormSubmission as x, type WebhookConfig as y, isCheckboxFormField as z };
|