@orkestrel/form 0.0.12 → 0.0.13

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 CHANGED
@@ -20,7 +20,7 @@ npm install @orkestrel/form
20
20
 
21
21
  ## Requirements
22
22
 
23
- - Node.js >= 22.12
23
+ - Node.js >= 22.18
24
24
  - Host-independent: no `node:*`, no DOM. Ships dual ESM+CJS builds.
25
25
 
26
26
  ## Usage
@@ -1,33 +1,11 @@
1
1
  import type { EmitterErrorHandler } from '@orkestrel/emitter';
2
2
  import type { EmitterHooks } from '@orkestrel/emitter';
3
3
  import type { EmitterInterface } from '@orkestrel/emitter';
4
- import type { JSONRecord } from '@orkestrel/contract';
5
- import type { Result } from '@orkestrel/contract';
6
-
7
- /**
8
- * Represents any number of choices out of a list, holding the checked values.
9
- *
10
- * @remarks
11
- * A field offering one box that means yes or no is a {@link ConfirmField}, not a one-choice
12
- * checkbox.
13
- */
14
- declare interface CheckboxField extends FieldBase {
15
- readonly control: 'checkbox';
16
- readonly choices: readonly FieldChoice[];
17
- readonly default?: readonly string[];
18
- }
19
-
20
- /** Represents a color, held as the control's own six-digit `#rrggbb` string. */
21
- declare interface ColorField extends FieldBase {
22
- readonly control: 'color';
23
- readonly default?: string;
24
- }
25
-
26
- /** Represents a single on/off box, holding a boolean. */
27
- declare interface ConfirmField extends FieldBase {
28
- readonly control: 'confirm';
29
- readonly default?: boolean;
30
- }
4
+ import type { FieldError } from '@orkestrel/form';
5
+ import type { FieldValue } from '@orkestrel/form';
6
+ import type { FormField } from '@orkestrel/form';
7
+ import type { FormInterface } from '@orkestrel/form';
8
+ import type { FormSubmission } from '@orkestrel/form';
31
9
 
32
10
  /**
33
11
  * Creates a native form binding exposed through its lifecycle interface.
@@ -43,171 +21,6 @@ declare interface ConfirmField extends FieldBase {
43
21
  */
44
22
  export declare function createFormBinding(element: HTMLFormElement, document: FormInterface, options?: FormBindingOptions): FormBindingInterface;
45
23
 
