@pipelex/mthds-form 0.9.0 → 0.10.1

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.
Files changed (50) hide show
  1. package/README.md +3 -0
  2. package/dist/{chunk-S4CB423P.js → chunk-4JQAJT7C.js} +3 -3
  3. package/dist/{chunk-S4CB423P.js.map → chunk-4JQAJT7C.js.map} +1 -1
  4. package/dist/{chunk-YABRYTQ4.js → chunk-4KGQ65TQ.js} +3 -3
  5. package/dist/{chunk-YABRYTQ4.js.map → chunk-4KGQ65TQ.js.map} +1 -1
  6. package/dist/chunk-CAKQ5VFT.js +35 -0
  7. package/dist/chunk-CAKQ5VFT.js.map +1 -0
  8. package/dist/{chunk-25I6JDIK.js → chunk-FABY3DEY.js} +2 -2
  9. package/dist/chunk-FABY3DEY.js.map +1 -0
  10. package/dist/{chunk-AZZAAGNX.js → chunk-TID7ZN63.js} +7 -3
  11. package/dist/chunk-TID7ZN63.js.map +1 -0
  12. package/dist/{chunk-KG4IYFWI.js → chunk-W56WIIVC.js} +174 -51
  13. package/dist/chunk-W56WIIVC.js.map +1 -0
  14. package/dist/chunk-XCO6GTEC.js +38 -0
  15. package/dist/chunk-XCO6GTEC.js.map +1 -0
  16. package/dist/{chunk-KIEOLP2L.js → chunk-ZB4RYUKV.js} +4 -4
  17. package/dist/chunk-ZB4RYUKV.js.map +1 -0
  18. package/dist/core/derive.d.ts +1 -0
  19. package/dist/core/derive.js +2 -2
  20. package/dist/core/descriptor.d.ts +13 -2
  21. package/dist/core/descriptor.js +1 -1
  22. package/dist/core/file-formats.d.ts +34 -7
  23. package/dist/core/file-formats.js +1 -1
  24. package/dist/core/gating-fields.d.ts +1 -0
  25. package/dist/core/index.d.ts +2 -1
  26. package/dist/core/index.js +7 -6
  27. package/dist/core/narrow-file-formats.d.ts +50 -0
  28. package/dist/core/narrow-file-formats.js +4 -0
  29. package/dist/core/narrow-file-formats.js.map +1 -0
  30. package/dist/core/native-content.d.ts +20 -11
  31. package/dist/core/native-content.js +1 -1
  32. package/dist/core/readiness.d.ts +1 -0
  33. package/dist/core/stuff-files.d.ts +1 -0
  34. package/dist/core/stuff-files.js +2 -2
  35. package/dist/core/values.d.ts +1 -0
  36. package/dist/core/values.js +3 -3
  37. package/dist/generative/index.d.ts +105 -12
  38. package/dist/generative/index.js +79 -157
  39. package/dist/generative/index.js.map +1 -1
  40. package/dist/{ui-designer.mthds → layout-design.mthds} +177 -29
  41. package/dist/react/index.d.ts +66 -10
  42. package/dist/react/index.js +5 -5
  43. package/dist/styles.css +1 -1
  44. package/package.json +3 -3
  45. package/dist/chunk-25I6JDIK.js.map +0 -1
  46. package/dist/chunk-2JWRG53S.js +0 -33
  47. package/dist/chunk-2JWRG53S.js.map +0 -1
  48. package/dist/chunk-AZZAAGNX.js.map +0 -1
  49. package/dist/chunk-KG4IYFWI.js.map +0 -1
  50. package/dist/chunk-KIEOLP2L.js.map +0 -1
@@ -1,18 +1,26 @@
1
1
  domain = "generative"
2
2
  description = "Lays out one page for a method - its inputs, or its result - as a json-render spec over a catalog of components, bound to the state the host provides."
3
- main_pipe = "ui_designer"
3
+ main_pipe = "design_layout"
4
4
 
