@samline/forms 2.4.0 → 2.7.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/LICENSE +21 -0
- package/README.md +11 -8
- package/dist/browser/global.d.ts +28 -18
- package/dist/browser/global.global.js +477 -66
- package/dist/browser/global.global.js.map +1 -1
- package/dist/browser/index.cjs +1450 -0
- package/dist/browser/index.cjs.map +1 -0
- package/dist/browser/index.d.cts +14 -0
- package/dist/browser/index.d.ts +14 -0
- package/dist/browser/index.js +23 -0
- package/dist/browser/index.js.map +1 -0
- package/dist/chunk-WGPAVJTK.js +1415 -0
- package/dist/chunk-WGPAVJTK.js.map +1 -0
- package/dist/index.cjs +296 -40
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -158
- package/dist/index.d.ts +4 -158
- package/dist/index.js +7 -1148
- package/dist/index.js.map +1 -1
- package/dist/registry-GzopYPCR.d.cts +164 -0
- package/dist/registry-GzopYPCR.d.ts +164 -0
- package/docs/api/add-cleanup.md +52 -0
- package/docs/api/append.md +96 -0
- package/docs/api/auto-submit.md +91 -0
- package/docs/api/clear-errors.md +69 -0
- package/docs/api/destroy.md +80 -0
- package/docs/api/disable-auto-submit.md +65 -0
- package/docs/api/element.md +78 -0
- package/docs/api/form.md +156 -0
- package/docs/api/format.md +270 -0
- package/docs/api/get-data.md +90 -0
- package/docs/api/get-field.md +87 -0
- package/docs/api/get-state.md +111 -0
- package/docs/api/get-value.md +114 -0
- package/docs/api/index.md +55 -0
- package/docs/api/observe.md +126 -0
- package/docs/api/on-submit.md +94 -0
- package/docs/api/parse-form-data.md +94 -0
- package/docs/api/prefill.md +89 -0
- package/docs/api/regex.md +155 -0
- package/docs/api/reset.md +61 -0
- package/docs/api/revalidate.md +52 -0
- package/docs/api/set-errors.md +97 -0
- package/docs/api/set-value.md +120 -0
- package/docs/api/subscribe.md +107 -0
- package/docs/api/unwatch.md +74 -0
- package/docs/api/validate-field-value.md +144 -0
- package/docs/api/validate-values.md +103 -0
- package/docs/api/validate.md +102 -0
- package/docs/api/watch.md +117 -0
- package/docs/browser.md +156 -0
- package/docs/css-styling.md +191 -0
- package/docs/getting-started.md +222 -0
- package/docs/options.md +326 -0
- package/docs/recipes.md +530 -0
- package/docs/typescript.md +615 -0
- package/docs/vanilla.md +12 -0
- package/package.json +58 -14
|
@@ -0,0 +1,615 @@
|
|
|
1
|
+
# TypeScript Reference
|
|
2
|
+
|
|
3
|
+
This page lists every type exported from `@samline/forms`, what it represents, and where it shows up. Each type links to the method(s) that consume or produce it.
|
|
4
|
+
|
|
5
|
+
All types are exported from the package root:
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
import type {
|
|
9
|
+
AppendContentOptions,
|
|
10
|
+
AutoSubmitOptions,
|
|
11
|
+
FieldFormatConfig,
|
|
12
|
+
FieldFormatConfigMap,
|
|
13
|
+
FieldValidationContext,
|
|
14
|
+
FieldValidationRules,
|
|
15
|
+
FieldValidator,
|
|
16
|
+
FormatType,
|
|
17
|
+
FormController,
|
|
18
|
+
FormControllerOptions,
|
|
19
|
+
FormCleanup,
|
|
20
|
+
FormDataPrimitive,
|
|
21
|
+
FormErrors,
|
|
22
|
+
FormFieldElement,
|
|
23
|
+
FormFieldValue,
|
|
24
|
+
FormFieldWatcher,
|
|
25
|
+
FormsApi,
|
|
26
|
+
FormsAvailable,
|
|
27
|
+
FormStateListener,
|
|
28
|
+
FormStateSnapshot,
|
|
29
|
+
FormSubmitHandler,
|
|
30
|
+
FormTarget,
|
|
31
|
+
FormValues,
|
|
32
|
+
NewFormInput,
|
|
33
|
+
RuleConfig,
|
|
34
|
+
SerializedFormResult,
|
|
35
|
+
SerializedFormValue,
|
|
36
|
+
ValidationResult,
|
|
37
|
+
ValidationSchema,
|
|
38
|
+
ValueValidationRules,
|
|
39
|
+
VisualAttributes
|
|
40
|
+
} from '@samline/forms'
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## `FormController`
|
|
46
|
+
|
|
47
|
+
The full controller surface returned by [`form()`](api/form.md). All public methods are defined here.
|
|
48
|
+
|
|
49
|
+
```ts
|
|
50
|
+
interface FormController {
|
|
51
|
+
readonly element: HTMLFormElement | null
|
|
52
|
+
readonly f: HTMLFormElement | null
|
|
53
|
+
readonly options: FormControllerOptions
|
|
54
|
+
onSubmit: (callback: FormSubmitHandler, preventDefault?: boolean) => FormController
|
|
55
|
+
addCleanup: (cleanup: FormCleanup) => () => void
|
|
56
|
+
watch: (field: string, callback: FormFieldWatcher) => FormController
|
|
57
|
+
observe: (field: string, callback: FormFieldWatcher) => () => void
|
|
58
|
+
unwatch: (field?: string, callback?: FormFieldWatcher) => FormController
|
|
59
|
+
subscribe: (listener: FormStateListener) => () => void
|
|
60
|
+
prefill: (fieldName?: string) => FormController
|
|
61
|
+
append: (options: AppendContentOptions) => HTMLElement | null
|
|
62
|
+
setErrors: (fields: string[] | FormErrors) => FormController
|
|
63
|
+
clearErrors: (fields?: string[]) => FormController
|
|
64
|
+
setValue: (name: string, value: unknown) => FormController
|
|
65
|
+
validate: (fields?: string[]) => ValidationResult
|
|
66
|
+
revalidate: (fields?: string[]) => ValidationResult
|
|
67
|
+
/**
|
|
68
|
+
* Apply the same `@samline/formatter` pipeline to a single field or
|
|
69
|
+
* to a list of fields sharing one configuration. Chainable.
|
|
70
|
+
*
|
|
71
|
+
* Requires the optional peer dependency `@samline/formatter`. When
|
|
72
|
+
* the peer is not installed the call logs a single `console.error`
|
|
73
|
+
* and returns the controller unchanged.
|
|
74
|
+
*/
|
|
75
|
+
format: (config: FieldFormatConfig) => FormController
|
|
76
|
+
formatAll: (config: FieldFormatConfig) => FormController
|
|
77
|
+
reset: () => FormController
|
|
78
|
+
autoSubmit: (options?: boolean | AutoSubmitOptions) => FormController
|
|
79
|
+
disableAutoSubmit: () => FormController
|
|
80
|
+
getValue: (name: string) => FormFieldValue
|
|
81
|
+
getField: (name: string) => FormFieldElement | FormFieldElement[] | null
|
|
82
|
+
getData: () => SerializedFormResult
|
|
83
|
+
getState: () => FormStateSnapshot
|
|
84
|
+
destroy: () => void
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
## `FormControllerOptions`
|
|
91
|
+
|
|
92
|
+
The second argument to [`form()`](api/form.md). See [docs/options.md](options.md) for the full reference.
|
|
93
|
+
|
|
94
|
+
```ts
|
|
95
|
+
interface FormControllerOptions {
|
|
96
|
+
attributes?: Partial<VisualAttributes>
|
|
97
|
+
autoValidate?: boolean
|
|
98
|
+
autoSubmit?: boolean | AutoSubmitOptions
|
|
99
|
+
clearManualErrorsOnChange?: boolean
|
|
100
|
+
clearErrorsOnSubmit?: boolean
|
|
101
|
+
validators?: ValidationSchema
|
|
102
|
+
/**
|
|
103
|
+
* Declarative format configuration. Each entry is applied during
|
|
104
|
+
* `form()` initialization using the same logic as `controller.format(...)`.
|
|
105
|
+
* The key is just an identifier — the canonical field name lives in
|
|
106
|
+
* `FieldFormatConfig.field`.
|
|
107
|
+
*/
|
|
108
|
+
formats?: FieldFormatConfigMap
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
## `FormTarget`
|
|
115
|
+
|
|
116
|
+
What [`form()`](api/form.md) accepts as its first argument.
|
|
117
|
+
|
|
118
|
+
```ts
|
|
119
|
+
type FormTarget =
|
|
120
|
+
| string // element id
|
|
121
|
+
| HTMLFormElement // direct element
|
|
122
|
+
| { current: HTMLFormElement | null } // ref-like
|
|
123
|
+
| null
|
|
124
|
+
| undefined
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
A string is treated as a `document.getElementById(id)` lookup; only `HTMLFormElement` matches count. A ref-like value lets you pass a Vue/React-style ref object.
|
|
128
|
+
|
|
129
|
+
---
|
|
130
|
+
|
|
131
|
+
## `FormFieldElement`
|
|
132
|
+
|
|
133
|
+
The set of DOM field types the controller manages.
|
|
134
|
+
|
|
135
|
+
```ts
|
|
136
|
+
type FormFieldElement =
|
|
137
|
+
| HTMLInputElement
|
|
138
|
+
| HTMLSelectElement
|
|
139
|
+
| HTMLTextAreaElement
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Returned by [`getField`](api/get-field.md).
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
## `FormFieldValue`
|
|
147
|
+
|
|
148
|
+
The normalized value of a field.
|
|
149
|
+
|
|
150
|
+
```ts
|
|
151
|
+
type FormFieldValue = string | string[] | File[] | undefined
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
- `string` — for text inputs, textareas, single selects, and single checked checkboxes / radios.
|
|
155
|
+
- `string[]` — for checkbox groups, multiple selects, and repeated `name="field[]"` controls. Radio groups remain scalar.
|
|
156
|
+
- `File[]` — for `<input type="file">` (may be empty).
|
|
157
|
+
- `undefined` — when no field with that name exists.
|
|
158
|
+
|
|
159
|
+
Returned by [`getValue`](api/get-value.md).
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
## `FormValues`
|
|
164
|
+
|
|
165
|
+
The aggregated values map produced by the controller and the helpers.
|
|
166
|
+
|
|
167
|
+
```ts
|
|
168
|
+
type FormValues = Record<string, FormFieldValue>
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
Useful when you build custom validators that need cross-field logic beyond exact equality (`sameAs` handles equality directly):
|
|
172
|
+
|
|
173
|
+
```ts
|
|
174
|
+
form('booking-form', {
|
|
175
|
+
validators: {
|
|
176
|
+
end_date: {
|
|
177
|
+
validate: ({ value, values }) =>
|
|
178
|
+
typeof value === 'string' &&
|
|
179
|
+
typeof values.start_date === 'string' &&
|
|
180
|
+
value >= values.start_date
|
|
181
|
+
? null
|
|
182
|
+
: 'End date must not precede start date.'
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
})
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
The controller infers reactive dependencies from `sameAs`, but not from arbitrary reads inside `validate`. Add `dependsOn: 'start_date'` to the `end_date` rules when changes to the source should automatically revalidate the custom rule.
|
|
189
|
+
|
|
190
|
+
---
|
|
191
|
+
|
|
192
|
+
## `FormErrors`
|
|
193
|
+
|
|
194
|
+
A map from field name to an array of error messages. Each field can have multiple errors (one per failed rule or per failing custom validator).
|
|
195
|
+
|
|
196
|
+
```ts
|
|
197
|
+
type FormErrors = Record<string, string[]>
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
Drives the `css-error` attribute on fields and is returned inside [`FormStateSnapshot`](#formstatesnapshot) and [`ValidationResult`](#validationresult).
|
|
201
|
+
|
|
202
|
+
---
|
|
203
|
+
|
|
204
|
+
## `FormStateSnapshot`
|
|
205
|
+
|
|
206
|
+
The shape returned by [`getState()`](api/get-state.md). Built fresh on every call — it does not retain references to controller internals.
|
|
207
|
+
|
|
208
|
+
```ts
|
|
209
|
+
interface FormStateSnapshot {
|
|
210
|
+
values: FormValues
|
|
211
|
+
errors: FormErrors
|
|
212
|
+
filledFields: string[]
|
|
213
|
+
isValid: boolean
|
|
214
|
+
isValidated: boolean
|
|
215
|
+
autoSubmit: boolean
|
|
216
|
+
isSubmitting: boolean
|
|
217
|
+
submitCount: number
|
|
218
|
+
}
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
| Field | Meaning |
|
|
222
|
+
| --- | --- |
|
|
223
|
+
| `values` | Current values for every tracked field. |
|
|
224
|
+
| `errors` | Merged validation and manual errors. |
|
|
225
|
+
| `filledFields` | Names of fields that have a non-empty value. |
|
|
226
|
+
| `isValid` | `true` when `errors` has no entries. |
|
|
227
|
+
| `isValidated` | `true` after the initial auto-validation pass or once [`validate`](api/validate.md) has run. |
|
|
228
|
+
| `autoSubmit` | `true` while auto-submit is enabled. |
|
|
229
|
+
| `isSubmitting` | `true` while one or more valid submissions have asynchronous handlers that have not settled. |
|
|
230
|
+
| `submitCount` | Number of submit attempts (valid or invalid). |
|
|
231
|
+
|
|
232
|
+
---
|
|
233
|
+
|
|
234
|
+
## `FormStateListener`
|
|
235
|
+
|
|
236
|
+
The callback passed to [`subscribe`](api/subscribe.md).
|
|
237
|
+
|
|
238
|
+
```ts
|
|
239
|
+
type FormStateListener = (state: FormStateSnapshot) => void
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
Receives the current snapshot immediately, then at controller notification points such as handled input, manual-error changes, reset, submit attempts, async-submit state transitions, auto-submit toggles, and observed DOM mutations. A direct `validate()` call does not independently notify it.
|
|
243
|
+
|
|
244
|
+
---
|
|
245
|
+
|
|
246
|
+
## `FormSubmitHandler`
|
|
247
|
+
|
|
248
|
+
The callback passed to [`onSubmit`](api/on-submit.md).
|
|
249
|
+
|
|
250
|
+
```ts
|
|
251
|
+
type FormSubmitHandler = (
|
|
252
|
+
form: HTMLFormElement,
|
|
253
|
+
data: Record<string, SerializedFormValue>,
|
|
254
|
+
formData: FormData,
|
|
255
|
+
state: FormStateSnapshot
|
|
256
|
+
) => void | Promise<void>
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
Only invoked when the form is valid. `data` and `formData` are produced fresh on each invocation. Returned promises are tracked by `FormStateSnapshot.isSubmitting`; fulfillment or rejection settles the tracked work.
|
|
260
|
+
|
|
261
|
+
---
|
|
262
|
+
|
|
263
|
+
## `FormFieldWatcher`
|
|
264
|
+
|
|
265
|
+
The callback passed to [`watch`](api/watch.md) and [`observe`](api/observe.md).
|
|
266
|
+
|
|
267
|
+
```ts
|
|
268
|
+
type FormFieldWatcher = (
|
|
269
|
+
value: FormFieldValue,
|
|
270
|
+
field: FormFieldElement | FormFieldElement[] | null,
|
|
271
|
+
form: HTMLFormElement,
|
|
272
|
+
state: FormStateSnapshot
|
|
273
|
+
) => void
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
- `value` — the current value of the field that just changed.
|
|
277
|
+
- `field` — the DOM element(s) backing the field (same shape as [`getField`](api/get-field.md) returns). For a single matching field it is `HTMLInputElement` / `HTMLSelectElement` / `HTMLTextAreaElement`; for repeated fields (e.g. checkbox / radio groups) it is an array of them; it is `null` when no element matches the name.
|
|
278
|
+
- `form` — the bound `HTMLFormElement`.
|
|
279
|
+
- `state` — a snapshot of the whole controller state (see [`FormStateSnapshot`](#formstatesnapshot)).
|
|
280
|
+
|
|
281
|
+
`observe` and `watch` fire once immediately with the current value, then on every matching `input` event. `observe` returns an unsubscribe function; `watch` returns the controller.
|
|
282
|
+
|
|
283
|
+
---
|
|
284
|
+
|
|
285
|
+
## `SerializedFormResult`
|
|
286
|
+
|
|
287
|
+
The shape returned by [`getData()`](api/get-data.md) and [`parseFormData()`](api/parse-form-data.md).
|
|
288
|
+
|
|
289
|
+
```ts
|
|
290
|
+
interface SerializedFormResult {
|
|
291
|
+
data: Record<string, SerializedFormValue>
|
|
292
|
+
formData: FormData
|
|
293
|
+
}
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
`data` is a plain object mirror of the `FormData`. Repeated names become arrays (e.g. `interests: ['design', 'code']`). Empty file entries are filtered out.
|
|
297
|
+
|
|
298
|
+
---
|
|
299
|
+
|
|
300
|
+
## `SerializedFormValue`
|
|
301
|
+
|
|
302
|
+
The value shape inside `SerializedFormResult.data`.
|
|
303
|
+
|
|
304
|
+
```ts
|
|
305
|
+
type SerializedFormValue = FormDataPrimitive | FormDataPrimitive[]
|
|
306
|
+
|
|
307
|
+
type FormDataPrimitive = FormDataEntryValue
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
`FormDataEntryValue` is `string | File` in the DOM lib types.
|
|
311
|
+
|
|
312
|
+
---
|
|
313
|
+
|
|
314
|
+
## `ValidationResult`
|
|
315
|
+
|
|
316
|
+
The shape returned by [`validate`](api/validate.md), [`revalidate`](api/revalidate.md), and [`validateValues`](api/validate-values.md).
|
|
317
|
+
|
|
318
|
+
```ts
|
|
319
|
+
interface ValidationResult {
|
|
320
|
+
isValid: boolean
|
|
321
|
+
errors: FormErrors
|
|
322
|
+
}
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
`errors` is always a fresh object — safe to mutate.
|
|
326
|
+
|
|
327
|
+
---
|
|
328
|
+
|
|
329
|
+
## `ValidationSchema`
|
|
330
|
+
|
|
331
|
+
The shape of `options.validators`.
|
|
332
|
+
|
|
333
|
+
```ts
|
|
334
|
+
type ValidationSchema = Record<string, FieldValidationRules>
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
```ts
|
|
338
|
+
form('signup-form', {
|
|
339
|
+
validators: {
|
|
340
|
+
email: { required: true, pattern: /^[^\s@]+@[^\s@]+\.[^\s@]+$/ },
|
|
341
|
+
password: { required: true, minLength: 8 }
|
|
342
|
+
}
|
|
343
|
+
})
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
---
|
|
347
|
+
|
|
348
|
+
## `FieldValidationRules`
|
|
349
|
+
|
|
350
|
+
The rule set for a single field.
|
|
351
|
+
|
|
352
|
+
```ts
|
|
353
|
+
interface FieldValidationRules extends ValueValidationRules {
|
|
354
|
+
sameAs?: RuleConfig<string>
|
|
355
|
+
dependsOn?: string | string[]
|
|
356
|
+
each?: ValueValidationRules
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
interface ValueValidationRules {
|
|
360
|
+
required?: RuleConfig<boolean>
|
|
361
|
+
minLength?: RuleConfig<number>
|
|
362
|
+
maxLength?: RuleConfig<number>
|
|
363
|
+
pattern?: RuleConfig<RegExp>
|
|
364
|
+
numeric?: RuleConfig<boolean>
|
|
365
|
+
min?: RuleConfig<number>
|
|
366
|
+
max?: RuleConfig<number>
|
|
367
|
+
validate?: FieldValidator | FieldValidator[]
|
|
368
|
+
}
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
Value rules run in the order: `required` → `minLength` → `maxLength` → `pattern` → numeric bounds → `validate`. Field-level `sameAs` and member-level `each` are then evaluated. All are optional; an empty rules object contributes nothing.
|
|
372
|
+
|
|
373
|
+
`sameAs` names another exact field key. It compares non-empty strings exactly and arrays by ordered contents; file entries compare by `File` object identity. In a controller, changing the referenced field automatically revalidates the field that declares `sameAs`. Reciprocal declarations are cycle-safe, but usually duplicate the same error on both controls; prefer declaring the rule only on the confirmation field.
|
|
374
|
+
|
|
375
|
+
`dependsOn` declares one or more exact source field names for controller revalidation. It is intended for custom validators that read `values`; it does not add an error or affect the pure helpers by itself. Dependency chains and cycles are traversed once per input event.
|
|
376
|
+
|
|
377
|
+
`each` applies a `ValueValidationRules` object to every collection member independently. Controller validation can therefore mark only the failing DOM controls, while [`FormErrors`](#formerrors) remains a flat `Record<string, string[]>` with item messages collected under the field name.
|
|
378
|
+
|
|
379
|
+
## `ValueValidationRules`
|
|
380
|
+
|
|
381
|
+
The exported subset of rules that can validate one value, including each member of a collection. It excludes field-level `sameAs`, `dependsOn`, and nested `each`.
|
|
382
|
+
|
|
383
|
+
`numeric`, `min`, and `max` skip empty values. Non-empty input must be a finite ordinary signed decimal: decimal integers and fractions are accepted, while exponent notation, hexadecimal, `Infinity`, `NaN`, and formatted separators are rejected. `min` and `max` are inclusive and imply numeric parsing even when `numeric` is omitted.
|
|
384
|
+
|
|
385
|
+
---
|
|
386
|
+
|
|
387
|
+
## `RuleConfig<T>`
|
|
388
|
+
|
|
389
|
+
Lets a rule be configured with a plain value or a `{ value, message }` object.
|
|
390
|
+
|
|
391
|
+
```ts
|
|
392
|
+
type RuleConfig<T> = T | { value: T; message?: string }
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
```ts
|
|
396
|
+
form('signup-form', {
|
|
397
|
+
validators: {
|
|
398
|
+
password: {
|
|
399
|
+
minLength: { value: 8, message: 'Use at least 8 characters.' }
|
|
400
|
+
},
|
|
401
|
+
terms: {
|
|
402
|
+
required: { value: true, message: 'Please accept the terms.' }
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
})
|
|
406
|
+
```
|
|
407
|
+
|
|
408
|
+
When the plain form is used, default messages are produced automatically.
|
|
409
|
+
|
|
410
|
+
---
|
|
411
|
+
|
|
412
|
+
## `FieldValidationContext`
|
|
413
|
+
|
|
414
|
+
The argument passed to a custom validator.
|
|
415
|
+
|
|
416
|
+
```ts
|
|
417
|
+
interface FieldValidationContext {
|
|
418
|
+
field: string
|
|
419
|
+
value: FormFieldValue
|
|
420
|
+
values: FormValues
|
|
421
|
+
element?: FormFieldElement
|
|
422
|
+
index?: number
|
|
423
|
+
}
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
`element` and `index` are populated while a bound controller evaluates an `each` member. `index` is zero-based. Pure helper validation has no DOM element, so `element` remains undefined; `index` is still provided for array members.
|
|
427
|
+
|
|
428
|
+
Use it to write cross-field validators:
|
|
429
|
+
|
|
430
|
+
```ts
|
|
431
|
+
form('checkout-form', {
|
|
432
|
+
validators: {
|
|
433
|
+
card: {
|
|
434
|
+
validate: ({ value, field }) => {
|
|
435
|
+
if (typeof value !== 'string') return `${field} is required.`
|
|
436
|
+
return /^\d{16}$/.test(value.replace(/\s+/g, ''))
|
|
437
|
+
? null
|
|
438
|
+
: 'Card number must be 16 digits.'
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
})
|
|
443
|
+
```
|
|
444
|
+
|
|
445
|
+
---
|
|
446
|
+
|
|
447
|
+
## `FieldValidator`
|
|
448
|
+
|
|
449
|
+
The custom validator signature.
|
|
450
|
+
|
|
451
|
+
```ts
|
|
452
|
+
type FieldValidator = (
|
|
453
|
+
context: FieldValidationContext
|
|
454
|
+
) => string | undefined | null | false | true
|
|
455
|
+
```
|
|
456
|
+
|
|
457
|
+
| Return | Meaning |
|
|
458
|
+
| --- | --- |
|
|
459
|
+
| `string` (non-empty) | Push as the error message. |
|
|
460
|
+
| `undefined`, `null`, `true` | Pass. |
|
|
461
|
+
| `false` | Push the generic error message `"Validation failed."`. |
|
|
462
|
+
|
|
463
|
+
Multiple validators can be chained by passing an array as `validate`:
|
|
464
|
+
|
|
465
|
+
```ts
|
|
466
|
+
form('order-form', {
|
|
467
|
+
validators: {
|
|
468
|
+
quantity: {
|
|
469
|
+
validate: [
|
|
470
|
+
({ value }) => (typeof value === 'string' && Number(value) > 0 ? null : 'Must be greater than zero.'),
|
|
471
|
+
({ value }) => (typeof value === 'string' && Number.isInteger(Number(value)) ? null : 'Must be an integer.')
|
|
472
|
+
]
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
})
|
|
476
|
+
```
|
|
477
|
+
|
|
478
|
+
---
|
|
479
|
+
|
|
480
|
+
## `FormCleanup`
|
|
481
|
+
|
|
482
|
+
The callback accepted by [`addCleanup()`](api/add-cleanup.md).
|
|
483
|
+
|
|
484
|
+
```ts
|
|
485
|
+
type FormCleanup = () => void
|
|
486
|
+
```
|
|
487
|
+
|
|
488
|
+
Cleanups are synchronous and run once in reverse registration order during `destroy()`, unless their returned unregister function removes them first.
|
|
489
|
+
|
|
490
|
+
---
|
|
491
|
+
|
|
492
|
+
## `AutoSubmitOptions`
|
|
493
|
+
|
|
494
|
+
The argument to [`autoSubmit()`](api/auto-submit.md) and the `autoSubmit` option.
|
|
495
|
+
|
|
496
|
+
```ts
|
|
497
|
+
interface AutoSubmitOptions {
|
|
498
|
+
debounce?: number
|
|
499
|
+
}
|
|
500
|
+
```
|
|
501
|
+
|
|
502
|
+
`debounce` is in milliseconds.
|
|
503
|
+
|
|
504
|
+
---
|
|
505
|
+
|
|
506
|
+
## `AppendContentOptions`
|
|
507
|
+
|
|
508
|
+
The argument to [`append()`](api/append.md).
|
|
509
|
+
|
|
510
|
+
```ts
|
|
511
|
+
interface AppendContentOptions {
|
|
512
|
+
tag: keyof HTMLElementTagNameMap
|
|
513
|
+
content: string
|
|
514
|
+
class?: string
|
|
515
|
+
atStart?: boolean
|
|
516
|
+
}
|
|
517
|
+
```
|
|
518
|
+
|
|
519
|
+
| Field | Meaning |
|
|
520
|
+
| --- | --- |
|
|
521
|
+
| `tag` | The HTML tag to create. |
|
|
522
|
+
| `content` | `innerHTML` content for the new node. |
|
|
523
|
+
| `class` | Optional class name. If a node with the same first class already exists inside the form, it is removed before the new one is inserted. |
|
|
524
|
+
| `atStart` | When `true`, inserts at the start of the form. Defaults to `false` (append at the end). |
|
|
525
|
+
|
|
526
|
+
---
|
|
527
|
+
|
|
528
|
+
## `VisualAttributes`
|
|
529
|
+
|
|
530
|
+
The shape of `options.attributes`.
|
|
531
|
+
|
|
532
|
+
```ts
|
|
533
|
+
interface VisualAttributes {
|
|
534
|
+
filled: string
|
|
535
|
+
error: string
|
|
536
|
+
}
|
|
537
|
+
```
|
|
538
|
+
|
|
539
|
+
`Partial<VisualAttributes>` is accepted, so you can override only one of them. See [docs/css-styling.md](css-styling.md).
|
|
540
|
+
|
|
541
|
+
---
|
|
542
|
+
|
|
543
|
+
## `FieldFormatConfig` and `FieldFormatConfigMap`
|
|
544
|
+
|
|
545
|
+
The argument to [`format()`](api/format.md) and [`formatAll()`](api/format.md). The map is the shape of `options.formats`.
|
|
546
|
+
|
|
547
|
+
```ts
|
|
548
|
+
type FormatType =
|
|
549
|
+
| 'general'
|
|
550
|
+
| 'phone'
|
|
551
|
+
| 'numeral'
|
|
552
|
+
| 'date'
|
|
553
|
+
| 'time'
|
|
554
|
+
| 'creditCard'
|
|
555
|
+
| 'creditCardType'
|
|
556
|
+
|
|
557
|
+
interface FieldFormatConfig {
|
|
558
|
+
type: FormatType
|
|
559
|
+
field: string | string[]
|
|
560
|
+
displayField?: string
|
|
561
|
+
options?: Record<string, unknown>
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
type FieldFormatConfigMap = Record<string, FieldFormatConfig>
|
|
565
|
+
```
|
|
566
|
+
|
|
567
|
+
The `field` name is the **canonical** name of the formatted pair. A custom `displayField` is valid only for one string field; passing it with a field array logs an error and leaves the form unchanged. Array configurations derive `${fieldName}_displayed` independently for every field. Every map value includes its own `field` because the map key is only an identifier. See [The mirror convention](api/format.md#the-mirror-convention).
|
|
568
|
+
|
|
569
|
+
---
|
|
570
|
+
|
|
571
|
+
## `FormsApi`
|
|
572
|
+
|
|
573
|
+
The shape of the [`browser`](../getting-started.md#browser-registry-helpers) singleton exported from the vanilla entrypoint. The IIFE bundle exposes the same shape as `window.Forms`.
|
|
574
|
+
|
|
575
|
+
```ts
|
|
576
|
+
interface FormsApi {
|
|
577
|
+
form: (target: FormTarget, options?: FormControllerOptions) => FormController
|
|
578
|
+
newForm: (input: NewFormInput) => FormController | undefined
|
|
579
|
+
destroyForm: (id: string) => void
|
|
580
|
+
available: FormsAvailable
|
|
581
|
+
}
|
|
582
|
+
```
|
|
583
|
+
|
|
584
|
+
`form` is the same reference exported from `@samline/forms`. `newForm` and `destroyForm` manage the module-level `available` registry keyed by the form id. Spread `browser` into a new object to derive an independent registry (with its own `available` map); see the getting-started guide for the pattern.
|
|
585
|
+
|
|
586
|
+
---
|
|
587
|
+
|
|
588
|
+
## `NewFormInput`
|
|
589
|
+
|
|
590
|
+
The argument to `FormsApi.newForm`.
|
|
591
|
+
|
|
592
|
+
```ts
|
|
593
|
+
interface NewFormInput {
|
|
594
|
+
id: string
|
|
595
|
+
options?: FormControllerOptions
|
|
596
|
+
}
|
|
597
|
+
```
|
|
598
|
+
|
|
599
|
+
A missing `id` logs `Form ID is required` to `console.error` and `newForm` returns `undefined` without touching the registry.
|
|
600
|
+
|
|
601
|
+
---
|
|
602
|
+
|
|
603
|
+
## `FormsAvailable`
|
|
604
|
+
|
|
605
|
+
The shape of `FormsApi.available`.
|
|
606
|
+
|
|
607
|
+
```ts
|
|
608
|
+
interface FormsAvailable {
|
|
609
|
+
[id: string]: FormController
|
|
610
|
+
}
|
|
611
|
+
```
|
|
612
|
+
|
|
613
|
+
Use it to inspect or iterate over every live controller in a registry. Each entry is the `FormController` returned by `newForm` for that id.
|
|
614
|
+
|
|
615
|
+
`Partial<VisualAttributes>` is accepted, so you can override only one of them. See [docs/css-styling.md](css-styling.md).
|
package/docs/vanilla.md
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# Vanilla
|
|
2
|
+
|
|
3
|
+
The vanilla documentation has been reorganised into a modular tree. Start here:
|
|
4
|
+
|
|
5
|
+
- [Getting started](getting-started.md) — concepts, observable contract, lifecycle, and the side-effect overview.
|
|
6
|
+
- [Options reference](options.md) — every `FormControllerOptions` field with defaults.
|
|
7
|
+
- [CSS styling](css-styling.md) — `css-filled` / `css-error` recipes and accessibility notes.
|
|
8
|
+
- [TypeScript reference](typescript.md) — every exported type, with examples.
|
|
9
|
+
- [API reference](api/index.md) — one page per public method.
|
|
10
|
+
- [Recipes](recipes.md) — end-to-end patterns.
|
|
11
|
+
|
|
12
|
+
If you arrived here from an older link, the equivalent of the previous one-page vanilla guide is now [docs/getting-started.md](getting-started.md).
|