46
- /** Represents a calendar date, held as the control's own `YYYY-MM-DD` string. */
47
- declare interface DateField extends FieldBase {
48
- readonly control: 'date';
49
- readonly default?: string;
50
- }
51
-
52
- /** Represents a date and a time of day together, with no zone, held as the control's own string. */
53
- declare interface DatetimeField extends FieldBase {
54
- readonly control: 'datetime';
55
- readonly default?: string;
56
- }
57
-
58
- /** Represents text over many lines. */
59
- declare interface EditorField extends FieldBase {
60
- readonly control: 'editor';
61
- readonly default?: string;
62
- readonly placeholder?: string;
63
- }
64
-
65
- /**
66
- * Declares what every field carries, whatever its control.
67
- *
68
- * @remarks
69
- * `name` keys the field in {@link FormValues} and `group` names a {@link FormGroup}.
70
- *
71
- * `hidden`, `locked`, and `disabled` differ in what they remove. `hidden` keeps the field out of
72
- * the rendered form, `locked` renders it unwritable, and both are still validated and still
73
- * submitted. `disabled` takes the field out of the form entirely: it is neither validated nor
74
- * submitted. It is the field's declared, opening state; {@link FormInterface.disabled} is the
75
- * current fact, because a live form can move a field either way.
76
- *
77
- * `meta` is a bounded JSON carrier for whatever the schema declines to model. Evaluation never
78
- * reads it, no rule sees it, and it round-trips verbatim through serialization. This package
79
- * defines no key in it, so every key belongs to the host.
80
- */
81
- declare interface FieldBase {
82
- readonly name: string;
83
- readonly label?: string;
84
- readonly help?: string;
85
- readonly group?: string;
86
- readonly hidden?: boolean;
87
- readonly disabled?: boolean;
88
- readonly locked?: boolean;
89
- readonly rule?: FieldRule;
90
- readonly meta?: JSONRecord;
91
- }
92
-
93
- /**
94
- * Represents one option a `select` or `checkbox` field offers.
95
- *
96
- * @remarks
97
- * `value` is what the form stores and `label` is what the person reads. `help` explains the
98
- * option, and `disabled` shows it while refusing its value at every input door, including
99
- * seeded values.
100
- */
101
- declare interface FieldChoice {
102
- readonly value: string;
103
- readonly label: string;
104
- readonly help?: string;
105
- readonly disabled?: boolean;
106
- }
107
-
108
- /**
109
- * Represents one failed check against one field.
110
- *
111
- * @remarks
112
- * `rule` names the constraint that failed. It is absent when the message came from a
113
- * {@link FieldRule.custom} validator or from {@link FormInterface.invalidate}, because
114
- * neither failure belongs to a named rule.
115
- */
116
- declare interface FieldError {
117
- readonly field: string;
118
- readonly message: string;
119
- readonly rule?: FieldRuleName;
120
- }
121
-
122
- /**
123
- * Represents the constraints one field's value must satisfy.
124
- *
125
- * @remarks
126
- * `minimum` and `maximum` measure whatever the control makes countable: characters for
127
- * `text`, `editor`, and `password`; magnitude for `number`; chronology for `date`, `time`,
128
- * and `datetime`, whose operand is a string written in that control's own format; and the
129
- * number of entries for `checkbox`, `list`, and `file`.
130
- *
131
- * `step` is the interval a numeric value must land on. `pattern` is regular-expression
132
- * source. `email`, `url`, `integer`, and `alphanumeric` each assert one shape over the whole
133
- * value, or each entry of a `list`. `required` requires an entry for `list` and presence
134
- * for other controls. `custom` runs last and is the only rule that sees the rest of the form.
135
- *
136
- * @example
137
- * ```ts
138
- * const rule: FieldRule = { required: true, minimum: 8, pattern: '\\d' }
139
- * ```
140
- */
141
- declare interface FieldRule {
142
- readonly required?: boolean;
143
- readonly minimum?: number | string;
144
- readonly maximum?: number | string;
145
- readonly step?: number;
146
- readonly pattern?: string;
147
- readonly email?: boolean;
148
- readonly url?: boolean;
149
- readonly integer?: boolean;
150
- readonly alphanumeric?: boolean;
151
- readonly custom?: FieldValidator;
152
- }
153
-
154
- /**
155
- * Lists every rule that reports its failure by name.
156
- *
157
- * @remarks
158
- * `custom` is excluded because it supplies its own message, so nothing keyed by a rule name
159
- * would ever be read for it. {@link FormOptions.messages} is keyed by this name.
160
- */
161
- declare type FieldRuleName = Exclude<keyof FieldRule, 'custom'>;
162
-
163
- /**
164
- * Checks one value against the whole form.
165
- *
166
- * @remarks
167
- * It runs after every named rule, and it runs on an absent value as well as a present one. That
168
- * is what makes a rule such as "required once the sibling says yes" expressible, and it means an
169
- * unanswered field can carry both a `required` message and this validator's own.
170
- *
171
- * @param value - The value the field holds, or `undefined` when nobody has answered it.
172
- * @param values - Every answer the form holds, so a rule can read its siblings.
173
- * @returns `true` when the value passes, or the message explaining why it failed.
174
- * @throws Thrown when a {@link FieldValidator} throws; its own thrown value escapes the mutation
175
- * call unchanged. When a form mutation has already changed state, the throw leaves those
176
- * changes beside the error list from before that mutation. An invalidation can therefore be
177
- * recorded without appearing in `errors`, and a clear can reset state without emitting `clear`.
178
- * Form-owned refusals use
179
- * {@link FormError} instead.
180
- * @example
181
- * ```ts
182
- * const matches: FieldValidator = (value, values) =>
183
- * value === values.password ? true : 'Both passwords must match'
184
- * ```
185
- */
186
- declare type FieldValidator = (value: FieldValue | undefined, values: FormValues) => true | string;
187
-
188
- /**
189
- * Represents every value a field can hold.
190
- *
191
- * @remarks
192
- * The variant follows the control: text-like controls hold a `string`, `number` holds a
193
- * `number`, `confirm` holds a `boolean`, and `checkbox`, `list`, and `file` hold a
194
- * `readonly string[]`.
195
- */
196
- declare type FieldValue = string | number | boolean | readonly string[];
197
-
198
- /**
199
- * Represents one or more files, by name.
200
- *
201
- * @remarks
202
- * A value is the names alone: bytes never enter the document. `accept` lists the media types
203
- * and extensions the control offers, in the form the host expects.
204
- */
205
- declare interface FileField extends FieldBase {
206
- readonly control: 'file';
207
- readonly accept?: readonly string[];
208
- readonly multiple?: boolean;
209
- }
210
-
211
24
  /** Implements a controlled native form over a borrowed document. */