5
5
  # The designer method. THIS FILE IS THE PROMPT: every paragraph the models
6
6
  # read - the output format, the state contract, the design direction, the
7
- # rules, the seed procedure - is written here as prose, and the only things
8
- # rendered into it are the inputs. The catalog arrives as DATA (the components
9
- # with their props signatures and descriptions, the actions), so a component
10
- # added to the vocabulary appears in the prompts with no change here, and the
11
- # prose that names components (the direction, the rules) is the method's own
12
- # reading of the vocabulary it was written for.
7
+ # rules, the seed procedure, and the brief's own prose - is written here, and
8
+ # the only things rendered into it are the inputs. The catalog arrives as DATA
9
+ # (the components with their props signatures and descriptions, the actions),
10
+ # so a component added to the vocabulary appears in the prompts with no change
11
+ # here, and the prose that names components (the direction, the rules) is the
12
+ # method's own reading of the vocabulary it was written for. The brief arrives
13
+ # as data too: the page's paths with their kinds, presence and constraints,
14
+ # which of them are delegated, what gates the run, and on a result page the
15
+ # state of one real run - and `render_brief` below is the template that lays
16
+ # it out as the Markdown both models read.
13
17
  #
14
- # It runs in two stages, and `ui_designer` is the sequence of them:
18
+ # It runs in three stages, and `design_layout` is the sequence of them:
15
19
  #
20
+ # - `render_brief` lays the brief out. It is a Jinja2 template over the data,
21
+ # with no model behind it, and its text is what the two stages below read
22
+ # under `@brief_text`. Every sentence of the brief - the headings, how a
23
+ # path line reads, what "delegated" says - is here and nowhere else.
16
24
  # - `plan_page` reads the brief and the catalog - and the creative seed, when
17
25
  # there is one - and writes a PagePlan: what the page is for, its title,
18
26
  # its composition, its regions with the elements and paths each holds, what
@@ -30,22 +38,34 @@ main_pipe = "ui_designer"
30
38
  # Neither prompt prescribes a composition. There is no skeleton a page must
31
39
  # have, no region it must contain, no place a control must sit, and the prose
32
40
  # names none of the catalog's chrome components: what a component is for is
33
- # in its own description, which travels as data. The rules that remain are the
34
- # ones a page is wrong without - the brief's paths, the bindings that fit,
35
- # delegation, who owns the state, one control that runs the method, heading
36
- # order, integrity of the tree. The shape of the page is the planner's
37
- # decision, written into the plan, and the builder's job is to build it.
41
+ # in its own description, which travels as data - and the one control that
42
+ # runs the method is named by the brief, as data, for the same reason. The
43
+ # rules that remain are the ones a page is wrong without - the brief's paths,
44
+ # the bindings that fit, delegation, who owns the state, one control that
45
+ # runs the method, heading order, integrity of the tree. The shape of the
46
+ # page is the planner's decision, written into the plan, and the builder's
47
+ # job is to build it.
38
48
  #
39
- # Two things to know before editing the prompts:
49
+ # Three things to know before editing the prompts:
40
50
  #
41
51
  # - A literal dollar sign is written `$$`, because `$name` is the language's
42
52
  # inline-substitution shorthand. Every json-render expression key in the
43
53
  # prose (`$$state`, `$$bindState`, `$$item`, `$$cond`, `$$template`, ...)
44
- # is spelled that way and renders as a single `$`.
45
- # - The component and action lists, and the plan, are Jinja2 loops. A loop
46
- # body ends with its own newline, so the heading that follows a loop sits
47
- # directly under `{% endfor %}` to render exactly one blank line between
48
- # the two.
54
+ # is spelled that way and renders as a single `$`, in the brief's template
55
+ # as much as in the prompts.
56
+ # - The component and action lists, and the plan, are Jinja2 loops in the two
57
+ # prompts, which keep every newline they are written with. A loop body ends
58
+ # with its own newline, so the heading that follows a loop sits directly
59
+ # under `{% endfor %}` to render exactly one blank line between the two.
60
+ # - The brief's template is a `markdown` template, and that category trims:
61
+ # a line holding only a `{% %}` tag renders as nothing, so a loop or a
62
+ # condition is written on lines of its own and the text between them keeps
63
+ # its own newlines. Two traps. A line that ENDS with a `{% %}` tag loses
64
+ # its newline with it, so such a tag is closed with `+%}`, which keeps the
65
+ # newline. And every `{% set %}` is written at the top level of the
66
+ # template, before any text, never inside a loop or a condition: the
67
+ # runtime reads a name set inside a block as an input the pipe did not
68
+ # declare, and refuses the method.
49
69
  #
