@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.
- package/CHANGELOG.md +34 -0
- package/README.md +4 -2
- package/dist/actions/body/converters.d.ts +20 -0
- package/dist/actions/body/converters.js +57 -0
- package/dist/actions/body/converters.js.map +1 -0
- package/dist/actions/body/escapeHtml.d.ts +6 -0
- package/dist/actions/body/escapeHtml.js +14 -0
- package/dist/actions/body/escapeHtml.js.map +1 -0
- package/dist/actions/body/serializeBody.d.ts +35 -0
- package/dist/actions/body/serializeBody.js +76 -0
- package/dist/actions/body/serializeBody.js.map +1 -0
- package/dist/actions/body/serializeSlate.js +31 -0
- package/dist/actions/body/serializeSlate.js.map +1 -0
- package/dist/actions/body/wildcards.d.ts +10 -0
- package/dist/actions/body/wildcards.js +33 -0
- package/dist/actions/body/wildcards.js.map +1 -0
- package/dist/actions/builtin/confirmation.js +28 -12
- package/dist/actions/builtin/confirmation.js.map +1 -1
- package/dist/actions/builtin/emailTeam.js +7 -9
- package/dist/actions/builtin/emailTeam.js.map +1 -1
- package/dist/actions/builtin/signedWebhook.js +21 -3
- package/dist/actions/builtin/signedWebhook.js.map +1 -1
- package/dist/actions/defineAction.d.ts +2 -1
- package/dist/actions/defineAction.js.map +1 -1
- package/dist/actions/dispatch.js +2 -1
- package/dist/actions/dispatch.js.map +1 -1
- package/dist/actions/runActions.js +8 -1
- package/dist/actions/runActions.js.map +1 -1
- package/dist/actions/task.js +7 -5
- package/dist/actions/task.js.map +1 -1
- package/dist/calc/normalizeCalc.js +5 -17
- package/dist/calc/normalizeCalc.js.map +1 -1
- package/dist/calc/types.d.ts +8 -2
- package/dist/calc/types.js +22 -0
- package/dist/calc/types.js.map +1 -0
- package/dist/client/ByteSizeField.d.ts +21 -0
- package/dist/client/ByteSizeField.js +56 -0
- package/dist/client/ByteSizeField.js.map +1 -0
- package/dist/client/ConditionBuilder.js +2 -1
- package/dist/client/ConditionBuilder.js.map +1 -1
- package/dist/client/FieldNameSelect.d.ts +20 -0
- package/dist/client/FieldNameSelect.js +58 -0
- package/dist/client/FieldNameSelect.js.map +1 -0
- package/dist/client/FlowBuilder.d.ts +0 -1
- package/dist/client/FlowBuilder.js +4 -6
- package/dist/client/FlowBuilder.js.map +1 -1
- package/dist/client/FormConditionField.js +1 -4
- package/dist/client/FormConditionField.js.map +1 -1
- package/dist/client/admin.css +192 -0
- package/dist/client/toStaticLabel.js +13 -0
- package/dist/client/toStaticLabel.js.map +1 -0
- package/dist/collections/formSubmissions.js +60 -39
- package/dist/collections/formSubmissions.js.map +1 -1
- package/dist/collections/forms.js +143 -115
- package/dist/collections/forms.js.map +1 -1
- package/dist/collections/uploads.d.ts +2 -1
- package/dist/collections/uploads.js +22 -13
- package/dist/collections/uploads.js.map +1 -1
- package/dist/exports/client.d.ts +3 -1
- package/dist/exports/client.js +3 -1
- package/dist/exports/react.d.ts +7 -2
- package/dist/exports/react.js +6 -2
- package/dist/exports/types.d.ts +2 -1
- package/dist/fields/buildFieldBlocks.js +22 -12
- package/dist/fields/buildFieldBlocks.js.map +1 -1
- package/dist/fields/builtin/calculation.js +115 -2
- package/dist/fields/builtin/calculation.js.map +1 -1
- package/dist/fields/builtin/date.js +29 -0
- package/dist/fields/builtin/date.js.map +1 -0
- package/dist/fields/builtin/file.d.ts +15 -0
- package/dist/fields/builtin/file.js +79 -3
- package/dist/fields/builtin/file.js.map +1 -1
- package/dist/fields/builtin/index.d.ts +14 -0
- package/dist/fields/builtin/index.js +13 -2
- package/dist/fields/builtin/index.js.map +1 -1
- package/dist/fields/builtin/repeater.js +44 -0
- package/dist/fields/builtin/repeater.js.map +1 -0
- package/dist/fields/fieldNamesOfType.js +25 -0
- package/dist/fields/fieldNamesOfType.js.map +1 -0
- package/dist/fields/sharedConfig.js +30 -18
- package/dist/fields/sharedConfig.js.map +1 -1
- package/dist/fields/types.d.ts +2 -1
- package/dist/index.d.ts +38 -2
- package/dist/index.js +17 -5
- package/dist/index.js.map +1 -1
- package/dist/plugin/collectionOverrides.d.ts +22 -0
- package/dist/plugin/registerCollections.js +39 -10
- package/dist/plugin/registerCollections.js.map +1 -1
- package/dist/react/Form.d.ts +32 -3
- package/dist/react/Form.js +50 -8
- package/dist/react/Form.js.map +1 -1
- package/dist/react/FormContext.js.map +1 -1
- package/dist/react/Poll.js +1 -1
- package/dist/react/captcha/HcaptchaCaptcha.d.ts +28 -0
- package/dist/react/captcha/HcaptchaCaptcha.js +53 -0
- package/dist/react/captcha/HcaptchaCaptcha.js.map +1 -0
- package/dist/react/captcha/RecaptchaCaptcha.d.ts +41 -0
- package/dist/react/captcha/RecaptchaCaptcha.js +93 -0
- package/dist/react/captcha/RecaptchaCaptcha.js.map +1 -0
- package/dist/react/captcha/TurnstileCaptcha.d.ts +28 -0
- package/dist/react/captcha/TurnstileCaptcha.js +53 -0
- package/dist/react/captcha/TurnstileCaptcha.js.map +1 -0
- package/dist/react/captcha/types.d.ts +8 -0
- package/dist/react/captcha/useCaptchaScript.js +45 -0
- package/dist/react/captcha/useCaptchaScript.js.map +1 -0
- package/dist/react/captcha/vendors.js +8 -0
- package/dist/react/captcha/vendors.js.map +1 -0
- package/dist/react/primitives/Input.d.ts +1 -1
- package/dist/react/primitives/Input.js.map +1 -1
- package/dist/react/renderers/calculation.js +1 -1
- package/dist/react/renderers/checkbox.js +1 -1
- package/dist/react/renderers/consent.js +1 -1
- package/dist/react/renderers/date.js +37 -0
- package/dist/react/renderers/date.js.map +1 -0
- package/dist/react/renderers/email.js +1 -1
- package/dist/react/renderers/file.js +20 -7
- package/dist/react/renderers/file.js.map +1 -1
- package/dist/react/renderers/index.js +4 -0
- package/dist/react/renderers/index.js.map +1 -1
- package/dist/react/renderers/number.js +1 -1
- package/dist/react/renderers/repeater.js +113 -0
- package/dist/react/renderers/repeater.js.map +1 -0
- package/dist/react/renderers/select.js +1 -1
- package/dist/react/renderers/text.js +1 -1
- package/dist/react/renderers/textarea.js +1 -1
- package/dist/spam/captcha.d.ts +3 -2
- package/dist/spam/captcha.js +3 -2
- package/dist/spam/captcha.js.map +1 -1
- package/dist/spam/clientIp.js +9 -0
- package/dist/spam/clientIp.js.map +1 -0
- package/dist/spam/identify.js +3 -6
- package/dist/spam/identify.js.map +1 -1
- package/dist/spam/providers/hcaptcha.d.ts +17 -0
- package/dist/spam/providers/hcaptcha.js +18 -0
- package/dist/spam/providers/hcaptcha.js.map +1 -0
- package/dist/spam/providers/recaptcha.d.ts +23 -0
- package/dist/spam/providers/recaptcha.js +23 -0
- package/dist/spam/providers/recaptcha.js.map +1 -0
- package/dist/spam/providers/siteverify.js +34 -0
- package/dist/spam/providers/siteverify.js.map +1 -0
- package/dist/spam/providers/turnstile.d.ts +17 -0
- package/dist/spam/providers/turnstile.js +18 -0
- package/dist/spam/providers/turnstile.js.map +1 -0
- package/dist/spam/spamGuard.js +2 -5
- package/dist/spam/spamGuard.js.map +1 -1
- package/dist/spam/types.d.ts +2 -2
- package/dist/submissions/SubmissionAnswers.d.ts +2 -4
- package/dist/submissions/SubmissionAnswers.js +110 -34
- package/dist/submissions/SubmissionAnswers.js.map +1 -1
- package/dist/submissions/SubmissionAnswersClient.js +142 -0
- package/dist/submissions/SubmissionAnswersClient.js.map +1 -0
- package/dist/submissions/runSubmission.js +54 -2
- package/dist/submissions/runSubmission.js.map +1 -1
- package/dist/submissions/types.d.ts +2 -1
- package/dist/translations/en.js +52 -5
- package/dist/translations/en.js.map +1 -1
- package/dist/translations/keys.d.ts +51 -4
- package/dist/translations/keys.js +52 -5
- package/dist/translations/keys.js.map +1 -1
- package/dist/uploads/formatBytes.d.ts +9 -0
- package/dist/uploads/formatBytes.js +25 -0
- package/dist/uploads/formatBytes.js.map +1 -0
- package/dist/uploads/resolveFileRef.js +1 -1
- package/dist/uploads/resolveFileRef.js.map +1 -1
- package/dist/validation/builtin/index.d.ts +14 -0
- package/dist/validation/builtin/index.js +12 -1
- package/dist/validation/builtin/index.js.map +1 -1
- package/dist/validation/builtin/maxDate.js +23 -0
- package/dist/validation/builtin/maxDate.js.map +1 -0
- package/dist/validation/builtin/minDate.js +23 -0
- package/dist/validation/builtin/minDate.js.map +1 -0
- package/dist/validation/builtin/validateDateBound.js +18 -0
- package/dist/validation/builtin/validateDateBound.js.map +1 -0
- package/dist/validation/runValidation.js +1 -1
- package/dist/validation/runValidation.js.map +1 -1
- package/package.json +4 -3
- package/styles/form-builder.css +0 -190
|
@@ -1,7 +1,116 @@
|
|
|
1
1
|
import { keys } from "../../translations/keys.js";
|
|
2
|
-
import { labelFor } from "../../translations/server.js";
|
|
2
|
+
import { asTranslate, labelFor } from "../../translations/server.js";
|
|
3
|
+
import { CALC_FNS, CALC_OPS } from "../../calc/types.js";
|
|
4
|
+
import { normalizeCalc } from "../../calc/normalizeCalc.js";
|
|
3
5
|
import { defineFormField } from "../defineFormField.js";
|
|
4
6
|
//#region src/fields/builtin/calculation.ts
|
|
7
|
+
/**
|
|
8
|
+
* Editor-facing JSON schema for `CalcExpression` (src/calc/types.ts), used by the admin JSON
|
|
9
|
+
* field's Monaco editor for autocomplete and inline diagnostics. The real validity gate is
|
|
10
|
+
* `validateExpression`/`normalizeCalc`; this schema is a convenience, not the source of truth.
|
|
11
|
+
*/
|
|
12
|
+
const calcExpressionSchema = {
|
|
13
|
+
uri: "https://10xmedia.de/schemas/form-builder/calc-expression.json",
|
|
14
|
+
fileMatch: ["https://10xmedia.de/schemas/form-builder/calc-expression.json"],
|
|
15
|
+
schema: {
|
|
16
|
+
$ref: "#/definitions/expr",
|
|
17
|
+
definitions: {
|
|
18
|
+
expr: { oneOf: [
|
|
19
|
+
{ $ref: "#/definitions/lit" },
|
|
20
|
+
{ $ref: "#/definitions/ref" },
|
|
21
|
+
{ $ref: "#/definitions/op" },
|
|
22
|
+
{ $ref: "#/definitions/neg" },
|
|
23
|
+
{ $ref: "#/definitions/fn" },
|
|
24
|
+
{ $ref: "#/definitions/weight" }
|
|
25
|
+
] },
|
|
26
|
+
lit: {
|
|
27
|
+
type: "object",
|
|
28
|
+
properties: {
|
|
29
|
+
type: { enum: ["lit"] },
|
|
30
|
+
value: { type: "number" }
|
|
31
|
+
},
|
|
32
|
+
required: ["type", "value"],
|
|
33
|
+
additionalProperties: false
|
|
34
|
+
},
|
|
35
|
+
ref: {
|
|
36
|
+
type: "object",
|
|
37
|
+
properties: {
|
|
38
|
+
type: { enum: ["ref"] },
|
|
39
|
+
field: { type: "string" }
|
|
40
|
+
},
|
|
41
|
+
required: ["type", "field"],
|
|
42
|
+
additionalProperties: false
|
|
43
|
+
},
|
|
44
|
+
op: {
|
|
45
|
+
type: "object",
|
|
46
|
+
properties: {
|
|
47
|
+
type: { enum: ["op"] },
|
|
48
|
+
op: { enum: [...CALC_OPS] },
|
|
49
|
+
left: { $ref: "#/definitions/expr" },
|
|
50
|
+
right: { $ref: "#/definitions/expr" }
|
|
51
|
+
},
|
|
52
|
+
required: [
|
|
53
|
+
"type",
|
|
54
|
+
"op",
|
|
55
|
+
"left",
|
|
56
|
+
"right"
|
|
57
|
+
],
|
|
58
|
+
additionalProperties: false
|
|
59
|
+
},
|
|
60
|
+
neg: {
|
|
61
|
+
type: "object",
|
|
62
|
+
properties: {
|
|
63
|
+
type: { enum: ["neg"] },
|
|
64
|
+
operand: { $ref: "#/definitions/expr" }
|
|
65
|
+
},
|
|
66
|
+
required: ["type", "operand"],
|
|
67
|
+
additionalProperties: false
|
|
68
|
+
},
|
|
69
|
+
fn: {
|
|
70
|
+
type: "object",
|
|
71
|
+
properties: {
|
|
72
|
+
type: { enum: ["fn"] },
|
|
73
|
+
fn: { enum: [...CALC_FNS] },
|
|
74
|
+
args: {
|
|
75
|
+
type: "array",
|
|
76
|
+
items: { $ref: "#/definitions/expr" }
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
required: [
|
|
80
|
+
"type",
|
|
81
|
+
"fn",
|
|
82
|
+
"args"
|
|
83
|
+
],
|
|
84
|
+
additionalProperties: false
|
|
85
|
+
},
|
|
86
|
+
weight: {
|
|
87
|
+
type: "object",
|
|
88
|
+
properties: {
|
|
89
|
+
type: { enum: ["weight"] },
|
|
90
|
+
field: { type: "string" },
|
|
91
|
+
weights: {
|
|
92
|
+
type: "object",
|
|
93
|
+
additionalProperties: { type: "number" }
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
required: [
|
|
97
|
+
"type",
|
|
98
|
+
"field",
|
|
99
|
+
"weights"
|
|
100
|
+
],
|
|
101
|
+
additionalProperties: false
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
/**
|
|
107
|
+
* Validates the calculation field's `expression`: unset/empty is fine, otherwise it must
|
|
108
|
+
* normalize into a well-formed `CalcExpression` tree. Exported for unit testing.
|
|
109
|
+
*/
|
|
110
|
+
const validateExpression = (value, { req }) => {
|
|
111
|
+
if (value == null || value === "") return true;
|
|
112
|
+
return normalizeCalc(value) !== void 0 ? true : asTranslate(req.t)(keys.validationCalcExpressionInvalid);
|
|
113
|
+
};
|
|
5
114
|
const calculationField = defineFormField({
|
|
6
115
|
type: "calculation",
|
|
7
116
|
label: keys.fieldTypeCalculation,
|
|
@@ -9,7 +118,11 @@ const calculationField = defineFormField({
|
|
|
9
118
|
config: [{
|
|
10
119
|
name: "expression",
|
|
11
120
|
type: "json",
|
|
12
|
-
label: labelFor(keys.configExpression)
|
|
121
|
+
label: labelFor(keys.configExpression),
|
|
122
|
+
admin: { description: labelFor(keys.configExpressionDescription) },
|
|
123
|
+
jsonSchema: calcExpressionSchema,
|
|
124
|
+
typescriptSchema: [() => ({ type: "object" })],
|
|
125
|
+
validate: validateExpression
|
|
13
126
|
}, {
|
|
14
127
|
name: "calcDisplay",
|
|
15
128
|
type: "checkbox",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"calculation.js","names":[],"sources":["../../../src/fields/builtin/calculation.ts"],"sourcesContent":["import { keys } from '../../translations/keys'\nimport { labelFor } from '../../translations/server'\nimport { defineFormField } from '../defineFormField'\n\nexport const calculationField = defineFormField<'number'>({\n\ttype: 'calculation',\n\tlabel: keys.fieldTypeCalculation,\n\tvalue: 'number',\n\tconfig: [\n\t\t{
|
|
1
|
+
{"version":3,"file":"calculation.js","names":[],"sources":["../../../src/fields/builtin/calculation.ts"],"sourcesContent":["import type { JSONField, PayloadRequest } from 'payload'\nimport { normalizeCalc } from '../../calc/normalizeCalc'\nimport { CALC_FNS, CALC_OPS } from '../../calc/types'\nimport { keys } from '../../translations/keys'\nimport { asTranslate, labelFor } from '../../translations/server'\nimport { defineFormField } from '../defineFormField'\n\ntype CalcExpressionSchema = NonNullable<JSONField['jsonSchema']>\n\n/**\n * Editor-facing JSON schema for `CalcExpression` (src/calc/types.ts), used by the admin JSON\n * field's Monaco editor for autocomplete and inline diagnostics. The real validity gate is\n * `validateExpression`/`normalizeCalc`; this schema is a convenience, not the source of truth.\n */\nconst calcExpressionSchema: CalcExpressionSchema = {\n\turi: 'https://10xmedia.de/schemas/form-builder/calc-expression.json',\n\tfileMatch: ['https://10xmedia.de/schemas/form-builder/calc-expression.json'],\n\tschema: {\n\t\t$ref: '#/definitions/expr',\n\t\tdefinitions: {\n\t\t\texpr: {\n\t\t\t\toneOf: [\n\t\t\t\t\t{ $ref: '#/definitions/lit' },\n\t\t\t\t\t{ $ref: '#/definitions/ref' },\n\t\t\t\t\t{ $ref: '#/definitions/op' },\n\t\t\t\t\t{ $ref: '#/definitions/neg' },\n\t\t\t\t\t{ $ref: '#/definitions/fn' },\n\t\t\t\t\t{ $ref: '#/definitions/weight' },\n\t\t\t\t],\n\t\t\t},\n\t\t\tlit: {\n\t\t\t\ttype: 'object',\n\t\t\t\tproperties: { type: { enum: ['lit'] }, value: { type: 'number' } },\n\t\t\t\trequired: ['type', 'value'],\n\t\t\t\tadditionalProperties: false,\n\t\t\t},\n\t\t\tref: {\n\t\t\t\ttype: 'object',\n\t\t\t\tproperties: { type: { enum: ['ref'] }, field: { type: 'string' } },\n\t\t\t\trequired: ['type', 'field'],\n\t\t\t\tadditionalProperties: false,\n\t\t\t},\n\t\t\top: {\n\t\t\t\ttype: 'object',\n\t\t\t\tproperties: {\n\t\t\t\t\ttype: { enum: ['op'] },\n\t\t\t\t\top: { enum: [...CALC_OPS] },\n\t\t\t\t\tleft: { $ref: '#/definitions/expr' },\n\t\t\t\t\tright: { $ref: '#/definitions/expr' },\n\t\t\t\t},\n\t\t\t\trequired: ['type', 'op', 'left', 'right'],\n\t\t\t\tadditionalProperties: false,\n\t\t\t},\n\t\t\tneg: {\n\t\t\t\ttype: 'object',\n\t\t\t\tproperties: { type: { enum: ['neg'] }, operand: { $ref: '#/definitions/expr' } },\n\t\t\t\trequired: ['type', 'operand'],\n\t\t\t\tadditionalProperties: false,\n\t\t\t},\n\t\t\tfn: {\n\t\t\t\ttype: 'object',\n\t\t\t\tproperties: {\n\t\t\t\t\ttype: { enum: ['fn'] },\n\t\t\t\t\tfn: { enum: [...CALC_FNS] },\n\t\t\t\t\targs: { type: 'array', items: { $ref: '#/definitions/expr' } },\n\t\t\t\t},\n\t\t\t\trequired: ['type', 'fn', 'args'],\n\t\t\t\tadditionalProperties: false,\n\t\t\t},\n\t\t\tweight: {\n\t\t\t\ttype: 'object',\n\t\t\t\tproperties: {\n\t\t\t\t\ttype: { enum: ['weight'] },\n\t\t\t\t\tfield: { type: 'string' },\n\t\t\t\t\tweights: { type: 'object', additionalProperties: { type: 'number' } },\n\t\t\t\t},\n\t\t\t\trequired: ['type', 'field', 'weights'],\n\t\t\t\tadditionalProperties: false,\n\t\t\t},\n\t\t},\n\t},\n}\n\n/**\n * Validates the calculation field's `expression`: unset/empty is fine, otherwise it must\n * normalize into a well-formed `CalcExpression` tree. Exported for unit testing.\n */\nexport const validateExpression = (\n\tvalue: unknown,\n\t{ req }: { data?: unknown; req: PayloadRequest }\n): string | true => {\n\tif (value == null || value === '') {\n\t\treturn true\n\t}\n\treturn normalizeCalc(value) !== undefined\n\t\t? true\n\t\t: asTranslate(req.t)(keys.validationCalcExpressionInvalid)\n}\n\nexport const calculationField = defineFormField<'number'>({\n\ttype: 'calculation',\n\tlabel: keys.fieldTypeCalculation,\n\tvalue: 'number',\n\tconfig: [\n\t\t{\n\t\t\tname: 'expression',\n\t\t\ttype: 'json',\n\t\t\tlabel: labelFor(keys.configExpression),\n\t\t\tadmin: { description: labelFor(keys.configExpressionDescription) },\n\t\t\tjsonSchema: calcExpressionSchema,\n\t\t\t// generate:types embeds jsonSchema.schema into the config-level schema, where its\n\t\t\t// document-root-relative $refs cannot resolve; hand type generation a flat shape instead.\n\t\t\ttypescriptSchema: [() => ({ type: 'object' })],\n\t\t\tvalidate: validateExpression,\n\t\t},\n\t\t{\n\t\t\tname: 'calcDisplay',\n\t\t\ttype: 'checkbox',\n\t\t\tdefaultValue: true,\n\t\t\tlabel: labelFor(keys.configCalcDisplay),\n\t\t},\n\t],\n\tformat: ({ value }) => (value == null ? '' : String(value)),\n})\n"],"mappings":";;;;;;;;;;;AAcA,MAAM,uBAA6C;CAClD,KAAK;CACL,WAAW,CAAC,+DAA+D;CAC3E,QAAQ;EACP,MAAM;EACN,aAAa;GACZ,MAAM,EACL,OAAO;IACN,EAAE,MAAM,oBAAoB;IAC5B,EAAE,MAAM,oBAAoB;IAC5B,EAAE,MAAM,mBAAmB;IAC3B,EAAE,MAAM,oBAAoB;IAC5B,EAAE,MAAM,mBAAmB;IAC3B,EAAE,MAAM,uBAAuB;GAChC,EACD;GACA,KAAK;IACJ,MAAM;IACN,YAAY;KAAE,MAAM,EAAE,MAAM,CAAC,KAAK,EAAE;KAAG,OAAO,EAAE,MAAM,SAAS;IAAE;IACjE,UAAU,CAAC,QAAQ,OAAO;IAC1B,sBAAsB;GACvB;GACA,KAAK;IACJ,MAAM;IACN,YAAY;KAAE,MAAM,EAAE,MAAM,CAAC,KAAK,EAAE;KAAG,OAAO,EAAE,MAAM,SAAS;IAAE;IACjE,UAAU,CAAC,QAAQ,OAAO;IAC1B,sBAAsB;GACvB;GACA,IAAI;IACH,MAAM;IACN,YAAY;KACX,MAAM,EAAE,MAAM,CAAC,IAAI,EAAE;KACrB,IAAI,EAAE,MAAM,CAAC,GAAG,QAAQ,EAAE;KAC1B,MAAM,EAAE,MAAM,qBAAqB;KACnC,OAAO,EAAE,MAAM,qBAAqB;IACrC;IACA,UAAU;KAAC;KAAQ;KAAM;KAAQ;IAAO;IACxC,sBAAsB;GACvB;GACA,KAAK;IACJ,MAAM;IACN,YAAY;KAAE,MAAM,EAAE,MAAM,CAAC,KAAK,EAAE;KAAG,SAAS,EAAE,MAAM,qBAAqB;IAAE;IAC/E,UAAU,CAAC,QAAQ,SAAS;IAC5B,sBAAsB;GACvB;GACA,IAAI;IACH,MAAM;IACN,YAAY;KACX,MAAM,EAAE,MAAM,CAAC,IAAI,EAAE;KACrB,IAAI,EAAE,MAAM,CAAC,GAAG,QAAQ,EAAE;KAC1B,MAAM;MAAE,MAAM;MAAS,OAAO,EAAE,MAAM,qBAAqB;KAAE;IAC9D;IACA,UAAU;KAAC;KAAQ;KAAM;IAAM;IAC/B,sBAAsB;GACvB;GACA,QAAQ;IACP,MAAM;IACN,YAAY;KACX,MAAM,EAAE,MAAM,CAAC,QAAQ,EAAE;KACzB,OAAO,EAAE,MAAM,SAAS;KACxB,SAAS;MAAE,MAAM;MAAU,sBAAsB,EAAE,MAAM,SAAS;KAAE;IACrE;IACA,UAAU;KAAC;KAAQ;KAAS;IAAS;IACrC,sBAAsB;GACvB;EACD;CACD;AACD;;;;;AAMA,MAAa,sBACZ,OACA,EAAE,UACiB;CACnB,IAAI,SAAS,QAAQ,UAAU,IAC9B,OAAO;CAER,OAAO,cAAc,KAAK,MAAM,KAAA,IAC7B,OACA,YAAY,IAAI,CAAC,EAAE,KAAK,+BAA+B;AAC3D;AAEA,MAAa,mBAAmB,gBAA0B;CACzD,MAAM;CACN,OAAO,KAAK;CACZ,OAAO;CACP,QAAQ,CACP;EACC,MAAM;EACN,MAAM;EACN,OAAO,SAAS,KAAK,gBAAgB;EACrC,OAAO,EAAE,aAAa,SAAS,KAAK,2BAA2B,EAAE;EACjE,YAAY;EAGZ,kBAAkB,QAAQ,EAAE,MAAM,SAAS,EAAE;EAC7C,UAAU;CACX,GACA;EACC,MAAM;EACN,MAAM;EACN,cAAc;EACd,OAAO,SAAS,KAAK,iBAAiB;CACvC,CACD;CACA,SAAS,EAAE,YAAa,SAAS,OAAO,KAAK,OAAO,KAAK;AAC1D,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { keys } from "../../translations/keys.js";
|
|
2
|
+
import { defineFormField } from "../defineFormField.js";
|
|
3
|
+
//#region src/fields/builtin/date.ts
|
|
4
|
+
const DATE_PATTERN = /^(\d{4})-(\d{2})-(\d{2})$/;
|
|
5
|
+
/** True calendar-date check for `YYYY-MM-DD` strings (rejects e.g. `2024-02-30`). */
|
|
6
|
+
const isValidCalendarDate = (value) => {
|
|
7
|
+
const match = DATE_PATTERN.exec(value);
|
|
8
|
+
if (!match) return false;
|
|
9
|
+
const [, yearStr, monthStr, dayStr] = match;
|
|
10
|
+
const year = Number(yearStr);
|
|
11
|
+
const month = Number(monthStr);
|
|
12
|
+
const day = Number(dayStr);
|
|
13
|
+
const date = new Date(Date.UTC(year, month - 1, day));
|
|
14
|
+
return date.getUTCFullYear() === year && date.getUTCMonth() === month - 1 && date.getUTCDate() === day;
|
|
15
|
+
};
|
|
16
|
+
const dateField = defineFormField({
|
|
17
|
+
type: "date",
|
|
18
|
+
label: keys.fieldTypeDate,
|
|
19
|
+
value: "date",
|
|
20
|
+
validate: ({ value, t }) => {
|
|
21
|
+
if (value == null || value === "") return true;
|
|
22
|
+
return isValidCalendarDate(value) ? true : t(keys.validationDate);
|
|
23
|
+
},
|
|
24
|
+
format: ({ value }) => value == null ? "" : String(value)
|
|
25
|
+
});
|
|
26
|
+
//#endregion
|
|
27
|
+
export { dateField, isValidCalendarDate };
|
|
28
|
+
|
|
29
|
+
//# sourceMappingURL=date.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"date.js","names":[],"sources":["../../../src/fields/builtin/date.ts"],"sourcesContent":["import { keys } from '../../translations/keys'\nimport { defineFormField } from '../defineFormField'\n\nconst DATE_PATTERN = /^(\\d{4})-(\\d{2})-(\\d{2})$/\n\n/** True calendar-date check for `YYYY-MM-DD` strings (rejects e.g. `2024-02-30`). */\nexport const isValidCalendarDate = (value: string): boolean => {\n\tconst match = DATE_PATTERN.exec(value)\n\tif (!match) {\n\t\treturn false\n\t}\n\tconst [, yearStr, monthStr, dayStr] = match\n\tconst year = Number(yearStr)\n\tconst month = Number(monthStr)\n\tconst day = Number(dayStr)\n\tconst date = new Date(Date.UTC(year, month - 1, day))\n\treturn (\n\t\tdate.getUTCFullYear() === year && date.getUTCMonth() === month - 1 && date.getUTCDate() === day\n\t)\n}\n\nexport const dateField = defineFormField<'date'>({\n\ttype: 'date',\n\tlabel: keys.fieldTypeDate,\n\tvalue: 'date',\n\tvalidate: ({ value, t }) => {\n\t\tif (value == null || value === '') {\n\t\t\treturn true\n\t\t}\n\t\treturn isValidCalendarDate(value) ? true : t(keys.validationDate)\n\t},\n\tformat: ({ value }) => (value == null ? '' : String(value)),\n})\n"],"mappings":";;;AAGA,MAAM,eAAe;;AAGrB,MAAa,uBAAuB,UAA2B;CAC9D,MAAM,QAAQ,aAAa,KAAK,KAAK;CACrC,IAAI,CAAC,OACJ,OAAO;CAER,MAAM,GAAG,SAAS,UAAU,UAAU;CACtC,MAAM,OAAO,OAAO,OAAO;CAC3B,MAAM,QAAQ,OAAO,QAAQ;CAC7B,MAAM,MAAM,OAAO,MAAM;CACzB,MAAM,OAAO,IAAI,KAAK,KAAK,IAAI,MAAM,QAAQ,GAAG,GAAG,CAAC;CACpD,OACC,KAAK,eAAe,MAAM,QAAQ,KAAK,YAAY,MAAM,QAAQ,KAAK,KAAK,WAAW,MAAM;AAE9F;AAEA,MAAa,YAAY,gBAAwB;CAChD,MAAM;CACN,OAAO,KAAK;CACZ,OAAO;CACP,WAAW,EAAE,OAAO,QAAQ;EAC3B,IAAI,SAAS,QAAQ,UAAU,IAC9B,OAAO;EAER,OAAO,oBAAoB,KAAK,IAAI,OAAO,EAAE,KAAK,cAAc;CACjE;CACA,SAAS,EAAE,YAAa,SAAS,OAAO,KAAK,OAAO,KAAK;AAC1D,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
//#region src/fields/builtin/file.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Curated MIME type choices for the file field's `mimeTypes` select. Values are raw MIME strings or
|
|
4
|
+
* trailing-`*` prefix wildcards, exactly the patterns `resolveFileRef` matches server-side; `type/*`
|
|
5
|
+
* values double as the file input's `accept` attribute (browsers ignore other prefix patterns, which
|
|
6
|
+
* is fine since the server stays authoritative). Every value must be 63 bytes or less: Payload's
|
|
7
|
+
* db-postgres adapter stores select options as a pg enum, and pg enum labels cap at 63 bytes.
|
|
8
|
+
*/
|
|
9
|
+
declare const fileMimeTypeOptions: {
|
|
10
|
+
label: string;
|
|
11
|
+
value: string;
|
|
12
|
+
}[];
|
|
13
|
+
//#endregion
|
|
14
|
+
export { fileMimeTypeOptions };
|
|
15
|
+
//# sourceMappingURL=file.d.ts.map
|
|
@@ -3,6 +3,76 @@ import { labelFor } from "../../translations/server.js";
|
|
|
3
3
|
import { defineFormField } from "../defineFormField.js";
|
|
4
4
|
//#region src/fields/builtin/file.ts
|
|
5
5
|
const isFileRef = (value) => typeof value === "object" && value !== null && "filename" in value;
|
|
6
|
+
const MAX_SIZE_REF = "@10x-media/form-builder/client#ByteSizeField";
|
|
7
|
+
/**
|
|
8
|
+
* Curated MIME type choices for the file field's `mimeTypes` select. Values are raw MIME strings or
|
|
9
|
+
* trailing-`*` prefix wildcards, exactly the patterns `resolveFileRef` matches server-side; `type/*`
|
|
10
|
+
* values double as the file input's `accept` attribute (browsers ignore other prefix patterns, which
|
|
11
|
+
* is fine since the server stays authoritative). Every value must be 63 bytes or less: Payload's
|
|
12
|
+
* db-postgres adapter stores select options as a pg enum, and pg enum labels cap at 63 bytes.
|
|
13
|
+
*/
|
|
14
|
+
const fileMimeTypeOptions = [
|
|
15
|
+
{
|
|
16
|
+
label: "Any image",
|
|
17
|
+
value: "image/*"
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
label: "PNG image",
|
|
21
|
+
value: "image/png"
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
label: "JPEG image",
|
|
25
|
+
value: "image/jpeg"
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
label: "WebP image",
|
|
29
|
+
value: "image/webp"
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
label: "GIF image",
|
|
33
|
+
value: "image/gif"
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
label: "SVG image",
|
|
37
|
+
value: "image/svg+xml"
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
label: "PDF",
|
|
41
|
+
value: "application/pdf"
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
label: "Plain text",
|
|
45
|
+
value: "text/plain"
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
label: "CSV",
|
|
49
|
+
value: "text/csv"
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
label: "ZIP archive",
|
|
53
|
+
value: "application/zip"
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
label: "Word document (.doc)",
|
|
57
|
+
value: "application/msword"
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
label: "Excel spreadsheet (.xls)",
|
|
61
|
+
value: "application/vnd.ms-excel"
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
label: "Office documents (docx, xlsx, pptx)",
|
|
65
|
+
value: "application/vnd.openxmlformats-officedocument.*"
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
label: "Any audio",
|
|
69
|
+
value: "audio/*"
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
label: "Any video",
|
|
73
|
+
value: "video/*"
|
|
74
|
+
}
|
|
75
|
+
];
|
|
6
76
|
/**
|
|
7
77
|
* The `file` field type. Its stored value is a server-captured {@link FileRef}; the client only ever submits
|
|
8
78
|
* the upload id, and `runSubmission` re-reads filename/mimeType/filesize from the upload doc at the trust
|
|
@@ -22,19 +92,25 @@ const fileField = defineFormField({
|
|
|
22
92
|
},
|
|
23
93
|
{
|
|
24
94
|
name: "mimeTypes",
|
|
25
|
-
type: "
|
|
95
|
+
type: "select",
|
|
26
96
|
hasMany: true,
|
|
97
|
+
options: fileMimeTypeOptions,
|
|
27
98
|
label: labelFor(keys.fileConfigMimeTypes)
|
|
28
99
|
},
|
|
29
100
|
{
|
|
30
101
|
name: "maxSize",
|
|
31
102
|
type: "number",
|
|
32
|
-
|
|
103
|
+
min: 0,
|
|
104
|
+
label: labelFor(keys.fileConfigMaxSize),
|
|
105
|
+
admin: {
|
|
106
|
+
description: labelFor(keys.fileConfigMaxSizeDescription),
|
|
107
|
+
components: { Field: MAX_SIZE_REF }
|
|
108
|
+
}
|
|
33
109
|
}
|
|
34
110
|
],
|
|
35
111
|
format: ({ value }) => isFileRef(value) ? value.filename : ""
|
|
36
112
|
});
|
|
37
113
|
//#endregion
|
|
38
|
-
export { fileField };
|
|
114
|
+
export { fileField, fileMimeTypeOptions };
|
|
39
115
|
|
|
40
116
|
//# sourceMappingURL=file.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"file.js","names":[],"sources":["../../../src/fields/builtin/file.ts"],"sourcesContent":["import { keys } from '../../translations/keys'\nimport { labelFor } from '../../translations/server'\nimport type { FileRef } from '../../uploads/types'\nimport { defineFormField } from '../defineFormField'\n\ntype FileConfig = {\n\trelationTo?: string\n\tmimeTypes?: string[]\n\tmaxSize?: number\n}\n\nconst isFileRef = (value: unknown): value is FileRef =>\n\ttypeof value === 'object' && value !== null && 'filename' in value\n\n/**\n * The `file` field type. Its stored value is a server-captured {@link FileRef}; the client only ever submits\n * the upload id, and `runSubmission` re-reads filename/mimeType/filesize from the upload doc at the trust\n * boundary (see `captureFileRef`). The intrinsic validator is intentionally a no-op: MIME/size/existence are\n * enforced authoritatively server-side against the stored doc, never against client metadata. `relationTo`,\n * `mimeTypes`, and `maxSize` persist on the block so the capture can enforce them.\n */\nexport const fileField = defineFormField<'file', FileConfig>({\n\ttype: 'file',\n\tlabel: keys.fieldTypeFile,\n\tvalue: 'file',\n\tconfig: [\n\t\t{ name: 'relationTo', type: 'text', label: labelFor(keys.fileConfigRelationTo) },\n\t\t{
|
|
1
|
+
{"version":3,"file":"file.js","names":[],"sources":["../../../src/fields/builtin/file.ts"],"sourcesContent":["import { keys } from '../../translations/keys'\nimport { labelFor } from '../../translations/server'\nimport type { FileRef } from '../../uploads/types'\nimport { defineFormField } from '../defineFormField'\n\ntype FileConfig = {\n\trelationTo?: string\n\tmimeTypes?: string[]\n\tmaxSize?: number\n}\n\nconst isFileRef = (value: unknown): value is FileRef =>\n\ttypeof value === 'object' && value !== null && 'filename' in value\n\nconst MAX_SIZE_REF = '@10x-media/form-builder/client#ByteSizeField'\n\n/**\n * Curated MIME type choices for the file field's `mimeTypes` select. Values are raw MIME strings or\n * trailing-`*` prefix wildcards, exactly the patterns `resolveFileRef` matches server-side; `type/*`\n * values double as the file input's `accept` attribute (browsers ignore other prefix patterns, which\n * is fine since the server stays authoritative). Every value must be 63 bytes or less: Payload's\n * db-postgres adapter stores select options as a pg enum, and pg enum labels cap at 63 bytes.\n */\nexport const fileMimeTypeOptions = [\n\t{ label: 'Any image', value: 'image/*' },\n\t{ label: 'PNG image', value: 'image/png' },\n\t{ label: 'JPEG image', value: 'image/jpeg' },\n\t{ label: 'WebP image', value: 'image/webp' },\n\t{ label: 'GIF image', value: 'image/gif' },\n\t{ label: 'SVG image', value: 'image/svg+xml' },\n\t{ label: 'PDF', value: 'application/pdf' },\n\t{ label: 'Plain text', value: 'text/plain' },\n\t{ label: 'CSV', value: 'text/csv' },\n\t{ label: 'ZIP archive', value: 'application/zip' },\n\t{ label: 'Word document (.doc)', value: 'application/msword' },\n\t{ label: 'Excel spreadsheet (.xls)', value: 'application/vnd.ms-excel' },\n\t{\n\t\tlabel: 'Office documents (docx, xlsx, pptx)',\n\t\tvalue: 'application/vnd.openxmlformats-officedocument.*',\n\t},\n\t{ label: 'Any audio', value: 'audio/*' },\n\t{ label: 'Any video', value: 'video/*' },\n]\n\n/**\n * The `file` field type. Its stored value is a server-captured {@link FileRef}; the client only ever submits\n * the upload id, and `runSubmission` re-reads filename/mimeType/filesize from the upload doc at the trust\n * boundary (see `captureFileRef`). The intrinsic validator is intentionally a no-op: MIME/size/existence are\n * enforced authoritatively server-side against the stored doc, never against client metadata. `relationTo`,\n * `mimeTypes`, and `maxSize` persist on the block so the capture can enforce them.\n */\nexport const fileField = defineFormField<'file', FileConfig>({\n\ttype: 'file',\n\tlabel: keys.fieldTypeFile,\n\tvalue: 'file',\n\tconfig: [\n\t\t{ name: 'relationTo', type: 'text', label: labelFor(keys.fileConfigRelationTo) },\n\t\t{\n\t\t\tname: 'mimeTypes',\n\t\t\ttype: 'select',\n\t\t\thasMany: true,\n\t\t\toptions: fileMimeTypeOptions,\n\t\t\tlabel: labelFor(keys.fileConfigMimeTypes),\n\t\t},\n\t\t{\n\t\t\tname: 'maxSize',\n\t\t\ttype: 'number',\n\t\t\tmin: 0,\n\t\t\tlabel: labelFor(keys.fileConfigMaxSize),\n\t\t\tadmin: {\n\t\t\t\tdescription: labelFor(keys.fileConfigMaxSizeDescription),\n\t\t\t\tcomponents: { Field: MAX_SIZE_REF },\n\t\t\t},\n\t\t},\n\t],\n\tformat: ({ value }) => (isFileRef(value) ? value.filename : ''),\n})\n"],"mappings":";;;;AAWA,MAAM,aAAa,UAClB,OAAO,UAAU,YAAY,UAAU,QAAQ,cAAc;AAE9D,MAAM,eAAe;;;;;;;;AASrB,MAAa,sBAAsB;CAClC;EAAE,OAAO;EAAa,OAAO;CAAU;CACvC;EAAE,OAAO;EAAa,OAAO;CAAY;CACzC;EAAE,OAAO;EAAc,OAAO;CAAa;CAC3C;EAAE,OAAO;EAAc,OAAO;CAAa;CAC3C;EAAE,OAAO;EAAa,OAAO;CAAY;CACzC;EAAE,OAAO;EAAa,OAAO;CAAgB;CAC7C;EAAE,OAAO;EAAO,OAAO;CAAkB;CACzC;EAAE,OAAO;EAAc,OAAO;CAAa;CAC3C;EAAE,OAAO;EAAO,OAAO;CAAW;CAClC;EAAE,OAAO;EAAe,OAAO;CAAkB;CACjD;EAAE,OAAO;EAAwB,OAAO;CAAqB;CAC7D;EAAE,OAAO;EAA4B,OAAO;CAA2B;CACvE;EACC,OAAO;EACP,OAAO;CACR;CACA;EAAE,OAAO;EAAa,OAAO;CAAU;CACvC;EAAE,OAAO;EAAa,OAAO;CAAU;AACxC;;;;;;;;AASA,MAAa,YAAY,gBAAoC;CAC5D,MAAM;CACN,OAAO,KAAK;CACZ,OAAO;CACP,QAAQ;EACP;GAAE,MAAM;GAAc,MAAM;GAAQ,OAAO,SAAS,KAAK,oBAAoB;EAAE;EAC/E;GACC,MAAM;GACN,MAAM;GACN,SAAS;GACT,SAAS;GACT,OAAO,SAAS,KAAK,mBAAmB;EACzC;EACA;GACC,MAAM;GACN,MAAM;GACN,KAAK;GACL,OAAO,SAAS,KAAK,iBAAiB;GACtC,OAAO;IACN,aAAa,SAAS,KAAK,4BAA4B;IACvD,YAAY,EAAE,OAAO,aAAa;GACnC;EACD;CACD;CACA,SAAS,EAAE,YAAa,UAAU,KAAK,IAAI,MAAM,WAAW;AAC7D,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { AnyFormFieldDefinition } from "../types.js";
|
|
2
|
+
|
|
3
|
+
//#region src/fields/builtin/index.d.ts
|
|
4
|
+
declare const defaultFieldDefinitions: AnyFormFieldDefinition[];
|
|
5
|
+
/**
|
|
6
|
+
* `defaultFieldDefinitions` indexed by `type`, so a single built-in can be spread and tweaked
|
|
7
|
+
* without hand-rolling a `.find()`, e.g.
|
|
8
|
+
* `fields: { text: { ...defaultFieldDefinitionsByType.text, validate: myValidate } }`. The
|
|
9
|
+
* `fields` plugin option replaces a built-in of the same `type`; `false` removes it, `true` keeps it.
|
|
10
|
+
*/
|
|
11
|
+
declare const defaultFieldDefinitionsByType: Record<string, AnyFormFieldDefinition>;
|
|
12
|
+
//#endregion
|
|
13
|
+
export { defaultFieldDefinitions, defaultFieldDefinitionsByType };
|
|
14
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { calculationField } from "./calculation.js";
|
|
2
2
|
import { checkboxField } from "./checkbox.js";
|
|
3
3
|
import { consentField } from "./consent.js";
|
|
4
|
+
import { dateField } from "./date.js";
|
|
4
5
|
import { emailField } from "./email.js";
|
|
5
6
|
import { fileField } from "./file.js";
|
|
6
7
|
import { numberField } from "./number.js";
|
|
8
|
+
import { repeaterField } from "./repeater.js";
|
|
7
9
|
import { selectField } from "./select.js";
|
|
8
10
|
import { textField } from "./text.js";
|
|
9
11
|
import { textareaField } from "./textarea.js";
|
|
@@ -17,9 +19,18 @@ const defaultFieldDefinitions = [
|
|
|
17
19
|
checkboxField,
|
|
18
20
|
calculationField,
|
|
19
21
|
consentField,
|
|
20
|
-
fileField
|
|
22
|
+
fileField,
|
|
23
|
+
repeaterField,
|
|
24
|
+
dateField
|
|
21
25
|
];
|
|
26
|
+
/**
|
|
27
|
+
* `defaultFieldDefinitions` indexed by `type`, so a single built-in can be spread and tweaked
|
|
28
|
+
* without hand-rolling a `.find()`, e.g.
|
|
29
|
+
* `fields: { text: { ...defaultFieldDefinitionsByType.text, validate: myValidate } }`. The
|
|
30
|
+
* `fields` plugin option replaces a built-in of the same `type`; `false` removes it, `true` keeps it.
|
|
31
|
+
*/
|
|
32
|
+
const defaultFieldDefinitionsByType = Object.fromEntries(defaultFieldDefinitions.map((definition) => [definition.type, definition]));
|
|
22
33
|
//#endregion
|
|
23
|
-
export { defaultFieldDefinitions };
|
|
34
|
+
export { defaultFieldDefinitions, defaultFieldDefinitionsByType };
|
|
24
35
|
|
|
25
36
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../../src/fields/builtin/index.ts"],"sourcesContent":["import type { AnyFormFieldDefinition } from '../types'\nimport { calculationField } from './calculation'\nimport { checkboxField } from './checkbox'\nimport { consentField } from './consent'\nimport { emailField } from './email'\nimport { fileField } from './file'\nimport { numberField } from './number'\nimport { selectField } from './select'\nimport { textField } from './text'\nimport { textareaField } from './textarea'\n\n// Field types are authored with precise value/config generics; the registry stores them erased\n// (config is re-narrowed per matched type at execution). One cast per built-in, no `any`.\nexport const defaultFieldDefinitions: AnyFormFieldDefinition[] = [\n\ttextField as AnyFormFieldDefinition,\n\ttextareaField as AnyFormFieldDefinition,\n\temailField as AnyFormFieldDefinition,\n\tnumberField as AnyFormFieldDefinition,\n\tselectField as AnyFormFieldDefinition,\n\tcheckboxField as AnyFormFieldDefinition,\n\tcalculationField as AnyFormFieldDefinition,\n\tconsentField as AnyFormFieldDefinition,\n\tfileField as AnyFormFieldDefinition,\n]\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../src/fields/builtin/index.ts"],"sourcesContent":["import type { AnyFormFieldDefinition } from '../types'\nimport { calculationField } from './calculation'\nimport { checkboxField } from './checkbox'\nimport { consentField } from './consent'\nimport { dateField } from './date'\nimport { emailField } from './email'\nimport { fileField } from './file'\nimport { numberField } from './number'\nimport { repeaterField } from './repeater'\nimport { selectField } from './select'\nimport { textField } from './text'\nimport { textareaField } from './textarea'\n\n// Field types are authored with precise value/config generics; the registry stores them erased\n// (config is re-narrowed per matched type at execution). One cast per built-in, no `any`.\nexport const defaultFieldDefinitions: AnyFormFieldDefinition[] = [\n\ttextField as AnyFormFieldDefinition,\n\ttextareaField as AnyFormFieldDefinition,\n\temailField as AnyFormFieldDefinition,\n\tnumberField as AnyFormFieldDefinition,\n\tselectField as AnyFormFieldDefinition,\n\tcheckboxField as AnyFormFieldDefinition,\n\tcalculationField as AnyFormFieldDefinition,\n\tconsentField as AnyFormFieldDefinition,\n\tfileField as AnyFormFieldDefinition,\n\trepeaterField as AnyFormFieldDefinition,\n\tdateField as AnyFormFieldDefinition,\n]\n\n/**\n * `defaultFieldDefinitions` indexed by `type`, so a single built-in can be spread and tweaked\n * without hand-rolling a `.find()`, e.g.\n * `fields: { text: { ...defaultFieldDefinitionsByType.text, validate: myValidate } }`. The\n * `fields` plugin option replaces a built-in of the same `type`; `false` removes it, `true` keeps it.\n */\nexport const defaultFieldDefinitionsByType: Record<string, AnyFormFieldDefinition> =\n\tObject.fromEntries(defaultFieldDefinitions.map((definition) => [definition.type, definition]))\n"],"mappings":";;;;;;;;;;;;AAeA,MAAa,0BAAoD;CAChE;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACD;;;;;;;AAQA,MAAa,gCACZ,OAAO,YAAY,wBAAwB,KAAK,eAAe,CAAC,WAAW,MAAM,UAAU,CAAC,CAAC"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { keys } from "../../translations/keys.js";
|
|
2
|
+
import { labelFor } from "../../translations/server.js";
|
|
3
|
+
import { defineFormField } from "../defineFormField.js";
|
|
4
|
+
//#region src/fields/builtin/repeater.ts
|
|
5
|
+
const repeaterField = defineFormField({
|
|
6
|
+
type: "repeater",
|
|
7
|
+
label: keys.fieldTypeRepeater,
|
|
8
|
+
value: "repeater",
|
|
9
|
+
config: [
|
|
10
|
+
{
|
|
11
|
+
name: "minRows",
|
|
12
|
+
type: "number",
|
|
13
|
+
min: 0,
|
|
14
|
+
label: labelFor(keys.configMinRows)
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
name: "maxRows",
|
|
18
|
+
type: "number",
|
|
19
|
+
min: 1,
|
|
20
|
+
label: labelFor(keys.configMaxRows)
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
name: "addLabel",
|
|
24
|
+
type: "text",
|
|
25
|
+
label: labelFor(keys.configAddLabel)
|
|
26
|
+
}
|
|
27
|
+
],
|
|
28
|
+
validate: ({ value, config, t }) => {
|
|
29
|
+
const rows = Array.isArray(value) ? value : [];
|
|
30
|
+
const min = typeof config.minRows === "number" ? config.minRows : 0;
|
|
31
|
+
if (rows.length < min) return t(keys.validationRepeaterMin).replace("{min}", String(min));
|
|
32
|
+
const max = typeof config.maxRows === "number" ? config.maxRows : void 0;
|
|
33
|
+
if (max != null && rows.length > max) return t(keys.validationRepeaterMax).replace("{max}", String(max));
|
|
34
|
+
return true;
|
|
35
|
+
},
|
|
36
|
+
format: ({ value, t }) => {
|
|
37
|
+
const count = Array.isArray(value) ? value.length : 0;
|
|
38
|
+
return t(keys.repeaterRowCount).replace("{count}", String(count));
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
//#endregion
|
|
42
|
+
export { repeaterField };
|
|
43
|
+
|
|
44
|
+
//# sourceMappingURL=repeater.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repeater.js","names":[],"sources":["../../../src/fields/builtin/repeater.ts"],"sourcesContent":["import { keys } from '../../translations/keys'\nimport { labelFor } from '../../translations/server'\nimport { defineFormField } from '../defineFormField'\n\ntype RepeaterConfig = {\n\tminRows?: number\n\tmaxRows?: number\n\taddLabel?: string\n}\n\nexport const repeaterField = defineFormField<'repeater', RepeaterConfig>({\n\ttype: 'repeater',\n\tlabel: keys.fieldTypeRepeater,\n\tvalue: 'repeater',\n\tconfig: [\n\t\t{\n\t\t\tname: 'minRows',\n\t\t\ttype: 'number',\n\t\t\tmin: 0,\n\t\t\tlabel: labelFor(keys.configMinRows),\n\t\t},\n\t\t{\n\t\t\tname: 'maxRows',\n\t\t\ttype: 'number',\n\t\t\tmin: 1,\n\t\t\tlabel: labelFor(keys.configMaxRows),\n\t\t},\n\t\t{\n\t\t\tname: 'addLabel',\n\t\t\ttype: 'text',\n\t\t\tlabel: labelFor(keys.configAddLabel),\n\t\t},\n\t\t// subFields blocks field is injected by buildFieldBlocks after the main loop,\n\t\t// so all non-repeater blocks are available and repeater-in-repeater is excluded.\n\t],\n\tvalidate: ({ value, config, t }) => {\n\t\tconst rows = Array.isArray(value) ? value : []\n\t\tconst min = typeof config.minRows === 'number' ? config.minRows : 0\n\t\tif (rows.length < min) {\n\t\t\treturn t(keys.validationRepeaterMin).replace('{min}', String(min))\n\t\t}\n\t\tconst max = typeof config.maxRows === 'number' ? config.maxRows : undefined\n\t\tif (max != null && rows.length > max) {\n\t\t\treturn t(keys.validationRepeaterMax).replace('{max}', String(max))\n\t\t}\n\t\treturn true\n\t},\n\tformat: ({ value, t }) => {\n\t\tconst count = Array.isArray(value) ? value.length : 0\n\t\treturn t(keys.repeaterRowCount).replace('{count}', String(count))\n\t},\n})\n"],"mappings":";;;;AAUA,MAAa,gBAAgB,gBAA4C;CACxE,MAAM;CACN,OAAO,KAAK;CACZ,OAAO;CACP,QAAQ;EACP;GACC,MAAM;GACN,MAAM;GACN,KAAK;GACL,OAAO,SAAS,KAAK,aAAa;EACnC;EACA;GACC,MAAM;GACN,MAAM;GACN,KAAK;GACL,OAAO,SAAS,KAAK,aAAa;EACnC;EACA;GACC,MAAM;GACN,MAAM;GACN,OAAO,SAAS,KAAK,cAAc;EACpC;CAGD;CACA,WAAW,EAAE,OAAO,QAAQ,QAAQ;EACnC,MAAM,OAAO,MAAM,QAAQ,KAAK,IAAI,QAAQ,CAAC;EAC7C,MAAM,MAAM,OAAO,OAAO,YAAY,WAAW,OAAO,UAAU;EAClE,IAAI,KAAK,SAAS,KACjB,OAAO,EAAE,KAAK,qBAAqB,EAAE,QAAQ,SAAS,OAAO,GAAG,CAAC;EAElE,MAAM,MAAM,OAAO,OAAO,YAAY,WAAW,OAAO,UAAU,KAAA;EAClE,IAAI,OAAO,QAAQ,KAAK,SAAS,KAChC,OAAO,EAAE,KAAK,qBAAqB,EAAE,QAAQ,SAAS,OAAO,GAAG,CAAC;EAElE,OAAO;CACR;CACA,SAAS,EAAE,OAAO,QAAQ;EACzB,MAAM,QAAQ,MAAM,QAAQ,KAAK,IAAI,MAAM,SAAS;EACpD,OAAO,EAAE,KAAK,gBAAgB,EAAE,QAAQ,WAAW,OAAO,KAAK,CAAC;CACjE;AACD,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
//#region src/fields/fieldNamesOfType.ts
|
|
2
|
+
/**
|
|
3
|
+
* Names of form `fields` blocks whose `blockType` is in `types`, trimmed and non-empty.
|
|
4
|
+
* Server-safe and defensive: `fields` may be missing, non-array, or contain garbled rows
|
|
5
|
+
* mid-edit. The single source of truth for which field names are selectable and valid as
|
|
6
|
+
* a field reference (e.g. the confirmation action's `toField`), so client options and
|
|
7
|
+
* server validation cannot drift apart.
|
|
8
|
+
*/
|
|
9
|
+
const fieldNamesOfType = (fields, types) => {
|
|
10
|
+
if (!Array.isArray(fields)) return [];
|
|
11
|
+
const names = [];
|
|
12
|
+
for (const row of fields) {
|
|
13
|
+
if (!row || typeof row !== "object") continue;
|
|
14
|
+
const { blockType, name } = row;
|
|
15
|
+
if (typeof blockType !== "string" || !types.includes(blockType)) continue;
|
|
16
|
+
if (typeof name !== "string") continue;
|
|
17
|
+
const trimmed = name.trim();
|
|
18
|
+
if (trimmed.length > 0) names.push(trimmed);
|
|
19
|
+
}
|
|
20
|
+
return names;
|
|
21
|
+
};
|
|
22
|
+
//#endregion
|
|
23
|
+
export { fieldNamesOfType };
|
|
24
|
+
|
|
25
|
+
//# sourceMappingURL=fieldNamesOfType.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fieldNamesOfType.js","names":[],"sources":["../../src/fields/fieldNamesOfType.ts"],"sourcesContent":["/**\n * Names of form `fields` blocks whose `blockType` is in `types`, trimmed and non-empty.\n * Server-safe and defensive: `fields` may be missing, non-array, or contain garbled rows\n * mid-edit. The single source of truth for which field names are selectable and valid as\n * a field reference (e.g. the confirmation action's `toField`), so client options and\n * server validation cannot drift apart.\n */\nexport const fieldNamesOfType = (fields: unknown, types: readonly string[]): string[] => {\n\tif (!Array.isArray(fields)) {\n\t\treturn []\n\t}\n\tconst names: string[] = []\n\tfor (const row of fields) {\n\t\tif (!row || typeof row !== 'object') {\n\t\t\tcontinue\n\t\t}\n\t\tconst { blockType, name } = row as { blockType?: unknown; name?: unknown }\n\t\tif (typeof blockType !== 'string' || !types.includes(blockType)) {\n\t\t\tcontinue\n\t\t}\n\t\tif (typeof name !== 'string') {\n\t\t\tcontinue\n\t\t}\n\t\tconst trimmed = name.trim()\n\t\tif (trimmed.length > 0) {\n\t\t\tnames.push(trimmed)\n\t\t}\n\t}\n\treturn names\n}\n"],"mappings":";;;;;;;;AAOA,MAAa,oBAAoB,QAAiB,UAAuC;CACxF,IAAI,CAAC,MAAM,QAAQ,MAAM,GACxB,OAAO,CAAC;CAET,MAAM,QAAkB,CAAC;CACzB,KAAK,MAAM,OAAO,QAAQ;EACzB,IAAI,CAAC,OAAO,OAAO,QAAQ,UAC1B;EAED,MAAM,EAAE,WAAW,SAAS;EAC5B,IAAI,OAAO,cAAc,YAAY,CAAC,MAAM,SAAS,SAAS,GAC7D;EAED,IAAI,OAAO,SAAS,UACnB;EAED,MAAM,UAAU,KAAK,KAAK;EAC1B,IAAI,QAAQ,SAAS,GACpB,MAAM,KAAK,OAAO;CAEpB;CACA,OAAO;AACR"}
|
|
@@ -13,11 +13,10 @@ const conditionField = (name, labelKey, conditionTypes) => ({
|
|
|
13
13
|
});
|
|
14
14
|
/**
|
|
15
15
|
* Config every field instance carries regardless of type. `name` is the machine key written into
|
|
16
|
-
* submissions; `width` is stored for the layout grid. `
|
|
17
|
-
*
|
|
18
|
-
* after these.
|
|
16
|
+
* submissions; `width` is stored for the layout grid. Field types add their own `config` after
|
|
17
|
+
* these inside the Field tab (see `fieldBlockTabs`).
|
|
19
18
|
*/
|
|
20
|
-
const sharedFieldConfig = (
|
|
19
|
+
const sharedFieldConfig = () => [
|
|
21
20
|
{
|
|
22
21
|
name: "name",
|
|
23
22
|
type: "text",
|
|
@@ -67,23 +66,36 @@ const sharedFieldConfig = (conditionTypes) => [
|
|
|
67
66
|
name: "description",
|
|
68
67
|
type: "textarea",
|
|
69
68
|
label: labelFor(keys.configDescription)
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
69
|
+
}
|
|
70
|
+
];
|
|
71
|
+
/**
|
|
72
|
+
* The single field of every field block: unnamed tabs (presentational only, data paths stay flat).
|
|
73
|
+
* Field tab holds the shared basics plus the type's own config; Validation holds the rule blocks and
|
|
74
|
+
* `validateWhen`; Advanced holds `visibleWhen` and `hidden`. `visibleWhen`/`validateWhen` store a
|
|
75
|
+
* canonical Payload `Where`, edited by the native condition builder.
|
|
76
|
+
*/
|
|
77
|
+
const fieldBlockTabs = (conditionTypes, typeConfig, validations) => ({
|
|
78
|
+
type: "tabs",
|
|
79
|
+
tabs: [
|
|
80
|
+
{
|
|
81
|
+
label: labelFor(keys.tabField),
|
|
82
|
+
fields: [...sharedFieldConfig(), ...typeConfig]
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
label: labelFor(keys.tabValidation),
|
|
86
|
+
fields: [validations, conditionField("validateWhen", keys.configValidateWhen, conditionTypes)]
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
label: labelFor(keys.tabAdvanced),
|
|
90
|
+
fields: [conditionField("visibleWhen", keys.configVisibleWhen, conditionTypes), {
|
|
79
91
|
name: "hidden",
|
|
80
92
|
type: "checkbox",
|
|
81
93
|
label: labelFor(keys.configHidden)
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
94
|
+
}]
|
|
95
|
+
}
|
|
96
|
+
]
|
|
97
|
+
});
|
|
86
98
|
//#endregion
|
|
87
|
-
export {
|
|
99
|
+
export { fieldBlockTabs };
|
|
88
100
|
|
|
89
101
|
//# sourceMappingURL=sharedConfig.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sharedConfig.js","names":[],"sources":["../../src/fields/sharedConfig.ts"],"sourcesContent":["import type { Field } from 'payload'\nimport type { ConditionFieldType } from '../conditions/fieldTypes'\nimport { keys } from '../translations/keys'\nimport { labelFor } from '../translations/server'\n\nconst CONDITION_FIELD_REF = '@10x-media/form-builder/client#FormConditionField'\n\nconst conditionField = (\n\tname: 'visibleWhen' | 'validateWhen',\n\tlabelKey: string,\n\tconditionTypes: Record<string, ConditionFieldType>\n): Field => ({\n\tname,\n\ttype: 'json',\n\tlabel: labelFor(labelKey),\n\tadmin: {\n\t\tcomponents: {\n\t\t\tField: { path: CONDITION_FIELD_REF, clientProps: { conditionTypes } },\n\t\t},\n\t},\n})\n\n/**\n * Config every field instance carries regardless of type. `name` is the machine key written into\n * submissions; `width` is stored for the layout grid. `
|
|
1
|
+
{"version":3,"file":"sharedConfig.js","names":[],"sources":["../../src/fields/sharedConfig.ts"],"sourcesContent":["import type { Field } from 'payload'\nimport type { ConditionFieldType } from '../conditions/fieldTypes'\nimport { keys } from '../translations/keys'\nimport { labelFor } from '../translations/server'\n\nconst CONDITION_FIELD_REF = '@10x-media/form-builder/client#FormConditionField'\n\nconst conditionField = (\n\tname: 'visibleWhen' | 'validateWhen',\n\tlabelKey: string,\n\tconditionTypes: Record<string, ConditionFieldType>\n): Field => ({\n\tname,\n\ttype: 'json',\n\tlabel: labelFor(labelKey),\n\tadmin: {\n\t\tcomponents: {\n\t\t\tField: { path: CONDITION_FIELD_REF, clientProps: { conditionTypes } },\n\t\t},\n\t},\n})\n\n/**\n * Config every field instance carries regardless of type. `name` is the machine key written into\n * submissions; `width` is stored for the layout grid. Field types add their own `config` after\n * these inside the Field tab (see `fieldBlockTabs`).\n */\nexport const sharedFieldConfig = (): Field[] => [\n\t{ name: 'name', type: 'text', required: true, label: labelFor(keys.configName) },\n\t{ name: 'label', type: 'text', label: labelFor(keys.configLabel) },\n\t{ name: 'required', type: 'checkbox', label: labelFor(keys.configRequired) },\n\t{\n\t\tname: 'width',\n\t\ttype: 'select',\n\t\tdefaultValue: 'full',\n\t\tlabel: labelFor(keys.configWidth),\n\t\toptions: [\n\t\t\t{ label: 'Full', value: 'full' },\n\t\t\t{ label: 'Half', value: 'half' },\n\t\t\t{ label: 'Third', value: 'third' },\n\t\t\t{ label: 'Two thirds', value: 'twoThirds' },\n\t\t],\n\t},\n\t{ name: 'placeholder', type: 'text', label: labelFor(keys.configPlaceholder) },\n\t{ name: 'description', type: 'textarea', label: labelFor(keys.configDescription) },\n]\n\n/**\n * The single field of every field block: unnamed tabs (presentational only, data paths stay flat).\n * Field tab holds the shared basics plus the type's own config; Validation holds the rule blocks and\n * `validateWhen`; Advanced holds `visibleWhen` and `hidden`. `visibleWhen`/`validateWhen` store a\n * canonical Payload `Where`, edited by the native condition builder.\n */\nexport const fieldBlockTabs = (\n\tconditionTypes: Record<string, ConditionFieldType>,\n\ttypeConfig: Field[],\n\tvalidations: Field\n): Field => ({\n\ttype: 'tabs',\n\ttabs: [\n\t\t{\n\t\t\tlabel: labelFor(keys.tabField),\n\t\t\tfields: [...sharedFieldConfig(), ...typeConfig],\n\t\t},\n\t\t{\n\t\t\tlabel: labelFor(keys.tabValidation),\n\t\t\tfields: [\n\t\t\t\tvalidations,\n\t\t\t\tconditionField('validateWhen', keys.configValidateWhen, conditionTypes),\n\t\t\t],\n\t\t},\n\t\t{\n\t\t\tlabel: labelFor(keys.tabAdvanced),\n\t\t\tfields: [\n\t\t\t\tconditionField('visibleWhen', keys.configVisibleWhen, conditionTypes),\n\t\t\t\t{ name: 'hidden', type: 'checkbox', label: labelFor(keys.configHidden) },\n\t\t\t],\n\t\t},\n\t],\n})\n"],"mappings":";;;AAKA,MAAM,sBAAsB;AAE5B,MAAM,kBACL,MACA,UACA,oBACY;CACZ;CACA,MAAM;CACN,OAAO,SAAS,QAAQ;CACxB,OAAO,EACN,YAAY,EACX,OAAO;EAAE,MAAM;EAAqB,aAAa,EAAE,eAAe;CAAE,EACrE,EACD;AACD;;;;;;AAOA,MAAa,0BAAmC;CAC/C;EAAE,MAAM;EAAQ,MAAM;EAAQ,UAAU;EAAM,OAAO,SAAS,KAAK,UAAU;CAAE;CAC/E;EAAE,MAAM;EAAS,MAAM;EAAQ,OAAO,SAAS,KAAK,WAAW;CAAE;CACjE;EAAE,MAAM;EAAY,MAAM;EAAY,OAAO,SAAS,KAAK,cAAc;CAAE;CAC3E;EACC,MAAM;EACN,MAAM;EACN,cAAc;EACd,OAAO,SAAS,KAAK,WAAW;EAChC,SAAS;GACR;IAAE,OAAO;IAAQ,OAAO;GAAO;GAC/B;IAAE,OAAO;IAAQ,OAAO;GAAO;GAC/B;IAAE,OAAO;IAAS,OAAO;GAAQ;GACjC;IAAE,OAAO;IAAc,OAAO;GAAY;EAC3C;CACD;CACA;EAAE,MAAM;EAAe,MAAM;EAAQ,OAAO,SAAS,KAAK,iBAAiB;CAAE;CAC7E;EAAE,MAAM;EAAe,MAAM;EAAY,OAAO,SAAS,KAAK,iBAAiB;CAAE;AAClF;;;;;;;AAQA,MAAa,kBACZ,gBACA,YACA,iBACY;CACZ,MAAM;CACN,MAAM;EACL;GACC,OAAO,SAAS,KAAK,QAAQ;GAC7B,QAAQ,CAAC,GAAG,kBAAkB,GAAG,GAAG,UAAU;EAC/C;EACA;GACC,OAAO,SAAS,KAAK,aAAa;GAClC,QAAQ,CACP,aACA,eAAe,gBAAgB,KAAK,oBAAoB,cAAc,CACvE;EACD;EACA;GACC,OAAO,SAAS,KAAK,WAAW;GAChC,QAAQ,CACP,eAAe,eAAe,KAAK,mBAAmB,cAAc,GACpE;IAAE,MAAM;IAAU,MAAM;IAAY,OAAO,SAAS,KAAK,YAAY;GAAE,CACxE;EACD;CACD;AACD"}
|
package/dist/fields/types.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ import { StandardSchemaV1 } from "@standard-schema/spec";
|
|
|
5
5
|
|
|
6
6
|
//#region src/fields/types.d.ts
|
|
7
7
|
/** The stored value shapes a field type can declare. Drives `validate`/`format` typing and value coercion. */
|
|
8
|
-
type FormFieldValueKind = 'text' | 'number' | 'boolean' | 'date' | 'text[]' | 'file';
|
|
8
|
+
type FormFieldValueKind = 'text' | 'number' | 'boolean' | 'date' | 'text[]' | 'file' | 'repeater';
|
|
9
9
|
type ValueKindTypeMap = {
|
|
10
10
|
text: string;
|
|
11
11
|
number: number;
|
|
@@ -13,6 +13,7 @@ type ValueKindTypeMap = {
|
|
|
13
13
|
date: string;
|
|
14
14
|
'text[]': string[];
|
|
15
15
|
file: FileRef;
|
|
16
|
+
repeater: Array<Record<string, unknown>>;
|
|
16
17
|
};
|
|
17
18
|
type ValueOfKind<K extends FormFieldValueKind> = ValueKindTypeMap[K];
|
|
18
19
|
/** Resolved per-instance config values for a field type (loose at the DB boundary, narrowed by the author's generic). */
|