1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
// Names this module's prose links to, resolved for rustdoc.
use crate::;
/// One option offered by a field [`FieldKind::offers_options`] accepts.
///
/// Two strings, because the submitted value and the read label are different
/// facts and every renderer that has tried to collapse them has had to
/// un-collapse them later. `makeover-webview` invented this shape writing its
/// form emitter and it is taken here unchanged; moving it down rather than
/// re-deriving it is the point, since the second and third renderers were each
/// going to arrive at a near-miss of it.
/// `#[non_exhaustive]`, which every type here that a renderer matches or builds
/// carries. Without it a new member is a breaking change at every literal site
/// in the tree.
/// One entry in a field's suggestion list.
///
/// A suggestion-only type rather than a fourth member on [`Choice`], ruled by
/// Max. The two are near-identical and that is the accepted drift risk, so the
/// mitigation is written here: **an
/// option and a candidate are submitted the same way and read differently.**
/// An option is a thing you pick from a known set, and the set is the whole of
/// what there is. A candidate is a thing you are being *oriented* toward out of
/// a set nobody can see, which is why it carries [`detail`](Self::detail) and
/// an option does not.
///
/// This reverses a position quasi-router stated in its own doc, that a
/// candidate is [`Choice`] "because a candidate is submitted under one string
/// and read under another, which is what an option is". True and not
/// sufficient: how a thing is submitted was never the half that differed.
///
/// # Why the second string is not folded into the label
///
/// Because every renderer wants it separately, and the two measured sites both
/// draw it by hand today. The MNW server's tag box computes its context as the
/// parent path -- "the parent path orients an otherwise ambiguous leaf:
/// 'Format' appears under audio, software, writing, and video" -- and a list of
/// four identical rows reading "Format" is not a usable list. In a webview the
/// second string is styled differently, in a terminal it wants the remaining
/// columns rather than a dash, and in neither is it part of what the typed
/// value matches against. `Choice::new(slug, format!("{label} - {context}"))`
/// loses all three of those facts, which is the condition this type exists to
/// end.
///
/// # No `unavailable`
///
/// [`Choice::unavailable`] has no counterpart here, and the omission is the
/// implementer's call recorded rather than an oversight. A suggestion that
/// cannot be picked is arguably not a suggestion: an option list is a fixed set
/// a user is owed an explanation about, and a candidate list is whatever a
/// route decided to offer, so a route with nothing to say simply does not offer
/// the row. Add it if a measured site ever wants it.
///
/// # What it does not carry, and where that lives
///
/// What *happens* when a candidate is picked. Picking is local by default -- it
/// writes [`value`](Self::value) into the field that owns the list -- and a
/// candidate that does something else says so with an action. An action is not
/// a word this crate has, exactly as [`Field`] here has no `suggests` member,
/// so both live on the router's owned mirror of this type.
///
/// `#[non_exhaustive]` from birth. Non-negotiable: adding it later means a
/// breaking change at every literal site in the tree.
/// One field of a form.
///
/// Borrowed rather than owned: a description is built, read once by a renderer,
/// and dropped. Nothing here outlives the screen it describes.
///
/// # What it carries, and what it does not
///
/// Stated here so the next renderer does not re-ask, which is what the first
/// two both did. It carries everything a renderer needs to *draw* the field:
/// its kind, what it is called, what it is asked for, its standing help, what
/// is wrong with it now, whether it is compulsory, whether it hides behind a
/// disclosure, its ghost text, and the options it offers.
///
/// It does not carry the **current value**, and it is not going to. That is the
/// one thing here that is genuinely renderer state: a webview reads it back out
/// of the DOM, an immediate-mode renderer holds a `&mut` to the app's own field
/// and writes through it, and a terminal keeps an edit buffer. A description
/// that carried the value would have to carry a way to write it back, at which
/// point it is a form model and no longer a description.
///
/// **Constraints** are here and enforcement is not, which is one line rather
/// than two. [`required`], [`max_length`], [`min`] and [`max`] are facts about
/// the *question*, so a renderer can emit its host's idiom for each — an HTML
/// attribute, a marked label, a clamped spinner — and the platform helps the
/// user before anything is submitted. Deciding that a value is wrong stays with
/// whoever validated, and [`error`] is that decision arriving back.
///
/// The set stops before `pattern`, and stops there on both tests at once. A
/// regex has an honest answer in a webview and none anywhere else: egui would
/// have to run it per keystroke and decide what a half-typed value means,
/// which is enforcement wearing description's clothes. And it is one site in
/// goingson and none in Balanced Breakfast, against 8 and 1 for `maxlength`.
///
/// [`error`]: Field::error
/// [`required`]: Field::required
/// [`max_length`]: Field::max_length
/// [`min`]: Field::min
/// [`max`]: Field::max
/// How a slider's position becomes its value, and how finely it moves.
///
/// **The data of a slider is a fraction and a function taking numbers to
/// numbers.** Stated by Max, and it is what [`min`](Field::min) and
/// [`max`](Field::max) are not: they were never the control's extent.
/// A slider's extent is always 0 to 1 — a thumb at 40% of a track — and the
/// bounds are `f(0)` and `f(1)`. Linear is the constant-slope case, which is
/// exactly why nobody noticed the function was there: when `f` is
/// `min + t * (max - min)` the extent and the bounds coincide numerically and
/// the mapping is invisible.
///
/// So this is not a scale flag bolted onto a range. Every range described
/// before it had a mapping, and four renderers each hard-coded the same one.
///
/// # Why a closed family and not a function
///
/// `fn(f64) -> f64` is the literal reading and it does not survive the
/// description boundary. A fn pointer cannot be emitted into a browser, and it
/// cannot be compared or hashed in a way that means anything, which this struct
/// needs. A named family is the same semantics with arbitrary closures given
/// up, and nothing measured wants one: the tree has a single non-linear shape
/// across five controls and no second shape at all.
///
/// # Why the step is here
///
/// Max, in the same breath: if the family is prescriptive anyway, the step
/// spacing belongs in it. On a slider the granularity and the mapping are one
/// decision — a curve chosen without saying how finely it moves is half an
/// answer — and holding them apart is what let a 0-to-1 threshold ship as a
/// two-position control, since the host default of 1 was applied to a mapping
/// nobody had named. It also un-overloads [`Field::step`], which stays as it
/// was for a *typed* value, where there is no mapping and the granularity is a
/// plain fact about the number.
///
/// A future curve carrying a fact of its own — an exponent, an inflection —
/// puts it in its own variant rather than on the struct, which is the second
/// reason this shape is right.
///
/// **The step is in the value's own units under every curve.** What a curve
/// changes is the mapping, not the units the granularity is measured in: a step
/// of `0.001` on an envelope time is three decimals whether the track is
/// logarithmic or not, and a renderer that reads the step for display precision
/// keeps reading it the same way.