50
70
  # The output is Text carrying JSONL patches - the format the prompt asks for -
51
71
  # rather than a typed structure: a spec is a map of heterogeneous elements
@@ -55,9 +75,9 @@ main_pipe = "ui_designer"
55
75
  # text, and fails loudly on any issue, so a repair is a change HERE, never to
56
76
  # the fixture.
57
77
  #
58
- # Both stages pin the same model. The specs pass takes MODEL=<id> to override
59
- # every pin at once for a comparative run (and TEMPERATURE=<n> for a model
60
- # that fixes its own), and records which model produced each fixture.
78
+ # Both model stages pin the same model. The specs pass takes MODEL=<id> to
79
+ # override every pin at once for a comparative run (and TEMPERATURE=<n> for a
80
+ # model that fixes its own), and records which model produced each fixture.
61
81
  #
62
82
  # The optional `seed` is the creative seed of the planner's last section: a
63
83
  # random string the harness generates, handed over as one line the prompt
@@ -90,6 +110,38 @@ name = { type = "text", description = "The action's name, exactly as a bi
90
110
  description = { type = "text", description = "What the action does and the params it takes.", required = true }
91
111
  built_in = { type = "boolean", description = "True when the runtime handles the action without a handler from the host.", required = true }
92
112
 
113
+ [concept.Brief]
114
+ description = "The page's half of the prompt, as data: which page it is and for which pipe, every path in the state with what it is, which paths are delegated and what gates the run, and on a result page the state of one real run - rendered from the method's own descriptor and from nothing else."
115
+
116
+ [concept.Brief.structure]
117
+ side = { choices = ["input", "result"], description = "Which page is being designed: the form a run is started from, or what a run produced.", required = true }
118
+ pipe_ref = { type = "text", description = "The pipe the page is for, as `domain.pipe_code`.", required = true }
119
+ description = { type = "text", description = "One sentence on what the page is about: the pipe's own description, or the host's summary of it." }
120
+ name = { type = "text", description = "On an input page, the method's name as the host lists it - the one product name the page may carry. Absent when the host lists none." }
121
+ paths = { type = "list", item_type = "concept", item_concept_ref = "PathEntry", description = "Every path in the state the page binds or reads, in reading order and flattened: a structure's members follow it one level deeper, and a list's item members follow the list, spelled relative to one item.", required = true }
122
+ run_control = { type = "text", description = "On an input page, the catalog component that runs the method, by name; the page has exactly one of it." }
123
+ sample_state = { type = "text", description = "On a result page, the state of one real run as the host loads it, as JSON - what `/result` held after one actual run, so magnitudes and lengths can be judged. Never copied into a page." }
124
+
125
+ [concept.PathEntry]
126
+ description = "One path of the state, as the brief describes it: where it is, what it holds, what it is called, what constrains it, and whether the page lays it out or hands it back to the kernel's own control."
127
+
128
+ [concept.PathEntry.structure]
129
+ depth = { type = "integer", description = "How deep the path sits under the page's root, for the indentation of its line: 0 for a top-level input or the result itself.", required = true }
130
+ path = { type = "text", description = "The path, spelled exactly as the page binds or reads it: absolute (`/inputs/request/city`), or relative to one item of the list above when `relative` is set (`city`, or `teams/<i>/name` inside a nested list).", required = true }
131
+ kind = { type = "text", description = "What the path holds, in words: `text`, `number`, `integer`, `boolean`, `date`, `prose (markdown)`, `choice of \"a\" | \"b\"`, `document (a file)`, `image (a file)`, `structure <concept>`, `list of <kind>`, or the native concept it carries.", required = true }
132
+ name = { type = "text", description = "The member's name as the method spells it. Absent on the result's own root entry, which is the whole result." }
133
+ title = { type = "text", description = "The member's human title, when the method gives one that differs from its name." }
134
+ description = { type = "text", description = "What the member is for, as the method's author wrote it." }
135
+ required = { type = "boolean", description = "On an input page, whether the input must be filled before the run: true for a required input, false for an optional one." }
136
+ gating = { type = "boolean", description = "On an input page, true when the run waits for this input - a top-level fact only." }
137
+ notes = { type = "list", item_type = "text", description = "The constraints and hints in words, each on its own: `min 1`, `at most 80 characters`, `default \"x\"`, `examples ...`, `hints intent=label`." }
138
+ default = { type = "text", description = "The authored default value, as JSON, when the method states one - the seed a `/state` patch sets." }
139
+ delegated = { type = "boolean", description = "True when the page hands the path back to the kernel's own control - MthdsField on an input page, MthdsResult on a result page - because the catalog cannot enter or show it. A delegated structure's members are not listed.", required = true }
140
+ relative = { type = "boolean", description = "True when the path is spelled relative to one item of the list above it, as a DataTable column or `$item` reads it, rather than from the page's root." }
141
+ item_kind = { type = "text", description = "On a list whose items the brief describes: what one item holds, in the same words as `kind`." }
142
+ item_description = { type = "text", description = "On a list whose items the brief describes: what one item is for, as the method's author wrote it." }
143
+ item_laid_out = { type = "boolean", description = "On a list whose items the brief describes: true when the item's members follow this entry, one each, spelled relative to one item." }
144
+
93
145
  [concept.PagePlan]
94
146
  description = "The designer's plan for one page, settled before any element is written: what the page is for, how it is composed - a decision the plan makes, with no shape given in advance - what each region shows or collects and with which components, what runs the method, and what is delegated."
95
147
 
@@ -111,20 +163,116 @@ purpose = { type = "text", description = "What this region shows or collects,
111
163
  container = { type = "text", description = "The component the region is built with, by its catalog name, when the composition has settled it; otherwise empty, and the builder chooses one that builds what the composition describes." }
112
164
  elements = { type = "list", item_type = "text", description = "The elements inside it in order, one line each: the component by its catalog name, the path it binds or reads spelled exactly as the brief lists it, and the choices it lists when it lists any. A container names what it holds.", required = true }
113
165
 
114
- [pipe.ui_designer]
166
+ [pipe.design_layout]
115
167
  type = "PipeSequence"
116
- description = "Design one page from the catalog and the brief: plan it, then build it as the JSONL patches of a spec bound to the host's state."
117
- inputs = { catalog = "Catalog", brief = "Text", seed = "Text?" }
168
+ description = "Design one page from the catalog and the brief: lay the brief out, plan the page from it, then build it as the JSONL patches of a spec bound to the host's state."
169
+ inputs = { catalog = "Catalog", brief = "Brief", seed = "Text?" }
118
170
  output = "Text"
119
171
  steps = [
172
+ { pipe = "render_brief", result = "brief_text" },
120
173
  { pipe = "plan_page", result = "plan" },
121
174
  { pipe = "emit_page", result = "page" },
122
175
  ]
123
176
 
177
+ [pipe.render_brief]
178
+ type = "PipeCompose"
179
+ description = "Lay the brief out as the Markdown both model stages read: the page and its pipe, the state and every path in it, what is delegated, and - on an input page - the defaults and what runs the method, or - on a result page - the state of one real run."
180
+ inputs = { brief = "Brief" }
181
+ output = "Text"
182
+
183
+ [pipe.render_brief.template]
184
+ category = "markdown"
185
+ template = """
186
+ {% set hatch = "MthdsField" if brief.side == "input" else "MthdsResult" %}
187
+ {% set delegated = brief.paths | selectattr("delegated") | rejectattr("relative") | list %}
188
+ {% set defaults = brief.paths | selectattr("default") | list %}
189
+ {% set gating = brief.paths | selectattr("gating") | list %}
190
+ # {{ "Input" if brief.side == "input" else "Result" }} page: {{ brief.pipe_ref }}
191
+
192
+ {% if brief.description %}
193
+ {{ brief.description }}
194
+ {% elif brief.side == "input" %}
195
+ A method with the inputs below.
196
+ {% else %}
197
+ The result of a method, described below.
198
+ {% endif %}
199
+
200
+ {% if brief.name %}
201
+ ## Name
202
+
203
+ The method is called «{{ brief.name }}», as the host lists it. That is the app's name wherever the layout asks for one; invent no other. Links, if the layout carries any, name this page's own sections. The page states nothing the method does not: no promise about storage, privacy, speed, or what happens after the run.
204
+
205
+ {% endif %}
206
+ ## State
207
+
208
+ {% if brief.side == "input" %}
209
+ The form's values live under `/inputs`, one member per input, exactly as listed. Bind each input with `$$bindState` at its path; a structure's members bind at their own paths beneath it.
210
+ {% else %}
211
+ The host loads the run's result under `/result` before the page renders. Read every value with `$$state`; emit no `/state` patches. Paths:
212
+ {% endif %}
213
+
214
+ {% for entry in brief.paths %}
215
+ {{ " " * entry.depth }}- `{{ entry.path }}` — {{ entry.kind }}{% if brief.side == "input" %}, {{ "required" if entry.required else "optional" }}{% if entry.gating %}, gates the run{% endif %}{% endif %}{% if entry.name %} — {% if entry.title %}{{ entry.title }} (`{{ entry.name }}`){% else %}`{{ entry.name }}`{% endif %}{% endif %}{% if entry.description %}: {{ entry.description }}{% endif %}{% if entry.notes %} ({{ entry.notes | join("; ") }}){% endif %}{% if entry.delegated and entry.relative %} (a DataTable prints it as text; delegate the whole list to {{ hatch }} to render it properly){% elif entry.delegated %} **[delegate: {{ hatch }}]**{% endif +%}
216
+ {% if entry.item_kind %}
217
+ {{ " " * (entry.depth + 1) }}- each item is a {{ entry.item_kind }}{% if entry.item_description %} ({{ entry.item_description }}){% endif %}{% if entry.item_laid_out and entry.relative %}, with:{% elif entry.item_laid_out %}, with these members (paths relative to one item, for DataTable columns or $$item):{% endif +%}
218
+ {% endif %}
219
+ {% endfor %}
220
+
221
+ ## Delegated
222
+
223
+ {% if delegated %}
224
+ {% if brief.side == "input" %}
225
+ Render these with `MthdsField` at the path, and nothing else:
226
+ {% else %}
227
+ Render these with `MthdsResult` at the path - they are kinds the catalog cannot show properly:
228
+ {% endif %}
229
+
230
+ {% for entry in delegated %}
231
+ - `{{ entry.path }}` ({{ entry.kind }})
232
+ {% endfor %}
233
+ {% elif brief.side == "input" %}
234
+ None: every input can be entered with the catalog's own inputs. `MthdsField` remains available for any you would rather not style.
235
+ {% else %}
236
+ None. `MthdsResult` remains available for any structure you choose not to lay out.
237
+ {% endif %}
238
+ {% if brief.side == "input" %}
239
+
240
+ ## Defaults
241
+
242
+ {% if defaults %}
243
+ Seed these, and only these, with `/state` patches (`{"op":"add","path":"/state/inputs/...","value":...}`):
244
+
245
+ {% for entry in defaults %}
246
+ - `{{ entry.path }}` = {{ entry.default }}
247
+ {% endfor %}
248
+ {% else %}
249
+ None. Emit no `/state` patches.
250
+ {% endif %}
251
+
252
+ ## Run
253
+
254
+ {% if gating %}
255
+ The run waits for `{{ gating | map(attribute="name") | join("`, `") }}`; say so near the {{ brief.run_control }}, briefly.
256
+ {% else %}
257
+ Nothing gates the run.
258
+ {% endif %}
259
+ The page has exactly one `{{ brief.run_control }}`, `on.press` bound to `validateForm` then `run`; label it with what the method does, in a person's words.
260
+ {% else %}
261
+
262
+ ## One real run, as loaded
263
+
264
+ The state of one actual run, so you can judge magnitudes and lengths. Bind to the paths; do not copy these values into the spec.
265
+
266
+ ```json
267
+ {{ brief.sample_state }}
268
+ ```
269
+ {% endif %}
270
+ """
271
+
124
272
  [pipe.plan_page]
125
273
  type = "PipeLLM"
126
274
  description = "Read the brief and plan the page: what it is for, how it is composed, what each region holds and with which components, what runs the method, and what is delegated."
127
- inputs = { catalog = "Catalog", brief = "Text", seed = "Text?" }
275
+ inputs = { catalog = "Catalog", brief_text = "Text", seed = "Text?" }
128
276
  output = "PagePlan"
129
277
  model = { model = "claude-5-sonnet", temperature = 0.5, max_tokens = 8192 }
130
278
  system_prompt = """
@@ -173,7 +321,7 @@ Never show, quote or mention the seed. Two designers given different seeds must
173
321
 
174
322
  Below is the brief for the page you are planning. It is the ONLY source of paths: every value the page shows or binds must be at a path the brief lists, spelled exactly as written.
175
323
 
176
- @brief
324
+ @brief_text
177
325
 
178
326
  ---
179
327
 
@@ -187,7 +335,7 @@ Plan this page.
187
335
  [pipe.emit_page]
188
336
  type = "PipeLLM"
189
337
  description = "Build the page the plan describes: emit the JSONL patches of a spec over the catalog, bound to the host's state at the paths the brief lists."
190
- inputs = { plan = "PagePlan", catalog = "Catalog", brief = "Text" }
338
+ inputs = { plan = "PagePlan", catalog = "Catalog", brief_text = "Text" }
191
339
  output = "Text"
192
340
  # The object form, because the default output cap (4096 tokens on this model)
193
341
  # is not enough for a page over a deeply nested result: the Company hero's
@@ -296,7 +444,7 @@ RULES:
296
444
 
297
445
  Below is the brief for the page you are building. It is the ONLY source of paths: every value you show or bind must be at a path the brief lists, spelled exactly as written.
298
446
 
299
- @brief
447
+ @brief_text
300
448
 
301
449
  ---
302
450
 
@@ -6,6 +6,7 @@ import { BooleanRunField, DateRunField, EnumRunField, FileRunField, ListRunField
6
6
  import { HtmlContentView } from '../core/native-content.js';
7
7
  import '../core/contracts.js';
8
8
  import 'mthds/protocol';
9
+ import '../core/file-formats.js';
9
10
 
10
11
  interface BooleanFieldProps {
11
12
  field: BooleanRunField;
@@ -48,6 +49,14 @@ interface EnumFieldProps {
48
49
  * Pick-one. A short option set (≤4, each label brief) renders as a segmented
49
50
  * control - every choice visible at a glance - and falls back to a select once
50
51
  * the set grows past what fits on a row.
52
+ *
53
+ * An option's LABEL follows the presentation and its value does not. In `app`
54
+ * a person picks "Unit price differs from po" and the form stores
55
+ * `unit_price_differs_from_po`, because the result that run produces shows the
56
+ * same field in words too, and a form and its result have to read the same
57
+ * way - which is why both apply one rule, including its fallback to the codes
58
+ * when two options would read the same. The segmented rule measures the label
59
+ * it shows, which is the text that has to fit on the row.
51
60
  */
52
61
  declare function EnumField({ field, value, onChange, id, error, disabled }: EnumFieldProps): react.JSX.Element;
53
62
 
@@ -377,8 +386,24 @@ interface ResultEnv {
377
386
  resolveUrl?: ResolveUrl;
378
387
  resolveShareUrl?: ResolveShareUrl;
379
388
  proseImages?: ProseImages;
389
+ /**
390
+ * How many data columns a table of records shows. Five when unset.
391
+ *
392
+ * A record with more fields than this keeps the columns a reader decides on —
393
+ * its name first, then the values that fit a cell whole — and the rest move
394
+ * into the row's detail, one click away. The columns shown keep the order the
395
+ * method's author wrote them in. A record within the budget shows every field.
396
+ *
397
+ * It is a COUNT rather than a width the view measures, and that is the point:
398
+ * a count renders the same table on a server, in a test and in a browser,
399
+ * where a measured budget would change the table's shape after hydration, and
400
+ * differently from one host to the next. A host that knows its panel is wide
401
+ * raises it; `Infinity` shows every column. A value below one reads as one,
402
+ * which is the record's name alone.
403
+ */
404
+ tableColumns?: number;
380
405
  }
381
- declare function ResultEnvProvider({ resolveUrl, resolveShareUrl, proseImages, children, }: ResultEnv & {
406
+ declare function ResultEnvProvider({ resolveUrl, resolveShareUrl, proseImages, tableColumns, children, }: ResultEnv & {
382
407
  children: ReactNode;
383
408
  }): react.JSX.Element;
384
409
  /**
@@ -506,7 +531,28 @@ interface FieldStrings {
506
531
  dropToUpload: string;
507
532
  dropOrBrowse: string;
508
533
  pasteUrlInstead: string;
534
+ /**
535
+ * The placeholder in the URL a person may paste instead of uploading. It names
536
+ * the web's own scheme only: a host whose runner also takes its own storage
537
+ * references can say so by overriding it, and no default shows an end user a
538
+ * platform's storage scheme.
539
+ */
509
540
  urlPlaceholder: string;
541
+ /**
542
+ * The accessible name of that URL input, given the field's label as the form
543
+ * shows it. The field's label is bound to the file input, so without this the
544
+ * placeholder was the only thing a screen reader announced here.
545
+ *
546
+ * The label is EMPTY inside a list row: the list drops each row's label, and
547
+ * the row number it shows instead is a bare glyph tied to no control. So every
548
+ * row's input currently carries the same generic name, and giving rows
549
+ * distinct names is a separate piece of work on the list control.
550
+ */
551
+ fileUrlAria: (label: string) => string;
552
+ /**
553
+ * The title of an attached file's card when the value carries no filename.
554
+ * True of a pasted link as well as of an upload, which "Uploaded file" was not.
555
+ */
510
556
  uploadedFile: string;
511
557
  /**
512
558
  * What names a file carried INSIDE its own URL (a `data:` URL), where a
@@ -560,10 +606,11 @@ interface FieldStrings {
560
606
  no: string;
561
607
  /**
562
608
  * Shown when a picked file is not a format this slot accepts. Takes the
563
- * accept label so the message names what WOULD have worked - "not accepted"
564
- * on its own leaves the user guessing at the list they just failed.
609
+ * slot's own formats as the hint names them (`PNG, JPG`), after any narrowing
610
+ * a host applied, so the message names what WOULD have worked - "not
611
+ * accepted" on its own leaves the user guessing at the list they just failed.
565
612
  */
566
- unsupportedFileType: (accept: string) => string;
613
+ unsupportedFileType: (formats: string) => string;
567
614
  /** The optional-entries disclosure ("field" inside a concept, "input" at top level). */
568
615
  hideOptionalFields: string;
569
616
  hideOptionalInputs: string;
@@ -598,19 +645,28 @@ declare function FieldDomIdProvider({ prefix, children, }: {
598
645
  declare function useFieldDomId(path: string): string;
599
646
 
600
647
  /**
601
- * How a field's LABEL chrome should read. The control itself never changes.
648
+ * How a field's LABEL chrome, and the enum values a person reads, should read.
649
+ * What a control stores never changes.
602
650
  *
603
651
  * - `studio` (default): the field's name verbatim in mono, with its concept
604
652
  * pill. The name IS the identifier a builder writes in the `.mthds` file, so
605
- * showing it exactly - and typed - is the point.
653
+ * showing it exactly - and typed - is the point. An enum value is shown as its
654
+ * code for the same reason: it has to match the bundle and the JSON the
655
+ * builder reads next.
606
656
  * - `app`: the field's name as a human question in sans, no concept pill. Inside
607
657
  * a method app, `full_name` and `native.Text` are implementation detail; the
608
- * person filling the form has never seen the method's source.
658
+ * person filling the form has never seen the method's source. An enum value
659
+ * follows the label and reads as words.
660
+ *
661
+ * An enum value is the only value the two presentations show differently. A
662
+ * number, a text, a date and every other value render the same in both.
609
663
  *
610
664
  * Deliberately a context rather than a prop or a `FieldEnv` flag: only the
611
- * components that own label chrome read it - `FieldShell`, `ObjectField`,
612
- * `BooleanField` and `ListField` - and threading a prop would have meant
613
- * editing every field control and both recursive containers.
665
+ * components that own label chrome or an enum value's wording read it -
666
+ * `FieldShell`, `ObjectField`, `BooleanField`, `ListField`, `EnumField` and the
667
+ * result view - plus the file control, whose card hides a storage reference in
668
+ * `app`, and threading a prop would have meant editing every field control and
669
+ * both recursive containers.
614
670
  */
615
671
  type FieldPresentation = 'studio' | 'app';
616
672
  declare function FieldPresentationProvider({ presentation, children, }: {
@@ -1,9 +1,9 @@
1
1
  "use client";
2
- export { BooleanField, ConceptPill, DEFAULT_FIELD_STRINGS, DateField, DocumentField, EnumField, FieldDomIdProvider, FieldPresentationProvider, FieldRenderer, FieldShell, FieldStringsProvider, HtmlPreview, ImageField, JsonView, ListField, Markdown, NumberField, ObjectField, OptionalToggle, ProseField, ResultEnvProvider, ResultField, StuffViewer, TextField, UnknownField, downloadStuff, fieldControlClass, humanizeFieldName, useFieldDomId, useFieldPresentation, useFieldStrings, useProseImages, useResolveShareUrl, useResolveUrl, useResolvedUrl } from '../chunk-KG4IYFWI.js';
3
- import '../chunk-S4CB423P.js';
4
- import '../chunk-AZZAAGNX.js';
5
- import '../chunk-25I6JDIK.js';
6
- import '../chunk-2JWRG53S.js';
2
+ export { BooleanField, ConceptPill, DEFAULT_FIELD_STRINGS, DateField, DocumentField, EnumField, FieldDomIdProvider, FieldPresentationProvider, FieldRenderer, FieldShell, FieldStringsProvider, HtmlPreview, ImageField, JsonView, ListField, Markdown, NumberField, ObjectField, OptionalToggle, ProseField, ResultEnvProvider, ResultField, StuffViewer, TextField, UnknownField, downloadStuff, fieldControlClass, humanizeFieldName, useFieldDomId, useFieldPresentation, useFieldStrings, useProseImages, useResolveShareUrl, useResolveUrl, useResolvedUrl } from '../chunk-W56WIIVC.js';
3
+ import '../chunk-4JQAJT7C.js';
4
+ import '../chunk-TID7ZN63.js';
5
+ import '../chunk-FABY3DEY.js';
6
+ import '../chunk-XCO6GTEC.js';
7
7
  import '../chunk-PM55AHRO.js';
8
8
  import '../chunk-GKV77RAS.js';
9
9
  import '../chunk-V3OV2XQT.js';