212
25
  export declare class FormBinding implements FormBindingInterface {
213
26
  #private;
@@ -301,340 +114,6 @@ export declare interface FormBindingValidity {
301
114
  /** Represents a native answer control admitted by the binding. */
302
115
  export declare type FormControl = HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement;
303
116
 
304
- /**
305
- * Lists everything a form announces.
306
- *
307
- * @remarks
308
- * `fill` carries the field that changed and its new value, where `undefined` is the value
309
- * being cleared. `validate` carries the errors a check produced, empty when it found none.
310
- * `disable` and `enable` each carry one field, and fire once per field whose state actually
311
- * moved, in the order the schema declares them. `submit` fires only on a submit that passed.
312
- * `touch` announces the first visit since clear. `prepare`, `accept`, and `abort` carry the receipt
313
- * after their state is committed. `clear` and `abandon` are signals.
314
- */
315
- declare type FormEventMap = {
316
- readonly fill: readonly [name: string, value: FieldValue | undefined];
317
- readonly touch: readonly [name: string];
318
- readonly validate: readonly [errors: readonly FieldError[]];
319
- readonly disable: readonly [name: string];
320
- readonly enable: readonly [name: string];
321
- readonly submit: readonly [values: FormValues];
322
- readonly prepare: readonly [submission: FormSubmission];
323
- readonly accept: readonly [submission: FormSubmission];
324
- readonly abort: readonly [submission: FormSubmission];
325
- readonly clear: readonly [];
326
- readonly abandon: readonly [];
327
- };
328
-
329
- /**
330
- * Represents any field a schema can declare.
331
- *
332
- * @remarks
333
- * The union discriminates on `control`, so narrowing on that member reaches each variant's
334
- * own options.
335
- *
336
- * @example
337
- * ```ts
338
- * function choices(field: FormField): readonly FieldChoice[] {
339
- * return field.control === 'select' || field.control === 'checkbox' ? field.choices : []
340
- * }
341
- * ```
342
- */
343
- declare type FormField = TextField | EditorField | PasswordField | NumberField | DateField | TimeField | DatetimeField | ColorField | ConfirmField | SelectField | CheckboxField | ListField | FileField;
344
-
345
- /**
346
- * Represents a named section of a form.
347
- *
348
- * @remarks
349
- * A field joins a group through {@link FieldBase.group}. Grouping arranges the form and
350
- * changes no answer.
351
- */
352
- declare interface FormGroup {
353
- readonly name: string;
354
- readonly label: string;
355
- readonly help?: string;
356
- }
357
-
358
- /**
359
- * Declares the contract a form exposes: the state it holds and the calls that move it.
360
- *
361
- * @remarks
362
- * `valid` is true when the last completed evaluation found no error, and `dirty` is true once
363
- * an answer differs from its acknowledged baseline. Both are derived, never stored.
364
- *
365
- * `touched` holds the fields somebody has visited, which is what lets a renderer withhold an
366
- * error until the person has had their turn at it.
367
- *
368
- * @example
369
- * ```ts
370
- * form.fill('email', 'ada@example.com')
371
- * const result = form.submit()
372
- * if (result.success) await form.answer
373
- * ```
374
- */
375
- declare interface FormInterface {
376
- /** Holds the form's event emitter. */
377
- readonly emitter: EmitterInterface<FormEventMap>;
378
- /** Holds the schema this form asks. */
379
- readonly schema: FormSchema;
380
- /** Reports the answers the form holds. */
381
- readonly values: FormValues;
382
- /**
383
- * Holds the acknowledged answers, initially the schema's defaults overlaid with seeded values.
384
- *
385
- * @remarks
386
- * Acceptance advances only the enabled fields captured by the submission, including absence.
387
- * It is what `dirty` measures against and what {@link FormInterface.clear} returns to.
388
- */
389
- readonly baseline: FormValues;
390
- /** Holds the submission awaiting acknowledgement, or `undefined` when none is pending. */
391
- readonly pending: FormSubmission | undefined;
392
- /** Holds every error the last check produced. */
393
- readonly errors: readonly FieldError[];
394
- /** Lists the names of the fields somebody has visited. */
395
- readonly touched: ReadonlySet<string>;
396
- /**
397
- * Lists the names of the fields that are out of the form.
398
- *
399
- * @remarks
400
- * It opens as the set the schema declares through {@link FieldBase.disabled} and moves with
401
- * every {@link FormInterface.disable} and {@link FormInterface.enable} call, so the schema
402
- * holds the declaration and this holds the current fact.
403
- */
404
- readonly disabled: ReadonlySet<string>;
405
- /** Reports where the form sits in its life. */
406
- readonly status: FormStatus;
407
- /** Reports whether the last completed evaluation found no error. */
408
- readonly valid: boolean;
409
- /** Reports whether any answer differs from its acknowledged baseline. */
410
- readonly dirty: boolean;
411
- /**
412
- * Holds the answers after the form settles.
413
- *
414
- * @remarks
415
- * It resolves with the submitted values on the first valid submit, and rejects when teardown
416
- * abandons the form before it settles.
417
- */
418
- readonly answer: Promise<FormValues>;
419
- /**
420
- * Finds one field by name.
421
- *
422
- * @param name - The field's name.
423
- * @returns The field, or `undefined` when the schema declares no such name.
424
- */
425
- field(name: string): FormField | undefined;
426
- /**
427
- * Answers one field, or several at once.
428
- *
429
- * @param values - The answers to write, each keyed by its field name.
430
- */
431
- fill(values: FormValues): void;
432
- /**
433
- * Answers one field.
434
- *
435
- * @param name - The field's name.
436
- * @param value - The answer to write, or `undefined` to clear it.
437
- */
438
- fill(name: string, value: FieldValue | undefined): void;
439
- /**
440
- * Records that somebody has visited a field.
441
- *
442
- * @param name - The field's name.
443
- */
444
- touch(name: string): void;
445
- /**
446
- * Fails a field from outside, for what the rules cannot see.
447
- *
448
- * @remarks
449
- * One field holds one external failure, so a second call replaces the first, and the failure
450
- * lasts until that field is filled again or the form is cleared.
451
- * A receipt admits only a captured enabled field whose fill revision still matches. Stale,
452
- * foreign, copied, consumed, and teardown-invalidated receipts return `false`; unknown fields
453
- * still throw `FIELD`.
454
- *
455
- * @param name - The field's name.
456
- * @param message - What to tell the person.
457
- * @param submission - The active receipt to check against the field's captured revision.
458
- * @returns True if the failure was applied; false if the receipt or field revision is stale.
459
- */
460
- invalidate(name: string, message: string, submission?: FormSubmission): boolean;
461
- /**
462
- * Takes one field, several fields, or every field out of the form.
463
- *
464
- * @remarks
465
- * A disabled field is neither evaluated nor submitted. Its answer is kept, and so is any
466
- * {@link FormInterface.invalidate} failure it carries, which is withheld from `errors` while
467
- * the field is out and restored when it comes back. The form emits `disable` once per field
468
- * whose state actually moved, in schema order, so a call that moves nothing announces
469
- * nothing. Disabling is a write, so a settled or abandoned form refuses it.
470
- */
471
- disable(): void;
472
- /**
473
- * Takes one field out of the form.
474
- *
475
- * @param name - The field's name.
476
- * @throws A {@link FormError} coded `FIELD` when the schema declares no such name.
477
- */
478
- disable(name: string): void;
479
- /**
480
- * Takes several fields out of the form.
481
- *
482
- * @param names - The field names.
483
- * @throws A {@link FormError} coded `FIELD` when the schema declares no such name. Every name
484
- * is checked before any field moves, so one bad name leaves the whole call undone.
485
- */
486
- disable(names: readonly string[]): void;
487
- /**
488
- * Puts one field, several fields, or every field back into the form.
489
- *
490
- * @remarks
491
- * An enabled field is evaluated and submitted again, and any invalidation held while it was
492
- * out reappears in `errors`. The form emits `enable` once per field whose state actually
493
- * moved, in schema order. Enabling is a write, so a settled or abandoned form refuses it.
494
- */
495
- enable(): void;
496
- /**
497
- * Puts one field back into the form.
498
- *
499
- * @param name - The field's name.
500
- * @throws A {@link FormError} coded `FIELD` when the schema declares no such name.
501
- */
502
- enable(name: string): void;
503
- /**
504
- * Puts several fields back into the form.
505
- *
506
- * @param names - The field names.
507
- * @throws A {@link FormError} coded `FIELD` when the schema declares no such name. Every name
508
- * is checked before any field moves, so one bad name leaves the whole call undone.
509
- */
510
- enable(names: readonly string[]): void;
511
- /**
512
- * Checks every answer and settles the form when they all pass.
513
- *
514
- * @returns The values on success, or every error that stopped them.
515
- */
516
- submit(): FormResult;
517
- /**
518
- * Prepares an owned enabled snapshot for acknowledgement while leaving the form editable.
519
- *
520
- * @returns The submission on success, or the errors that prevented preparation.
521
- * @throws A {@link FormError} coded `PENDING` for an overlapping preparation or pending receipt,
522
- * or when clear interrupts preparation; terminal forms retain their terminal refusals.
523
- */
524
- prepare(): FormPreparationResult;
525
- /**
526
- * Adopts the active submission's captured answers into the baseline without changing live state.
527
- *
528
- * @param submission - The receipt returned by preparation.
529
- * @returns True if this active receipt was accepted; false otherwise, including after teardown.
530
- */
531
- accept(submission: FormSubmission): boolean;
532
- /**
533
- * Consumes the active submission and aborts its signal without changing answers or baseline.
534
- *
535
- * @param submission - The receipt returned by preparation.
536
- * @returns True if this active receipt was aborted; false otherwise, including after teardown.
537
- */
538
- abort(submission: FormSubmission): boolean;
539
- /**
540
- * Returns every answer to its acknowledged baseline and aborts pending acknowledgement.
541
- *
542
- * @remarks
543
- * Those answers are {@link FormInterface.baseline}. The runtime disabled overlay resets with
544
- * them, so {@link FormInterface.disabled} reads the schema's declarations again.
545
- */
546
- clear(): void;
547
- /**
548
- * Tears the form down, abandoning it when it has not settled.
549
- *
550
- * @remarks
551
- * Tearing down twice does nothing the second time. A request from inside a listener defers
552
- * teardown until the outermost mutation batch closes, so an in-flight settlement can win and
553
- * leave the form `settled` rather than `abandoned`.
554
- */
555
- destroy(): void;
556
- }
557
-
558
- /** Reports a prepared submission, or every error that prevented its preparation. */
559
- declare type FormPreparationResult = Result<FormSubmission, readonly FieldError[]>;
560
-
561
- /**
562
- * Reports what a submit answers with: the values, or every error that stopped them.
563
- *
564
- * @example
565
- * ```ts
566
- * const result: FormResult = form.submit()
567
- * const email = result.success ? result.value.email : undefined
568
- * ```
569
- */
570
- declare type FormResult = Result<FormValues, readonly FieldError[]>;
571
-
572
- /**
573
- * Describes everything a form asks.
574
- *
575
- * @remarks
576
- * `fields` is the schema's only required member, and the order it declares is the order the
577
- * form presents. `name`, `label`, and `help` describe the form itself.
578
- *
579
- * @example
580
- * ```ts
581
- * const schema: FormSchema = {
582
- * label: 'Sign up',
583
- * fields: [
584
- * { control: 'text', name: 'email', label: 'Email', rule: { required: true, email: true } },
585
- * { control: 'confirm', name: 'terms', label: 'I accept the terms' },
586
- * ],
587
- * }
588
- * ```
589
- */
590
- declare interface FormSchema {
591
- readonly name?: string;
592
- readonly label?: string;
593
- readonly help?: string;
594
- readonly groups?: readonly FormGroup[];
595
- readonly fields: readonly FormField[];
596
- }
597
-
598
- /**
599
- * Represents where a form sits in its life.
600
- *
601
- * @remarks
602
- * A form opens `editing`, turns `settled` on its first valid submit, and turns `abandoned`
603
- * when it is destroyed before settling. Both end states are terminal, and a write to a form
604
- * in either one is refused. A destroy requested while a mutation batch is open is recorded,
605
- * refuses every subsequent write immediately, and defers teardown until the outermost batch
606
- * closes. The batch outcome wins: a batch that settles the form leaves it `settled`, resolves
607
- * `answer`, and emits no `abandon`. Teardown never advances into, aborts, or rolls back the
608
- * batch. The pending request is private, unnamed state and adds no fourth status.
609
- */
610
- declare type FormStatus = 'editing' | 'settled' | 'abandoned';
611
-
612
- /**
613
- * Carries an owned, frozen answer snapshot and the signal for its pending acknowledgement.
614
- *
615
- * @remarks
616
- * Only the producing form accepts this object's identity. Copying its members cannot create a
617
- * receipt. The values and their lists are frozen; the native signal remains usable by transports.
618
- */
619
- declare interface FormSubmission {
620
- readonly values: FormValues;
621
- readonly signal: AbortSignal;
622
- }
623
-
624
- /**
625
- * Represents a form's answers, keyed by field name.
626
- *
627
- * @remarks
628
- * A name with no key is a field nobody has answered. A disabled field's value may appear so a
629
- * renderer can show it, but the value is never evaluated or submitted.
630
- *
631
- * @example
632
- * ```ts
633
- * const values: FormValues = { email: 'ada@example.com', terms: true }
634
- * ```
635
- */
636
- declare type FormValues = Readonly<Record<string, FieldValue>>;
637
-
638
117
  /**
639
118
  * Checks whether a value is a native binding refusal.
640
119
  * @param value - The value to inspect.
@@ -657,26 +136,6 @@ export declare function isFormBindingError(value: unknown): value is FormBinding
657
136
  */
658
137
  export declare function isFormControl(value: unknown): value is FormControl;
659
138
 
660
- /**
661
- * Represents an ordered list of free-text strings.
662
- *
663
- * @remarks
664
- * `required` requires at least one entry. `minimum` and `maximum` count entries.
665
- * `pattern`, `email`, `url`, `integer`, and `alphanumeric` check each entry and name
666
- * the failing value in its message. `custom` checks the whole list. Duplicates are retained.
667
- *
668
- * @example
669
- * ```ts
670
- * const to: ListField = {
671
- * control: 'list', name: 'to', rule: { required: true, email: true },
672
- * }
673
- * ```
674
- */
675
- declare interface ListField extends FieldBase {
676
- readonly control: 'list';
677
- readonly default?: readonly string[];
678
- }
679
-
680
139
  /**
681
140
  * Checks a native control population against a field's declared value shape.
682
141
  * @param field - The declared field.
@@ -689,25 +148,6 @@ declare interface ListField extends FieldBase {
689
148
  */
690
149
  export declare function matchesFormControls(field: FormField, controls: readonly FormControl[]): boolean;
691
150
 
692
- /** Represents a number. */
693
- declare interface NumberField extends FieldBase {
694
- readonly control: 'number';
695
- readonly default?: number;
696
- readonly placeholder?: string;
697
- }
698
-
699
- /**
700
- * Represents a secret, obscured as it is typed.
701
- *
702
- * @remarks
703
- * It carries no `default` deliberately: a seeded secret is a secret written down. `mask` is
704
- * the character the control repeats in place of the text.
705
- */
706
- declare interface PasswordField extends FieldBase {
707
- readonly control: 'password';
708
- readonly mask?: string;
709
- }
710
-
711
151
  /**
712
152
  * Reads one compatible native population using the document's blank-to-absence semantics.
713
153
  * @param field - The field declaring the answer shape.
@@ -741,31 +181,4 @@ export declare function readFormControls(field: FormField, controls: readonly Fo
741
181
  */
742
182
  export declare function readNativeMessages(control: FormControl, errors: readonly FieldError[]): readonly string[];
743
183
 
744
- /**
745
- * Represents one choice out of a list.
746
- *
747
- * @remarks
748
- * `open` admits a value the list does not offer, which is what turns a closed menu into a
749
- * suggestion list.
750
- */
751
- declare interface SelectField extends FieldBase {
752
- readonly control: 'select';
753
- readonly choices: readonly FieldChoice[];
754
- readonly default?: string;
755
- readonly open?: boolean;
756
- }
757
-
758
- /** Represents a single line of text. */
759
- declare interface TextField extends FieldBase {
760
- readonly control: 'text';
761
- readonly default?: string;
762
- readonly placeholder?: string;
763
- }
764
-
765
- /** Represents a time of day, held as the control's own `HH:MM` string, with seconds optional. */
766
- declare interface TimeField extends FieldBase {
767
- readonly control: 'time';
768
- readonly default?: string;
769
- }
770
-
771
184
  export { }