@marktiderman/genesis-forms 0.4.2 → 0.6.0
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 +195 -0
- package/dist/destinations.cjs +147 -7
- package/dist/destinations.cjs.map +1 -1
- package/dist/destinations.d.cts +1 -1
- package/dist/destinations.d.ts +1 -1
- package/dist/destinations.js +147 -7
- package/dist/destinations.js.map +1 -1
- package/dist/{engine-BkNuzlna.d.cts → engine-CpfOz8FN.d.ts} +33 -3
- package/dist/{engine-Dz9J5ej2.d.ts → engine-DC4YTPdr.d.cts} +33 -3
- package/dist/index.cjs +734 -69
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +142 -75
- package/dist/index.d.ts +142 -75
- package/dist/index.js +687 -70
- package/dist/index.js.map +1 -1
- package/dist/server.cjs +721 -26
- package/dist/server.cjs.map +1 -1
- package/dist/server.d.cts +201 -4
- package/dist/server.d.ts +201 -4
- package/dist/server.js +702 -27
- package/dist/server.js.map +1 -1
- package/dist/testing.cjs +494 -26
- package/dist/testing.cjs.map +1 -1
- package/dist/testing.d.cts +4 -4
- package/dist/testing.d.ts +4 -4
- package/dist/testing.js +494 -26
- package/dist/testing.js.map +1 -1
- package/dist/{types-BBKBQ8sp.d.cts → types-oAckGR_Z.d.cts} +31 -1
- package/dist/{types-BBKBQ8sp.d.ts → types-oAckGR_Z.d.ts} +31 -1
- package/dist/validate-B5WKHbst.d.cts +322 -0
- package/dist/validate-GpTXPwyl.d.ts +322 -0
- package/package.json +1 -1
- package/dist/validate-BXXqi0fq.d.cts +0 -30
- package/dist/validate-BjNwF1UE.d.ts +0 -30
|
@@ -32,6 +32,28 @@ interface FieldBlock {
|
|
|
32
32
|
identifying?: boolean;
|
|
33
33
|
props?: Record<string, Json>;
|
|
34
34
|
}
|
|
35
|
+
/**
|
|
36
|
+
* Where a choice field (single choice, multiple choice, dropdown) also takes
|
|
37
|
+
* options from, as `props.optionsFrom`. `source: "host"`: the app showing the
|
|
38
|
+
* form supplies the list named `key` when the form opens and again when a
|
|
39
|
+
* response is checked (`hostOptions` on `createForm` and `validateSubmission`),
|
|
40
|
+
* such as a practice's current coaches. They follow the field's own
|
|
41
|
+
* `props.options`, if it has any.
|
|
42
|
+
*/
|
|
43
|
+
interface OptionsSource {
|
|
44
|
+
source: "host";
|
|
45
|
+
key: string;
|
|
46
|
+
/**
|
|
47
|
+
* Show only the options that match another answer: those whose `attributes[attribute]` is the
|
|
48
|
+
* earlier question `field`'s answer (by key), or, for a list attribute or a multiple choice
|
|
49
|
+
* answer, shares a value with it. Until that question is answered every option shows. See
|
|
50
|
+
* `visibleOptions`.
|
|
51
|
+
*/
|
|
52
|
+
filter?: {
|
|
53
|
+
attribute: string;
|
|
54
|
+
field: string;
|
|
55
|
+
};
|
|
56
|
+
}
|
|
35
57
|
interface ContentBlock {
|
|
36
58
|
kind: "content";
|
|
37
59
|
id: string;
|
|
@@ -112,6 +134,14 @@ interface FormSettings {
|
|
|
112
134
|
anonymous?: boolean;
|
|
113
135
|
/** Clear the values of fields hidden by logic on submit. Default true. */
|
|
114
136
|
clearHiddenValues?: boolean;
|
|
137
|
+
/**
|
|
138
|
+
* Save answers as they go, off by default (Typeform's partial responses). When
|
|
139
|
+
* true, a host saves the answers so far each time the respondent moves on
|
|
140
|
+
* (genesis-forms-web's `onProgress`, with `formProgress` saying how far they
|
|
141
|
+
* got), so an unfinished response is kept even if they never submit. The form
|
|
142
|
+
* tells respondents so. Saving is the host's: the engine only says it's on.
|
|
143
|
+
*/
|
|
144
|
+
saveProgress?: boolean;
|
|
115
145
|
}
|
|
116
146
|
type FormLayout = {
|
|
117
147
|
mode: "classic";
|
|
@@ -152,4 +182,4 @@ type FormEvent = {
|
|
|
152
182
|
at?: number;
|
|
153
183
|
};
|
|
154
184
|
|
|
155
|
-
export type { Block as B, ContentBlock as C, Ending as E, FormDefinition as F, HiddenInput as H, Json as J, LogicRule as L,
|
|
185
|
+
export type { Block as B, ContentBlock as C, Ending as E, FormDefinition as F, HiddenInput as H, Json as J, LogicRule as L, OptionsSource as O, PageBreakBlock as P, FieldBlock as a, FormLayout as b, FormSettings as c, Condition as d, FormEvent as e, Operand as f, Operator as g };
|
|
@@ -32,6 +32,28 @@ interface FieldBlock {
|
|
|
32
32
|
identifying?: boolean;
|
|
33
33
|
props?: Record<string, Json>;
|
|
34
34
|
}
|
|
35
|
+
/**
|
|
36
|
+
* Where a choice field (single choice, multiple choice, dropdown) also takes
|
|
37
|
+
* options from, as `props.optionsFrom`. `source: "host"`: the app showing the
|
|
38
|
+
* form supplies the list named `key` when the form opens and again when a
|
|
39
|
+
* response is checked (`hostOptions` on `createForm` and `validateSubmission`),
|
|
40
|
+
* such as a practice's current coaches. They follow the field's own
|
|
41
|
+
* `props.options`, if it has any.
|
|
42
|
+
*/
|
|
43
|
+
interface OptionsSource {
|
|
44
|
+
source: "host";
|
|
45
|
+
key: string;
|
|
46
|
+
/**
|
|
47
|
+
* Show only the options that match another answer: those whose `attributes[attribute]` is the
|
|
48
|
+
* earlier question `field`'s answer (by key), or, for a list attribute or a multiple choice
|
|
49
|
+
* answer, shares a value with it. Until that question is answered every option shows. See
|
|
50
|
+
* `visibleOptions`.
|
|
51
|
+
*/
|
|
52
|
+
filter?: {
|
|
53
|
+
attribute: string;
|
|
54
|
+
field: string;
|
|
55
|
+
};
|
|
56
|
+
}
|
|
35
57
|
interface ContentBlock {
|
|
36
58
|
kind: "content";
|
|
37
59
|
id: string;
|
|
@@ -112,6 +134,14 @@ interface FormSettings {
|
|
|
112
134
|
anonymous?: boolean;
|
|
113
135
|
/** Clear the values of fields hidden by logic on submit. Default true. */
|
|
114
136
|
clearHiddenValues?: boolean;
|
|
137
|
+
/**
|
|
138
|
+
* Save answers as they go, off by default (Typeform's partial responses). When
|
|
139
|
+
* true, a host saves the answers so far each time the respondent moves on
|
|
140
|
+
* (genesis-forms-web's `onProgress`, with `formProgress` saying how far they
|
|
141
|
+
* got), so an unfinished response is kept even if they never submit. The form
|
|
142
|
+
* tells respondents so. Saving is the host's: the engine only says it's on.
|
|
143
|
+
*/
|
|
144
|
+
saveProgress?: boolean;
|
|
115
145
|
}
|
|
116
146
|
type FormLayout = {
|
|
117
147
|
mode: "classic";
|
|
@@ -152,4 +182,4 @@ type FormEvent = {
|
|
|
152
182
|
at?: number;
|
|
153
183
|
};
|
|
154
184
|
|
|
155
|
-
export type { Block as B, ContentBlock as C, Ending as E, FormDefinition as F, HiddenInput as H, Json as J, LogicRule as L,
|
|
185
|
+
export type { Block as B, ContentBlock as C, Ending as E, FormDefinition as F, HiddenInput as H, Json as J, LogicRule as L, OptionsSource as O, PageBreakBlock as P, FieldBlock as a, FormLayout as b, FormSettings as c, Condition as d, FormEvent as e, Operand as f, Operator as g };
|
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
import { J as Json, g as Operator, a as FieldBlock, B as Block, O as OptionsSource, F as FormDefinition, e as FormEvent } from './types-oAckGR_Z.cjs';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* A field type, without any UI. Renderers are registered separately per
|
|
5
|
+
* platform (`genesis-forms-react`), so a manifest runs anywhere.
|
|
6
|
+
*/
|
|
7
|
+
interface FieldTypeManifest {
|
|
8
|
+
type: string;
|
|
9
|
+
label: string;
|
|
10
|
+
category: "text" | "choice" | "scale" | "date" | "media" | "advanced";
|
|
11
|
+
/** `json: false` types must convert, so drafts and server replay never lose an answer. */
|
|
12
|
+
value: {
|
|
13
|
+
json: true;
|
|
14
|
+
} | {
|
|
15
|
+
json: false;
|
|
16
|
+
serialize: (value: unknown) => Json;
|
|
17
|
+
deserialize: (json: Json) => unknown;
|
|
18
|
+
};
|
|
19
|
+
operators: Operator[];
|
|
20
|
+
a11y: {
|
|
21
|
+
semantics: "control" | "group";
|
|
22
|
+
/** The HTML `autocomplete` token, such as `"email"` or `"tel"`. */
|
|
23
|
+
autocomplete?: string;
|
|
24
|
+
/** The HTML `inputmode` hint for on-screen keyboards, such as `"email"` or `"tel"`. */
|
|
25
|
+
inputMode?: "text" | "email" | "tel" | "numeric" | "decimal" | "url" | "search";
|
|
26
|
+
};
|
|
27
|
+
isEmpty?: (value: Json | undefined) => boolean;
|
|
28
|
+
/** Return an error message, or null when the (non-empty) value is valid. */
|
|
29
|
+
validate?: (value: Json, field: FieldBlock) => string | null;
|
|
30
|
+
/** Plain text for recall, exports and emails. */
|
|
31
|
+
summarize?: (value: Json, field: FieldBlock) => string;
|
|
32
|
+
/**
|
|
33
|
+
* The form a (valid, non-empty) value is stored in, such as an email
|
|
34
|
+
* without surrounding spaces. Applied by `engine.answers()` and the server.
|
|
35
|
+
*/
|
|
36
|
+
normalize?: (value: Json, field: FieldBlock) => Json;
|
|
37
|
+
/** Valid example answers, used by `coverage()` and other test tools to explore a path. */
|
|
38
|
+
samples?: (field: FieldBlock) => Json[];
|
|
39
|
+
}
|
|
40
|
+
declare function registerFieldType(manifest: FieldTypeManifest): void;
|
|
41
|
+
declare function getFieldType(type: string): FieldTypeManifest | undefined;
|
|
42
|
+
declare function listFieldTypes(): FieldTypeManifest[];
|
|
43
|
+
declare function isEmptyValue(value: Json | undefined, field?: FieldBlock): boolean;
|
|
44
|
+
/** A value in its stored form (see `FieldTypeManifest.normalize`). */
|
|
45
|
+
declare function normalizeValue(value: Json, field: FieldBlock): Json;
|
|
46
|
+
/** Whether a block holds personal or secret data: `sensitive: true`, or the `props.sensitive: true` alias. */
|
|
47
|
+
declare function isSensitive(block: Block): boolean;
|
|
48
|
+
declare function summarizeValue(value: Json | undefined, field: FieldBlock): string;
|
|
49
|
+
interface ChoiceOption {
|
|
50
|
+
value: string;
|
|
51
|
+
label?: string;
|
|
52
|
+
/** A muted line under the label, such as a location's address. At most `OPTION_LIMITS.description` characters. */
|
|
53
|
+
description?: string;
|
|
54
|
+
/** A small picture beside the label: an `https://` URL, at most `OPTION_LIMITS.image` characters. */
|
|
55
|
+
image?: string;
|
|
56
|
+
/**
|
|
57
|
+
* Facts about the option for filtering and recall, such as `{ location: ["cff", "cornerstone"] }`
|
|
58
|
+
* for a coach who works at two locations (see `props.optionsFrom.filter`). Names and values are
|
|
59
|
+
* text; a value is one text or a list of them.
|
|
60
|
+
*/
|
|
61
|
+
attributes?: Record<string, string | string[]>;
|
|
62
|
+
}
|
|
63
|
+
/** Bounds on an option's extra details. A longer or malformed detail is dropped when options are read. */
|
|
64
|
+
declare const OPTION_LIMITS: {
|
|
65
|
+
/** Characters in a description. */
|
|
66
|
+
readonly description: 500;
|
|
67
|
+
/** Characters in an image URL. */
|
|
68
|
+
readonly image: 2048;
|
|
69
|
+
/** Attributes on one option. */
|
|
70
|
+
readonly attributes: 20;
|
|
71
|
+
/** Characters in an attribute's name. */
|
|
72
|
+
readonly attributeName: 64;
|
|
73
|
+
/** Characters in one attribute value. */
|
|
74
|
+
readonly attributeValue: 200;
|
|
75
|
+
/** Values in one attribute's list. */
|
|
76
|
+
readonly attributeItems: 50;
|
|
77
|
+
};
|
|
78
|
+
/**
|
|
79
|
+
* Whether `url` is an `https://` link with a host and no spaces or control characters, within
|
|
80
|
+
* `OPTION_LIMITS.image`. A pattern rather than `new URL`, so it behaves the same in React Native.
|
|
81
|
+
*/
|
|
82
|
+
declare function isHttpsUrl(url: unknown): url is string;
|
|
83
|
+
/**
|
|
84
|
+
* An option from untrusted JSON (a definition, the host's list): its string `value`, and its
|
|
85
|
+
* `label`, `description`, `image` and `attributes` when each is well formed and within
|
|
86
|
+
* `OPTION_LIMITS`; anything else is left out. Null when there is no string value.
|
|
87
|
+
*/
|
|
88
|
+
declare function readOption(raw: unknown): ChoiceOption | null;
|
|
89
|
+
/** An option as JSON, with only the details it has. */
|
|
90
|
+
declare function optionJson(option: ChoiceOption): Json;
|
|
91
|
+
/** The longest answer an "Other" option takes. */
|
|
92
|
+
declare const OTHER_MAX_LENGTH = 200;
|
|
93
|
+
/**
|
|
94
|
+
* A choice question's "Other" option (`props.other: true` or `{ label }`): the respondent types
|
|
95
|
+
* their own answer, stored as the answer's value itself (single choice, dropdown) or as one more
|
|
96
|
+
* item (multiple choice). Null when the question has none.
|
|
97
|
+
*/
|
|
98
|
+
declare function otherOption(field: FieldBlock): {
|
|
99
|
+
label: string;
|
|
100
|
+
} | null;
|
|
101
|
+
/** Whether a value is a typed "Other" answer: text that isn't one of the question's options. */
|
|
102
|
+
declare function isOtherValue(field: FieldBlock, value: unknown): value is string;
|
|
103
|
+
declare function choiceOptions(field: FieldBlock): ChoiceOption[];
|
|
104
|
+
/**
|
|
105
|
+
* Option lists the app showing a form supplies, by key (`OptionsSource.key`):
|
|
106
|
+
* `{ coaches: [{ value: "8c1…", label: "Ada Lovelace" }] }`.
|
|
107
|
+
*/
|
|
108
|
+
type HostOptions = Readonly<Record<string, readonly ChoiceOption[]>>;
|
|
109
|
+
/**
|
|
110
|
+
* A choice field's `props.optionsFrom`, when it is a well-formed `{ source: "host", key }`, with its
|
|
111
|
+
* `filter` when that is well formed too (`{ attribute, field }`, both non-empty text).
|
|
112
|
+
*/
|
|
113
|
+
declare function optionsSource(field: FieldBlock): OptionsSource | undefined;
|
|
114
|
+
/**
|
|
115
|
+
* The definition with each `optionsFrom: { source: "host" }` field's options
|
|
116
|
+
* filled in from `hostOptions`: its own `props.options` first, then the host's
|
|
117
|
+
* list for its key (a value the field already has is not added twice). A key
|
|
118
|
+
* the host does not supply adds nothing, so the field offers its own options
|
|
119
|
+
* only. `createForm` and `validateSubmission` call it with their `hostOptions`,
|
|
120
|
+
* so a respondent sees, and a submit accepts, exactly these. Returns
|
|
121
|
+
* `definition` itself when no field takes options from the host.
|
|
122
|
+
*/
|
|
123
|
+
declare function withHostOptions(definition: FormDefinition, hostOptions: HostOptions | undefined): FormDefinition;
|
|
124
|
+
/** The optional words under the ends of a rating or NPS scale ("Poor", "Great"). */
|
|
125
|
+
declare function scaleLabels(field: FieldBlock): {
|
|
126
|
+
low?: string;
|
|
127
|
+
high?: string;
|
|
128
|
+
};
|
|
129
|
+
/** How a rating is drawn: `"numbers"` (default) or `"stars"`. */
|
|
130
|
+
declare function ratingDisplay(field: FieldBlock): "numbers" | "stars";
|
|
131
|
+
/** A `number` field's limits: `min`, `max` and `step` (each optional; `step` is above 0). */
|
|
132
|
+
declare function numberLimits(field: FieldBlock): {
|
|
133
|
+
min?: number;
|
|
134
|
+
max?: number;
|
|
135
|
+
step?: number;
|
|
136
|
+
};
|
|
137
|
+
/** `YYYY-MM-DD`, a real calendar day (no 2026-02-30), years 0001 to 9999. */
|
|
138
|
+
declare function isIsoDate(value: string): boolean;
|
|
139
|
+
/** A `date` field's earliest and latest days (`YYYY-MM-DD`), when set. */
|
|
140
|
+
declare function dateLimits(field: FieldBlock): {
|
|
141
|
+
min?: string;
|
|
142
|
+
max?: string;
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Which options a choice question shows, and how they are picked: lists filtered by another
|
|
147
|
+
* answer, search for long lists, preselecting from a link, and snapshots of what was picked.
|
|
148
|
+
* Pure and renderer-agnostic, so the engine, the server and every renderer (web and native)
|
|
149
|
+
* decide the same way.
|
|
150
|
+
*/
|
|
151
|
+
|
|
152
|
+
/** Field types whose answer is one or more of their options. */
|
|
153
|
+
declare const CHOICE_FIELD_TYPES: ReadonlySet<string>;
|
|
154
|
+
/** A choice field's `props.optionsFrom.filter` (`{ attribute, field }`), when it is well formed. */
|
|
155
|
+
declare function optionFilter(field: FieldBlock): {
|
|
156
|
+
attribute: string;
|
|
157
|
+
field: string;
|
|
158
|
+
} | undefined;
|
|
159
|
+
/**
|
|
160
|
+
* Whether an option matches an answer on one attribute: its `attributes[attribute]` (a text or a
|
|
161
|
+
* list) shares a value with the answer (a text, or a list from a multiple choice). An option
|
|
162
|
+
* without the attribute matches nothing.
|
|
163
|
+
*/
|
|
164
|
+
declare function optionMatches(option: ChoiceOption, attribute: string, answer: Json | undefined): boolean;
|
|
165
|
+
/**
|
|
166
|
+
* The options a choice question shows given the answers so far (`values`, keyed by field id, as
|
|
167
|
+
* in `FormState.values`): all of `choiceOptions(field)`, or, with `props.optionsFrom.filter`,
|
|
168
|
+
* only those matching the filtered-by question's answer (`optionMatches`). While that question is
|
|
169
|
+
* unanswered (or isn't in the form) every option shows. Pass the definition with the host's lists
|
|
170
|
+
* filled in (`engine.definition`, or `withHostOptions`).
|
|
171
|
+
*/
|
|
172
|
+
declare function visibleOptions(definition: FormDefinition, field: FieldBlock, values: Readonly<Record<string, Json | undefined>>): ChoiceOption[];
|
|
173
|
+
/**
|
|
174
|
+
* The answers on the respondent's path, by field id: what a filter reads. An answer to a question
|
|
175
|
+
* off the path (hidden by logic, jumped over) counts as none, as it does for logic. Pass these to
|
|
176
|
+
* `visibleOptions` from a renderer, so it shows exactly what the engine accepts.
|
|
177
|
+
*/
|
|
178
|
+
declare function answersOnPath(state: {
|
|
179
|
+
path: readonly string[];
|
|
180
|
+
values: Readonly<Record<string, Json | undefined>>;
|
|
181
|
+
}): Record<string, Json | undefined>;
|
|
182
|
+
/**
|
|
183
|
+
* Null, or the error for a (non-empty) choice answer that is one of the question's options but
|
|
184
|
+
* not one it shows now because of its filter (`visibleOptions`). A typed "Other" answer is left
|
|
185
|
+
* to the field type's own check. The engine and `validateSubmission` both call it, so a value
|
|
186
|
+
* outside the filtered list is refused on the server too.
|
|
187
|
+
*/
|
|
188
|
+
declare function filteredChoiceError(definition: FormDefinition, field: FieldBlock, value: Json | undefined, values: Readonly<Record<string, Json | undefined>>): string | null;
|
|
189
|
+
/** Whether any choice question in the definition filters its options by another answer. */
|
|
190
|
+
declare function hasOptionFilters(definition: FormDefinition): boolean;
|
|
191
|
+
/**
|
|
192
|
+
* `values` after the answer to `changedId` changed, with every choice its filter no longer
|
|
193
|
+
* shows taken out: a single choice or dropdown is cleared, a multiple choice keeps the options
|
|
194
|
+
* that still show (and a typed "Other" answer). It follows on: clearing one question clears what
|
|
195
|
+
* was filtered by it. Returns `values` itself when nothing is cleared. The engine calls it on
|
|
196
|
+
* every answer, so a pick never outlives the answer it depended on.
|
|
197
|
+
*/
|
|
198
|
+
declare function clearFilteredAnswers(definition: FormDefinition, values: Record<string, Json | undefined>, changedId: string): Record<string, Json | undefined>;
|
|
199
|
+
/** A choice question with more options than this gets a search box, unless `props.searchable` says otherwise. */
|
|
200
|
+
declare const SEARCHABLE_OPTION_COUNT = 10;
|
|
201
|
+
/**
|
|
202
|
+
* Whether a choice question shows a search box over its options: `props.searchable` when it is
|
|
203
|
+
* true or false, otherwise when it has more than `SEARCHABLE_OPTION_COUNT` options. The default
|
|
204
|
+
* counts all its options (`choiceOptions(field)`, with the host's lists filled in), so a list a
|
|
205
|
+
* filter narrows keeps its search box while the respondent answers.
|
|
206
|
+
*/
|
|
207
|
+
declare function isSearchable(field: FieldBlock, optionCount?: number): boolean;
|
|
208
|
+
/**
|
|
209
|
+
* The options that match what the respondent typed, in their order: every word of `query` is
|
|
210
|
+
* found (ignoring case and accents) in the option's label, value or description. A blank query
|
|
211
|
+
* matches every option.
|
|
212
|
+
*/
|
|
213
|
+
declare function searchOptions(options: readonly ChoiceOption[], query: string): ChoiceOption[];
|
|
214
|
+
/** Characters in a link parameter's name. */
|
|
215
|
+
declare const MAX_PREFILL_PARAM_LENGTH = 64;
|
|
216
|
+
/** A choice question's `props.prefill`: the link parameter that preselects it, and whether it is then hidden. */
|
|
217
|
+
interface PrefillSetting {
|
|
218
|
+
/** The query parameter, as in `?location=cornerstone`. */
|
|
219
|
+
param: string;
|
|
220
|
+
/** Skip the question while the link has filled it in. */
|
|
221
|
+
hideWhenPrefilled: boolean;
|
|
222
|
+
}
|
|
223
|
+
/** A well-formed parameter name: letters, digits, `_`, `-` and `.`, at most `MAX_PREFILL_PARAM_LENGTH`. */
|
|
224
|
+
declare function isPrefillParam(param: unknown): param is string;
|
|
225
|
+
/** A choice field's `props.prefill` (`{ param, hideWhenPrefilled? }`), when it is well formed. */
|
|
226
|
+
declare function prefillSetting(field: FieldBlock): PrefillSetting | undefined;
|
|
227
|
+
/**
|
|
228
|
+
* A link's query parameters: a `URLSearchParams` (or anything with `getAll`), or a plain record
|
|
229
|
+
* of a text or a list of texts per name.
|
|
230
|
+
*/
|
|
231
|
+
type LinkParams = {
|
|
232
|
+
getAll(name: string): string[];
|
|
233
|
+
} | Readonly<Record<string, string | readonly string[] | undefined>>;
|
|
234
|
+
/**
|
|
235
|
+
* Answers a link preselects, by field id, for `createForm`'s `initialValues` (its `linkParams`
|
|
236
|
+
* option calls this). Each choice question with `props.prefill: { param }` takes the parameter's
|
|
237
|
+
* value when it is one of the options the question shows (`visibleOptions`, so a filtered list is
|
|
238
|
+
* respected); anything else is ignored. A multiple choice takes every matching value, from
|
|
239
|
+
* repeated parameters (`?coach=a&coach=b`) or one comma-separated value. Questions are filled in
|
|
240
|
+
* form order, so a filtered question sees what the link picked before it. A question `values`
|
|
241
|
+
* already answers (the host's own prefill) is left alone. The server checks these like any answer.
|
|
242
|
+
*/
|
|
243
|
+
declare function prefillFromLink(definition: FormDefinition, params: LinkParams | undefined, values?: Readonly<Record<string, Json | undefined>>): Record<string, Json>;
|
|
244
|
+
/** The parts of a form's state `hiddenByPrefill` reads (a `FormState` has them all). */
|
|
245
|
+
interface PrefillState {
|
|
246
|
+
path: readonly string[];
|
|
247
|
+
values: Readonly<Record<string, Json | undefined>>;
|
|
248
|
+
errors: Readonly<Record<string, string>>;
|
|
249
|
+
events: readonly FormEvent[];
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* Questions on the path the respondent skips because a prefill answered them: those with
|
|
253
|
+
* `props.prefill.hideWhenPrefilled` whose answer is still the prefilled one (the last answer
|
|
254
|
+
* event for them came from `initialValues` or a link) and has no error. The engine steps over
|
|
255
|
+
* them and renderers leave them out; their answers are stored like any other. A question shows
|
|
256
|
+
* again once its answer is cleared or changed (by a filter, say).
|
|
257
|
+
*/
|
|
258
|
+
declare function hiddenByPrefill(definition: FormDefinition, state: PrefillState): string[];
|
|
259
|
+
/** The blocks the respondent steps through: the path without the questions a prefill hides (`hiddenByPrefill`). */
|
|
260
|
+
declare function respondentPath(definition: FormDefinition, state: PrefillState): string[];
|
|
261
|
+
/** One picked option as it was when the response was stored: its value (an id) and its label then. */
|
|
262
|
+
interface OptionSnapshot {
|
|
263
|
+
value: string;
|
|
264
|
+
label: string;
|
|
265
|
+
/** A typed "Other" answer rather than one of the options. */
|
|
266
|
+
other?: true;
|
|
267
|
+
}
|
|
268
|
+
/** A choice answer's snapshot: one pick (single choice, dropdown) or a list (multiple choice). */
|
|
269
|
+
type AnswerSnapshot = OptionSnapshot | OptionSnapshot[];
|
|
270
|
+
/**
|
|
271
|
+
* Each answer to a choice question that takes options from the app (`props.optionsFrom`), as
|
|
272
|
+
* `{ value, label }` pairs as of now, by field id: store them beside the answers so reports
|
|
273
|
+
* group by the value (an id) while history keeps the name it had then. Pass the definition with
|
|
274
|
+
* the host's lists filled in (`withHostOptions`, or `engine.definition`) and the checked
|
|
275
|
+
* answers (`validateSubmission`'s `submission.answers`). A value that isn't one of the options
|
|
276
|
+
* keeps itself as its label, marked `other` (a typed "Other" answer).
|
|
277
|
+
*/
|
|
278
|
+
declare function answerSnapshots(definition: FormDefinition, answers: Readonly<Record<string, Json | undefined>>): Record<string, AnswerSnapshot>;
|
|
279
|
+
/** What `answersFromSnapshots` found again. */
|
|
280
|
+
interface RestoredAnswers {
|
|
281
|
+
/** Answers by field id, for `initialValues`: each pick's current value. */
|
|
282
|
+
answers: Record<string, Json>;
|
|
283
|
+
/** Picks no longer offered, by field id: the option was removed and no option has its label now. */
|
|
284
|
+
missing: Record<string, OptionSnapshot[]>;
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
287
|
+
* The reverse of `answerSnapshots`, for an edit link: the answers to prefill from stored
|
|
288
|
+
* snapshots. A pick whose value is still an option keeps it; otherwise an option with the same
|
|
289
|
+
* label (ignoring case and accents) stands in, such as a location deleted and added again; a
|
|
290
|
+
* typed "Other" answer stays one when the question still allows it. Anything else is reported
|
|
291
|
+
* in `missing` and left out. Pass the definition with the host's current lists filled in.
|
|
292
|
+
*/
|
|
293
|
+
declare function answersFromSnapshots(definition: FormDefinition, snapshots: Readonly<Record<string, unknown>>): RestoredAnswers;
|
|
294
|
+
|
|
295
|
+
/** The Standard Schema interface (standardschema.dev), as far as validation needs it. */
|
|
296
|
+
interface StandardSchemaV1<T = unknown> {
|
|
297
|
+
readonly "~standard": {
|
|
298
|
+
readonly version: 1;
|
|
299
|
+
readonly vendor: string;
|
|
300
|
+
readonly validate: (value: unknown) => {
|
|
301
|
+
value: T;
|
|
302
|
+
issues?: undefined;
|
|
303
|
+
} | {
|
|
304
|
+
issues: ReadonlyArray<{
|
|
305
|
+
message: string;
|
|
306
|
+
}>;
|
|
307
|
+
} | Promise<unknown>;
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
/** A custom check for one field: a function, or any Standard Schema (Zod, Valibot, ArkType…). */
|
|
311
|
+
type FieldValidator = ((value: Json) => string | null) | StandardSchemaV1;
|
|
312
|
+
declare const REQUIRED_MESSAGE = "This question needs an answer.";
|
|
313
|
+
/**
|
|
314
|
+
* Validate one field's value. `requireAnswers: false` (drafts) checks the
|
|
315
|
+
* format of what was answered without requiring the rest.
|
|
316
|
+
*/
|
|
317
|
+
declare function validateField(field: FieldBlock, value: Json | undefined, options?: {
|
|
318
|
+
requireAnswers?: boolean;
|
|
319
|
+
custom?: FieldValidator;
|
|
320
|
+
}): string | null;
|
|
321
|
+
|
|
322
|
+
export { withHostOptions as $, type AnswerSnapshot as A, numberLimits as B, CHOICE_FIELD_TYPES as C, optionFilter as D, optionJson as E, type FieldValidator as F, optionMatches as G, type HostOptions as H, optionsSource as I, otherOption as J, prefillFromLink as K, type LinkParams as L, MAX_PREFILL_PARAM_LENGTH as M, prefillSetting as N, OPTION_LIMITS as O, type PrefillSetting as P, ratingDisplay as Q, REQUIRED_MESSAGE as R, SEARCHABLE_OPTION_COUNT as S, readOption as T, registerFieldType as U, respondentPath as V, scaleLabels as W, searchOptions as X, summarizeValue as Y, validateField as Z, visibleOptions as _, type ChoiceOption as a, type FieldTypeManifest as b, OTHER_MAX_LENGTH as c, type OptionSnapshot as d, type PrefillState as e, type RestoredAnswers as f, type StandardSchemaV1 as g, answerSnapshots as h, answersFromSnapshots as i, answersOnPath as j, choiceOptions as k, clearFilteredAnswers as l, dateLimits as m, filteredChoiceError as n, getFieldType as o, hasOptionFilters as p, hiddenByPrefill as q, isEmptyValue as r, isHttpsUrl as s, isIsoDate as t, isOtherValue as u, isPrefillParam as v, isSearchable as w, isSensitive as x, listFieldTypes as y, normalizeValue as z };
|