@fieldia/core 0.28.0 → 0.30.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.
Files changed (251) hide show
  1. package/README.md +125 -1
  2. package/package.json +1 -1
  3. package/schema/page.schema.json +279 -6
  4. package/src/index.d.mts +8 -2
  5. package/src/index.d.ts +8 -2
  6. package/src/index.js +29 -2
  7. package/src/index.js.map +1 -1
  8. package/src/index.mjs +11 -2
  9. package/src/index.mjs.map +1 -1
  10. package/src/lib/format/approval-checks.d.mts +8 -0
  11. package/src/lib/format/approval-checks.d.ts +8 -0
  12. package/src/lib/format/approval-checks.js +29 -0
  13. package/src/lib/format/approval-checks.js.map +1 -0
  14. package/src/lib/format/approval-checks.mjs +26 -0
  15. package/src/lib/format/approval-checks.mjs.map +1 -0
  16. package/src/lib/format/approval.d.mts +20 -0
  17. package/src/lib/format/approval.d.ts +20 -0
  18. package/src/lib/format/approval.js +25 -0
  19. package/src/lib/format/approval.js.map +1 -0
  20. package/src/lib/format/approval.mjs +22 -0
  21. package/src/lib/format/approval.mjs.map +1 -0
  22. package/src/lib/format/assist-checks.d.mts +14 -0
  23. package/src/lib/format/assist-checks.d.ts +14 -0
  24. package/src/lib/format/assist-checks.js +68 -0
  25. package/src/lib/format/assist-checks.js.map +1 -0
  26. package/src/lib/format/assist-checks.mjs +64 -0
  27. package/src/lib/format/assist-checks.mjs.map +1 -0
  28. package/src/lib/format/assist.d.mts +41 -0
  29. package/src/lib/format/assist.d.ts +41 -0
  30. package/src/lib/format/assist.js +29 -0
  31. package/src/lib/format/assist.js.map +1 -0
  32. package/src/lib/format/assist.mjs +26 -0
  33. package/src/lib/format/assist.mjs.map +1 -0
  34. package/src/lib/format/editable-checks.d.mts +8 -0
  35. package/src/lib/format/editable-checks.d.ts +8 -0
  36. package/src/lib/format/editable-checks.js +38 -0
  37. package/src/lib/format/editable-checks.js.map +1 -0
  38. package/src/lib/format/editable-checks.mjs +35 -0
  39. package/src/lib/format/editable-checks.mjs.map +1 -0
  40. package/src/lib/format/field.d.mts +86 -0
  41. package/src/lib/format/field.d.ts +86 -0
  42. package/src/lib/format/field.js +56 -10
  43. package/src/lib/format/field.js.map +1 -1
  44. package/src/lib/format/field.mjs +55 -9
  45. package/src/lib/format/field.mjs.map +1 -1
  46. package/src/lib/format/head-checks.d.mts +10 -2
  47. package/src/lib/format/head-checks.d.ts +10 -2
  48. package/src/lib/format/head-checks.js +9 -2
  49. package/src/lib/format/head-checks.js.map +1 -1
  50. package/src/lib/format/head-checks.mjs +10 -4
  51. package/src/lib/format/head-checks.mjs.map +1 -1
  52. package/src/lib/format/languages-checks.d.mts +8 -0
  53. package/src/lib/format/languages-checks.d.ts +8 -0
  54. package/src/lib/format/languages-checks.js +40 -0
  55. package/src/lib/format/languages-checks.js.map +1 -0
  56. package/src/lib/format/languages-checks.mjs +37 -0
  57. package/src/lib/format/languages-checks.mjs.map +1 -0
  58. package/src/lib/format/later-checks.d.mts +4 -3
  59. package/src/lib/format/later-checks.d.ts +4 -3
  60. package/src/lib/format/later-checks.js +4 -3
  61. package/src/lib/format/later-checks.js.map +1 -1
  62. package/src/lib/format/later-checks.mjs +4 -3
  63. package/src/lib/format/later-checks.mjs.map +1 -1
  64. package/src/lib/format/layout.d.mts +129 -26
  65. package/src/lib/format/layout.d.ts +129 -26
  66. package/src/lib/format/layout.js +24 -3
  67. package/src/lib/format/layout.js.map +1 -1
  68. package/src/lib/format/layout.mjs +22 -1
  69. package/src/lib/format/layout.mjs.map +1 -1
  70. package/src/lib/format/layout.types.d.mts +2 -1
  71. package/src/lib/format/layout.types.d.ts +2 -1
  72. package/src/lib/format/list-editable.d.mts +20 -0
  73. package/src/lib/format/list-editable.d.ts +20 -0
  74. package/src/lib/format/list-editable.js +33 -0
  75. package/src/lib/format/list-editable.js.map +1 -0
  76. package/src/lib/format/list-editable.mjs +28 -0
  77. package/src/lib/format/list-editable.mjs.map +1 -0
  78. package/src/lib/format/page.d.mts +88 -9
  79. package/src/lib/format/page.d.ts +88 -9
  80. package/src/lib/format/page.js +4 -0
  81. package/src/lib/format/page.js.map +1 -1
  82. package/src/lib/format/page.mjs +4 -0
  83. package/src/lib/format/page.mjs.map +1 -1
  84. package/src/lib/format/photos-options.d.mts +29 -0
  85. package/src/lib/format/photos-options.d.ts +29 -0
  86. package/src/lib/format/photos-options.js +49 -0
  87. package/src/lib/format/photos-options.js.map +1 -0
  88. package/src/lib/format/photos-options.mjs +45 -0
  89. package/src/lib/format/photos-options.mjs.map +1 -0
  90. package/src/lib/format/references.d.mts +3 -1
  91. package/src/lib/format/references.d.ts +3 -1
  92. package/src/lib/format/references.js +41 -14
  93. package/src/lib/format/references.js.map +1 -1
  94. package/src/lib/format/references.mjs +42 -15
  95. package/src/lib/format/references.mjs.map +1 -1
  96. package/src/lib/format/scan-checks.d.mts +12 -0
  97. package/src/lib/format/scan-checks.d.ts +12 -0
  98. package/src/lib/format/scan-checks.js +89 -0
  99. package/src/lib/format/scan-checks.js.map +1 -0
  100. package/src/lib/format/scan-checks.mjs +86 -0
  101. package/src/lib/format/scan-checks.mjs.map +1 -0
  102. package/src/lib/format/scan-options.d.mts +84 -0
  103. package/src/lib/format/scan-options.d.ts +84 -0
  104. package/src/lib/format/scan-options.js +58 -0
  105. package/src/lib/format/scan-options.js.map +1 -0
  106. package/src/lib/format/scan-options.mjs +54 -0
  107. package/src/lib/format/scan-options.mjs.map +1 -0
  108. package/src/lib/format/sheet-head-checks.d.mts +10 -2
  109. package/src/lib/format/sheet-head-checks.d.ts +10 -2
  110. package/src/lib/format/sheet-head-checks.js +24 -0
  111. package/src/lib/format/sheet-head-checks.js.map +1 -1
  112. package/src/lib/format/sheet-head-checks.mjs +23 -0
  113. package/src/lib/format/sheet-head-checks.mjs.map +1 -1
  114. package/src/lib/format/upgrade.d.mts +6 -2
  115. package/src/lib/format/upgrade.d.ts +6 -2
  116. package/src/lib/format/upgrade.js +6 -2
  117. package/src/lib/format/upgrade.js.map +1 -1
  118. package/src/lib/format/upgrade.mjs +6 -2
  119. package/src/lib/format/upgrade.mjs.map +1 -1
  120. package/src/lib/format/version.d.mts +2 -2
  121. package/src/lib/format/version.d.ts +2 -2
  122. package/src/lib/format/version.js +2 -2
  123. package/src/lib/format/version.js.map +1 -1
  124. package/src/lib/format/version.mjs +2 -2
  125. package/src/lib/format/version.mjs.map +1 -1
  126. package/src/lib/record/approvals-part.d.mts +6 -0
  127. package/src/lib/record/approvals-part.d.ts +6 -0
  128. package/src/lib/record/approvals-part.js +14 -0
  129. package/src/lib/record/approvals-part.js.map +1 -0
  130. package/src/lib/record/approvals-part.mjs +7 -0
  131. package/src/lib/record/approvals-part.mjs.map +1 -0
  132. package/src/lib/record/approving.d.mts +45 -0
  133. package/src/lib/record/approving.d.ts +45 -0
  134. package/src/lib/record/approving.js +10 -0
  135. package/src/lib/record/approving.js.map +1 -0
  136. package/src/lib/record/approving.mjs +7 -0
  137. package/src/lib/record/approving.mjs.map +1 -0
  138. package/src/lib/record/check.js +4 -0
  139. package/src/lib/record/check.js.map +1 -1
  140. package/src/lib/record/check.mjs +4 -0
  141. package/src/lib/record/check.mjs.map +1 -1
  142. package/src/lib/record/data-source.d.mts +270 -0
  143. package/src/lib/record/data-source.d.ts +270 -0
  144. package/src/lib/record/data-source.js.map +1 -1
  145. package/src/lib/record/data-source.mjs.map +1 -1
  146. package/src/lib/record/files-part.d.mts +7 -0
  147. package/src/lib/record/files-part.d.ts +7 -0
  148. package/src/lib/record/files-part.js +167 -0
  149. package/src/lib/record/files-part.js.map +1 -0
  150. package/src/lib/record/files-part.mjs +163 -0
  151. package/src/lib/record/files-part.mjs.map +1 -0
  152. package/src/lib/record/filter.d.mts +5 -0
  153. package/src/lib/record/filter.d.ts +5 -0
  154. package/src/lib/record/filter.js +1 -0
  155. package/src/lib/record/filter.js.map +1 -1
  156. package/src/lib/record/filter.mjs +1 -1
  157. package/src/lib/record/filter.mjs.map +1 -1
  158. package/src/lib/record/form-approvals.d.mts +47 -0
  159. package/src/lib/record/form-approvals.d.ts +47 -0
  160. package/src/lib/record/form-approvals.js +186 -0
  161. package/src/lib/record/form-approvals.js.map +1 -0
  162. package/src/lib/record/form-approvals.mjs +180 -0
  163. package/src/lib/record/form-approvals.mjs.map +1 -0
  164. package/src/lib/record/form.d.mts +32 -1
  165. package/src/lib/record/form.d.ts +32 -1
  166. package/src/lib/record/form.js +60 -15
  167. package/src/lib/record/form.js.map +1 -1
  168. package/src/lib/record/form.mjs +60 -15
  169. package/src/lib/record/form.mjs.map +1 -1
  170. package/src/lib/record/languages-part.d.mts +32 -0
  171. package/src/lib/record/languages-part.d.ts +32 -0
  172. package/src/lib/record/languages-part.js +104 -0
  173. package/src/lib/record/languages-part.js.map +1 -0
  174. package/src/lib/record/languages-part.mjs +96 -0
  175. package/src/lib/record/languages-part.mjs.map +1 -0
  176. package/src/lib/record/languages.d.mts +26 -0
  177. package/src/lib/record/languages.d.ts +26 -0
  178. package/src/lib/record/languages.js +20 -0
  179. package/src/lib/record/languages.js.map +1 -0
  180. package/src/lib/record/languages.mjs +15 -0
  181. package/src/lib/record/languages.mjs.map +1 -0
  182. package/src/lib/record/locales/ar.js +5 -0
  183. package/src/lib/record/locales/ar.js.map +1 -1
  184. package/src/lib/record/locales/ar.mjs +5 -0
  185. package/src/lib/record/locales/ar.mjs.map +1 -1
  186. package/src/lib/record/locales/de.js +5 -0
  187. package/src/lib/record/locales/de.js.map +1 -1
  188. package/src/lib/record/locales/de.mjs +5 -0
  189. package/src/lib/record/locales/de.mjs.map +1 -1
  190. package/src/lib/record/locales/fr.js +5 -0
  191. package/src/lib/record/locales/fr.js.map +1 -1
  192. package/src/lib/record/locales/fr.mjs +5 -0
  193. package/src/lib/record/locales/fr.mjs.map +1 -1
  194. package/src/lib/record/memory-approvals.d.mts +47 -0
  195. package/src/lib/record/memory-approvals.d.ts +47 -0
  196. package/src/lib/record/memory-approvals.js +78 -0
  197. package/src/lib/record/memory-approvals.js.map +1 -0
  198. package/src/lib/record/memory-approvals.mjs +75 -0
  199. package/src/lib/record/memory-approvals.mjs.map +1 -0
  200. package/src/lib/record/memory-assist.d.mts +53 -0
  201. package/src/lib/record/memory-assist.d.ts +53 -0
  202. package/src/lib/record/memory-assist.js +519 -0
  203. package/src/lib/record/memory-assist.js.map +1 -0
  204. package/src/lib/record/memory-assist.mjs +513 -0
  205. package/src/lib/record/memory-assist.mjs.map +1 -0
  206. package/src/lib/record/memory-clusters.d.mts +18 -0
  207. package/src/lib/record/memory-clusters.d.ts +18 -0
  208. package/src/lib/record/memory-clusters.js +83 -0
  209. package/src/lib/record/memory-clusters.js.map +1 -0
  210. package/src/lib/record/memory-clusters.mjs +80 -0
  211. package/src/lib/record/memory-clusters.mjs.map +1 -0
  212. package/src/lib/record/memory-data-source.d.mts +43 -3
  213. package/src/lib/record/memory-data-source.d.ts +43 -3
  214. package/src/lib/record/memory-data-source.js +105 -19
  215. package/src/lib/record/memory-data-source.js.map +1 -1
  216. package/src/lib/record/memory-data-source.mjs +105 -19
  217. package/src/lib/record/memory-data-source.mjs.map +1 -1
  218. package/src/lib/record/memory-later.d.mts +1 -1
  219. package/src/lib/record/memory-later.d.ts +1 -1
  220. package/src/lib/record/memory-later.js +4 -1
  221. package/src/lib/record/memory-later.js.map +1 -1
  222. package/src/lib/record/memory-later.mjs +4 -1
  223. package/src/lib/record/memory-later.mjs.map +1 -1
  224. package/src/lib/record/messages.d.mts +14 -0
  225. package/src/lib/record/messages.d.ts +14 -0
  226. package/src/lib/record/messages.js +5 -0
  227. package/src/lib/record/messages.js.map +1 -1
  228. package/src/lib/record/messages.mjs +5 -0
  229. package/src/lib/record/messages.mjs.map +1 -1
  230. package/src/lib/record/run.d.mts +6 -1
  231. package/src/lib/record/run.d.ts +6 -1
  232. package/src/lib/record/run.js.map +1 -1
  233. package/src/lib/record/run.mjs.map +1 -1
  234. package/src/lib/record/uploads.d.mts +35 -9
  235. package/src/lib/record/uploads.d.ts +35 -9
  236. package/src/lib/record/uploads.js +49 -169
  237. package/src/lib/record/uploads.js.map +1 -1
  238. package/src/lib/record/uploads.mjs +42 -164
  239. package/src/lib/record/uploads.mjs.map +1 -1
  240. package/src/lib/record/values.d.mts +23 -0
  241. package/src/lib/record/values.d.ts +23 -0
  242. package/src/lib/record/values.js +4 -0
  243. package/src/lib/record/values.js.map +1 -1
  244. package/src/lib/record/values.mjs +4 -0
  245. package/src/lib/record/values.mjs.map +1 -1
  246. package/src/runtime.d.mts +12 -5
  247. package/src/runtime.d.ts +12 -5
  248. package/src/runtime.js +18 -3
  249. package/src/runtime.js.map +1 -1
  250. package/src/runtime.mjs +7 -1
  251. package/src/runtime.mjs.map +1 -1
package/README.md CHANGED
@@ -28,7 +28,7 @@ list of records — that your app implements;
28
28
  The page format is also a JSON Schema, for editors and other languages:
29
29
  `@fieldia/core/page.schema.json`.
30
30
 
31
- A page says which format it is written in (`"fieldia": "0.7"`, `FORMAT_VERSION`; a page in 0.1, 0.2, 0.3, 0.4, 0.5 or 0.6 is read as it is).
31
+ A page says which format it is written in (`"fieldia": "0.9"`, `FORMAT_VERSION`; a page in 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7 or 0.8 is read as it is).
32
32
  One in an older format is brought up to date as it is read — by `checkPage`,
33
33
  `validatePage` and `createForm`, so by the viewer and the designer too — and
34
34
  `upgradePage` does it for the pages your app keeps. One newer than this Fieldia
@@ -204,6 +204,33 @@ carries no options from a question: its own, or one of the app's lists — the s
204
204
  `optionsFrom` as a page's own choice (`{ list, dependsOn }`, its `dependsOn` naming
205
205
  the line's columns or `parent.` and a field).
206
206
 
207
+ ## One text in several languages
208
+
209
+ A line, a paragraph or formatted text may keep its text in several languages, each
210
+ typed by a person — Fieldia never translates it (`translate`), and `requiredIn` says
211
+ which a required answer is typed in (every one when left out):
212
+
213
+ ```json
214
+ "title": { "type": "char", "label": "Title", "translate": ["ar", "en"], "required": true, "size": 80 },
215
+ "description": { "type": "text", "label": "Description", "translate": ["ar", "en"], "required": true, "requiredIn": ["en"] }
216
+ ```
217
+
218
+ Its value is an object of each language's text by its tag — `{ "ar": "شقة…", "en":
219
+ "Nile-view flat" }` — a language not typed yet left out, none typed `null`; a plain
220
+ text loaded for it is read as its first language's. The form checks it in each
221
+ language: "Title is required in Arabic" while it is typed in some (`languagesNeeded`,
222
+ or `languagesNeededQuestion` for a label that asks), "Title is required" in none;
223
+ each language held to the field's `size` and `pattern`, named in the problem ("Title
224
+ (English) is 4 characters too long: shorten it to 80"). `textIn(value, reader,
225
+ languages)` reads it as a reader of a language does — theirs where typed, else the
226
+ field's first typed, said to be another's — `languageName(tag, locale)` names a
227
+ language, `checkTranslated` and `languagesAtFault` check it. They come in the
228
+ languages part (`formLanguagesPart`), which a form with such a field asks for as it
229
+ is made and a save waits for; `languagesOf(field)` and `hasLanguages(page)` say
230
+ whether a page has one. A table's line keeps one language. The memory source finds
231
+ such a text by a search in any of its languages, and reads one text — a link's
232
+ name, a list's order — in its `language` option's.
233
+
207
234
  ## A public form's bot check
208
235
 
209
236
  A page of responses anyone may send — a sign-up, a contact form — can check that
@@ -300,6 +327,10 @@ record (`model` and `recordId` are the record's, `field` is where it sits:
300
327
  `consent.deed`), and the record's save waits for them. A file picked while a save
301
328
  is on its way stays a change, to save next. A draft never keeps a file's bytes
302
329
  where the source has `upload`; without it, a draft keeps them, as before.
330
+ The sending itself — each file made ready and sent, its link put in its field —
331
+ is a part of its own (`formUploadsPart`), which comes with @fieldia/widgets'
332
+ files part, or the first time a form sends a file: `form.upload` gives its ids
333
+ at once, each file waiting its turn until the part is in.
303
334
 
304
335
  ```ts
305
336
  import { uploadTo } from '@fieldia/core';
@@ -317,6 +348,16 @@ your words and offers no Retry; any other error offers Retry. Stop with an
317
348
  one. Without `upload`, files travel inside the record as base64, as before.
318
349
  See [files stored as they are picked](https://fieldia.dev/data/#upload).
319
350
 
351
+ A photo set (`"widget": "photos"`, @fieldia/widgets' README) keeps everything in
352
+ the field's value, so any source that keeps a file value keeps it: the photos in
353
+ the order a person put them (the first the cover), a photo's `caption`, and for a
354
+ photo cropped or turned the photo as it was (`original`, a file value of its
355
+ own) and what was done to it (`edit`: `{ turn: 90, crop: { x, y, width, height }
356
+ }`, fractions of the turned original). A photo cropped is stored at once —
357
+ `form.upload(field, [file], { replaces })`: its link takes the place of the
358
+ bytes the field holds for it, with whatever stands beside them by then (a
359
+ caption typed meanwhile).
360
+
320
361
  ## Lists that add up, and filter by time
321
362
 
322
363
  A list asks its source's optional `totals({ model, filter, totals, groupBy?,
@@ -333,6 +374,20 @@ the span a value falls in as the list counts it, and `dayIn` and `dayStarts`
333
374
  a day in a time zone; `createMemoryDataSource` does it all. See
334
375
  [lists that add up](https://fieldia.dev/lists/#totals).
335
376
 
377
+ ## A map's records counted where they crowd
378
+
379
+ A list's map (@fieldia/map) asks its source's optional `clusters({ model,
380
+ filter, field, longitude?, bbox, zoom, radius, fields, weight?, signal })` for
381
+ the view's bubbles — `{ clusters: [{ lat, lng, count, bbox?, weight? }],
382
+ points?: [{ id, values }], unplaced? }` — instead of loading at most 500 records
383
+ and gathering them itself: every record a search finds, however many, a record
384
+ standing alone with its values for its pin and its card. Answer `false` to let
385
+ the map load the search's records, as it does without the member. The memory
386
+ source has it where its `clusters` option says how it answers:
387
+ `createMemoryDataSource({ records, clusters: gridClusters({ models: ['home'] }) })`
388
+ gathers its records by a grid of squares fixed to the world, as a server does.
389
+ See [lists on a map](https://fieldia.dev/lists/#map).
390
+
336
391
  ## Time zones and booking slots
337
392
 
338
393
  A page may name the time zone its dates and times are in, by its IANA name —
@@ -577,6 +632,60 @@ const form = createForm({ page, dataSource, resume: new URLSearchParams(location
577
632
  form.on('draft', ({ key, later, saved }) => later && console.log('Continue from', saved.link));
578
633
  ```
579
634
 
635
+ ## Approvals on a record
636
+
637
+ A record's page may say its records wait for approval:
638
+
639
+ ```json
640
+ { "approval": { "open": ["notes"] } }
641
+ ```
642
+
643
+ The data source tells where a record stands, `approvals({ model, recordId,
644
+ user })` answering `{ levels, history, mine, together, why }` — each level its
645
+ `id`, `name`, `approvers` (each `{ id, name, decision, at }` in the round asked
646
+ now), `needs` (`any`, the default, or `all`) and `state` (`waiting`, `later`,
647
+ `approved`, `rejected`, `skipped`); `history` oldest first (`{ decision:
648
+ 'requested' | 'approved' | 'rejected', level, by, at, reason }`); `mine` the
649
+ levels this person may decide now — and takes the decisions, `decide({ model,
650
+ recordId, level, decision, reason, user })`, a rejection always with why. Who is
651
+ asked, and in what order, is the app's, or its approval engine's: Fieldia never
652
+ works it out. The form asks as a saved record is shown, after each save and each
653
+ decision, keeping what it told in `state.approval` (`status`: `none`, `needed`,
654
+ `waiting`, `approved`, `rejected`); an answer for a record no longer shown is
655
+ laid on none. While it waits, every field is read-only but those `open` names
656
+ (`form.node(id).readonly`, `form.fieldReadonly`), `form.approvalLock(name)`
657
+ saying why; `"lock": false` locks none. `form.decide(level, decision, reason?)`
658
+ reads and saves what is typed first, then decides, then loads the record again;
659
+ it refuses a level not this person's and a rejection with no reason, in words.
660
+ The memory source's `approvals` option routes records as an engine would (in
661
+ turn or together, any or all, a rejection ending the round), keeping each
662
+ decision; `approvalHistory` is what it starts from.
663
+
664
+ ```ts
665
+ await form.decide('finance', 'rejected', 'Over the quarter’s budget');
666
+ form.getState().approval?.status; // 'rejected'
667
+ ```
668
+
669
+ ## AI help: values proposed, words written, a search read
670
+
671
+ Three optional members answer with the app's own model — Fieldia ships no model
672
+ and no keys. `suggest({ page, values, fields, from: { text?, files? } })` gives
673
+ values for a form (a page's `suggest`: `fields`, `label`, `from`, `fromField`),
674
+ a table's lines to add among them; `rewrite({ field, how, text, values })` a
675
+ text field's words (its node's `options.rewrite`: `"draft"`, `"polish"`, or
676
+ `{ "how", "label" }`); `searchToFilter({ text, fields })` a list's conditions
677
+ (its `searchToFilter`). The viewer shows each value on its field to accept or
678
+ reject first, and Undo after; `checkPage` and `validatePage` check the settings.
679
+ The memory source has each member only where its `assist` option answers it;
680
+ `assistStandIn({ drafts })` is a stand-in for demos and tests — no model, words
681
+ read by their patterns, every answer saying so ("Stand-in AI, no model: …"):
682
+
683
+ ```ts
684
+ import { assistStandIn, createMemoryDataSource } from '@fieldia/core';
685
+
686
+ const dataSource = createMemoryDataSource({ records, assist: assistStandIn({ drafts: { 'enquiry.reply': (values) => `Dear ${values.partner_name},` } }) });
687
+ ```
688
+
580
689
  ## What a page's records are called
581
690
 
582
691
  A page may say what its records are, so Fieldia's own sentences name them as
@@ -744,6 +853,21 @@ fields); `importFields(page, list)` says which fields a file's columns may fill.
744
853
  `createMemoryDataSource` gives `createMany`. See [many records made at
745
854
  once](https://fieldia.dev/data/#import).
746
855
 
856
+ ## A record found by a code a scanner read
857
+
858
+ A link scanned into with the camera (`options.scan` on a many2one or a table's
859
+ link column, drawn by @fieldia/widgets' scan part) finds the record a code names
860
+ through the data source's `search`, with no member of its own:
861
+ `form.search(field, code, 2, { field: 'barcode' })` asks for the records whose
862
+ `barcode` holds the code exactly — the field's own filter kept, the condition
863
+ added to it, the query empty — and `form.searchLine(…)` the same for a line's
864
+ link. Without a field named, the code is searched as a name, the exact name
865
+ first. The page check holds `options.scan` to a kind a code is written into —
866
+ a char, a text, a many2one, or a one2many counted by a column (`field`) and a
867
+ number (`count`) — and the fields a GS1 code fills (`fills`) to fields of the
868
+ page, or of the line, that take a code's part; `ScanOptionSchema`
869
+ gives its shape. See [scanning a code](https://fieldia.dev/fields/#scan).
870
+
747
871
  ## A saved form placed in another
748
872
 
749
873
  A block made once — an address, a contact person, a consent — is a page of its
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fieldia/core",
3
- "version": "0.28.0",
3
+ "version": "0.30.0",
4
4
  "description": "Headless form model for Fieldia: the page format, modifiers, validation and record state. No DOM.",
5
5
  "license": "MIT",
6
6
  "homepage": "https://fieldia.dev",
@@ -11,7 +11,9 @@
11
11
  "0.4",
12
12
  "0.5",
13
13
  "0.6",
14
- "0.7"
14
+ "0.7",
15
+ "0.8",
16
+ "0.9"
15
17
  ]
16
18
  },
17
19
  "id": {
@@ -389,6 +391,12 @@
389
391
  },
390
392
  "continueLater": {
391
393
  "type": "boolean"
394
+ },
395
+ "approval": {
396
+ "$ref": "#/$defs/PageApproval"
397
+ },
398
+ "suggest": {
399
+ "$ref": "#/$defs/PageSuggest"
392
400
  }
393
401
  },
394
402
  "required": [
@@ -452,13 +460,36 @@
452
460
  "patternHint": {
453
461
  "type": "string",
454
462
  "minLength": 1
463
+ },
464
+ "translate": {
465
+ "minItems": 2,
466
+ "type": "array",
467
+ "items": {
468
+ "$ref": "#/$defs/LanguageTag"
469
+ },
470
+ "uniqueItems": true
471
+ },
472
+ "requiredIn": {
473
+ "minItems": 1,
474
+ "type": "array",
475
+ "items": {
476
+ "$ref": "#/$defs/LanguageTag"
477
+ },
478
+ "uniqueItems": true
455
479
  }
456
480
  },
457
481
  "required": [
458
482
  "type",
459
483
  "label"
460
484
  ],
461
- "additionalProperties": false
485
+ "additionalProperties": false,
486
+ "dependentSchemas": {
487
+ "requiredIn": {
488
+ "required": [
489
+ "translate"
490
+ ]
491
+ }
492
+ }
462
493
  },
463
494
  {
464
495
  "type": "object",
@@ -501,13 +532,36 @@
501
532
  "type": "integer",
502
533
  "exclusiveMinimum": 0,
503
534
  "maximum": 9007199254740991
535
+ },
536
+ "translate": {
537
+ "minItems": 2,
538
+ "type": "array",
539
+ "items": {
540
+ "$ref": "#/$defs/LanguageTag"
541
+ },
542
+ "uniqueItems": true
543
+ },
544
+ "requiredIn": {
545
+ "minItems": 1,
546
+ "type": "array",
547
+ "items": {
548
+ "$ref": "#/$defs/LanguageTag"
549
+ },
550
+ "uniqueItems": true
504
551
  }
505
552
  },
506
553
  "required": [
507
554
  "type",
508
555
  "label"
509
556
  ],
510
- "additionalProperties": false
557
+ "additionalProperties": false,
558
+ "dependentSchemas": {
559
+ "requiredIn": {
560
+ "required": [
561
+ "translate"
562
+ ]
563
+ }
564
+ }
511
565
  },
512
566
  {
513
567
  "type": "object",
@@ -545,13 +599,36 @@
545
599
  "items": {
546
600
  "$ref": "#/$defs/SetWhen"
547
601
  }
602
+ },
603
+ "translate": {
604
+ "minItems": 2,
605
+ "type": "array",
606
+ "items": {
607
+ "$ref": "#/$defs/LanguageTag"
608
+ },
609
+ "uniqueItems": true
610
+ },
611
+ "requiredIn": {
612
+ "minItems": 1,
613
+ "type": "array",
614
+ "items": {
615
+ "$ref": "#/$defs/LanguageTag"
616
+ },
617
+ "uniqueItems": true
548
618
  }
549
619
  },
550
620
  "required": [
551
621
  "type",
552
622
  "label"
553
623
  ],
554
- "additionalProperties": false
624
+ "additionalProperties": false,
625
+ "dependentSchemas": {
626
+ "requiredIn": {
627
+ "required": [
628
+ "translate"
629
+ ]
630
+ }
631
+ }
555
632
  },
556
633
  {
557
634
  "type": "object",
@@ -1684,6 +1761,17 @@
1684
1761
  }
1685
1762
  ]
1686
1763
  },
1764
+ "LanguageTag": {
1765
+ "type": "string",
1766
+ "pattern": "^[A-Za-z]{2,3}(-[A-Za-z0-9]{2,8})*$",
1767
+ "description": "A language by its BCP 47 tag.",
1768
+ "examples": [
1769
+ "ar",
1770
+ "en",
1771
+ "fr",
1772
+ "pt-BR"
1773
+ ]
1774
+ },
1687
1775
  "MoneyLook": {
1688
1776
  "type": "object",
1689
1777
  "properties": {
@@ -2014,13 +2102,36 @@
2014
2102
  "patternHint": {
2015
2103
  "type": "string",
2016
2104
  "minLength": 1
2105
+ },
2106
+ "translate": {
2107
+ "minItems": 2,
2108
+ "type": "array",
2109
+ "items": {
2110
+ "$ref": "#/$defs/LanguageTag"
2111
+ },
2112
+ "uniqueItems": true
2113
+ },
2114
+ "requiredIn": {
2115
+ "minItems": 1,
2116
+ "type": "array",
2117
+ "items": {
2118
+ "$ref": "#/$defs/LanguageTag"
2119
+ },
2120
+ "uniqueItems": true
2017
2121
  }
2018
2122
  },
2019
2123
  "required": [
2020
2124
  "type",
2021
2125
  "label"
2022
2126
  ],
2023
- "additionalProperties": false
2127
+ "additionalProperties": false,
2128
+ "dependentSchemas": {
2129
+ "requiredIn": {
2130
+ "required": [
2131
+ "translate"
2132
+ ]
2133
+ }
2134
+ }
2024
2135
  },
2025
2136
  {
2026
2137
  "type": "object",
@@ -2063,13 +2174,36 @@
2063
2174
  "type": "integer",
2064
2175
  "exclusiveMinimum": 0,
2065
2176
  "maximum": 9007199254740991
2177
+ },
2178
+ "translate": {
2179
+ "minItems": 2,
2180
+ "type": "array",
2181
+ "items": {
2182
+ "$ref": "#/$defs/LanguageTag"
2183
+ },
2184
+ "uniqueItems": true
2185
+ },
2186
+ "requiredIn": {
2187
+ "minItems": 1,
2188
+ "type": "array",
2189
+ "items": {
2190
+ "$ref": "#/$defs/LanguageTag"
2191
+ },
2192
+ "uniqueItems": true
2066
2193
  }
2067
2194
  },
2068
2195
  "required": [
2069
2196
  "type",
2070
2197
  "label"
2071
2198
  ],
2072
- "additionalProperties": false
2199
+ "additionalProperties": false,
2200
+ "dependentSchemas": {
2201
+ "requiredIn": {
2202
+ "required": [
2203
+ "translate"
2204
+ ]
2205
+ }
2206
+ }
2073
2207
  },
2074
2208
  {
2075
2209
  "type": "object",
@@ -2659,6 +2793,12 @@
2659
2793
  "patternHint": {
2660
2794
  "type": "string",
2661
2795
  "minLength": 1
2796
+ },
2797
+ "translate": {
2798
+ "not": {}
2799
+ },
2800
+ "requiredIn": {
2801
+ "not": {}
2662
2802
  }
2663
2803
  },
2664
2804
  "required": [
@@ -2708,6 +2848,12 @@
2708
2848
  "type": "integer",
2709
2849
  "exclusiveMinimum": 0,
2710
2850
  "maximum": 9007199254740991
2851
+ },
2852
+ "translate": {
2853
+ "not": {}
2854
+ },
2855
+ "requiredIn": {
2856
+ "not": {}
2711
2857
  }
2712
2858
  },
2713
2859
  "required": [
@@ -2752,6 +2898,12 @@
2752
2898
  "items": {
2753
2899
  "$ref": "#/$defs/SetWhen"
2754
2900
  }
2901
+ },
2902
+ "translate": {
2903
+ "not": {}
2904
+ },
2905
+ "requiredIn": {
2906
+ "not": {}
2755
2907
  }
2756
2908
  },
2757
2909
  "required": [
@@ -3859,6 +4011,12 @@
3859
4011
  "patternHint": {
3860
4012
  "type": "string",
3861
4013
  "minLength": 1
4014
+ },
4015
+ "translate": {
4016
+ "not": {}
4017
+ },
4018
+ "requiredIn": {
4019
+ "not": {}
3862
4020
  }
3863
4021
  },
3864
4022
  "required": [
@@ -3908,6 +4066,12 @@
3908
4066
  "type": "integer",
3909
4067
  "exclusiveMinimum": 0,
3910
4068
  "maximum": 9007199254740991
4069
+ },
4070
+ "translate": {
4071
+ "not": {}
4072
+ },
4073
+ "requiredIn": {
4074
+ "not": {}
3911
4075
  }
3912
4076
  },
3913
4077
  "required": [
@@ -3952,6 +4116,12 @@
3952
4116
  "items": {
3953
4117
  "$ref": "#/$defs/SetWhen"
3954
4118
  }
4119
+ },
4120
+ "translate": {
4121
+ "not": {}
4122
+ },
4123
+ "requiredIn": {
4124
+ "not": {}
3955
4125
  }
3956
4126
  },
3957
4127
  "required": [
@@ -7249,6 +7419,10 @@
7249
7419
  "type": "string",
7250
7420
  "pattern": "^[A-Za-z0-9][A-Za-z0-9._-]*$"
7251
7421
  },
7422
+ "type": {
7423
+ "type": "string",
7424
+ "const": "divider"
7425
+ },
7252
7426
  "label": {
7253
7427
  "type": "string"
7254
7428
  },
@@ -7300,6 +7474,17 @@
7300
7474
  },
7301
7475
  "roles": {
7302
7476
  "$ref": "#/$defs/Roles"
7477
+ },
7478
+ "menu": {
7479
+ "minItems": 1,
7480
+ "type": "array",
7481
+ "items": {
7482
+ "$ref": "#/$defs/MenuItem"
7483
+ }
7484
+ },
7485
+ "menuFrom": {
7486
+ "type": "string",
7487
+ "minLength": 1
7303
7488
  }
7304
7489
  },
7305
7490
  "required": [
@@ -9541,6 +9726,9 @@
9541
9726
  "filterSheet": {
9542
9727
  "type": "boolean"
9543
9728
  },
9729
+ "searchToFilter": {
9730
+ "type": "boolean"
9731
+ },
9544
9732
  "parentField": {
9545
9733
  "type": "string",
9546
9734
  "pattern": "^[A-Za-z_][A-Za-z0-9_]*$"
@@ -9723,6 +9911,16 @@
9723
9911
  ],
9724
9912
  "additionalProperties": false
9725
9913
  }
9914
+ },
9915
+ "editable": {
9916
+ "anyOf": [
9917
+ {
9918
+ "type": "boolean"
9919
+ },
9920
+ {
9921
+ "$ref": "#/$defs/ListEditable"
9922
+ }
9923
+ ]
9726
9924
  }
9727
9925
  },
9728
9926
  "required": [
@@ -10025,6 +10223,26 @@
10025
10223
  },
10026
10224
  "additionalProperties": false
10027
10225
  },
10226
+ "ListEditable": {
10227
+ "type": "object",
10228
+ "properties": {
10229
+ "fields": {
10230
+ "minItems": 1,
10231
+ "type": "array",
10232
+ "items": {
10233
+ "type": "string",
10234
+ "pattern": "^[A-Za-z_][A-Za-z0-9_]*$"
10235
+ }
10236
+ },
10237
+ "add": {
10238
+ "type": "boolean"
10239
+ },
10240
+ "open": {
10241
+ "type": "boolean"
10242
+ }
10243
+ },
10244
+ "additionalProperties": false
10245
+ },
10028
10246
  "PageEvents": {
10029
10247
  "type": "object",
10030
10248
  "properties": {
@@ -10242,6 +10460,61 @@
10242
10460
  }
10243
10461
  },
10244
10462
  "additionalProperties": false
10463
+ },
10464
+ "PageApproval": {
10465
+ "type": "object",
10466
+ "properties": {
10467
+ "open": {
10468
+ "type": "array",
10469
+ "items": {
10470
+ "type": "string",
10471
+ "minLength": 1
10472
+ }
10473
+ },
10474
+ "lock": {
10475
+ "type": "boolean"
10476
+ }
10477
+ },
10478
+ "additionalProperties": false
10479
+ },
10480
+ "PageSuggest": {
10481
+ "type": "object",
10482
+ "properties": {
10483
+ "fields": {
10484
+ "minItems": 1,
10485
+ "type": "array",
10486
+ "items": {
10487
+ "type": "string",
10488
+ "minLength": 1
10489
+ }
10490
+ },
10491
+ "from": {
10492
+ "minItems": 1,
10493
+ "type": "array",
10494
+ "items": {
10495
+ "type": "string",
10496
+ "enum": [
10497
+ "text",
10498
+ "files"
10499
+ ]
10500
+ }
10501
+ },
10502
+ "label": {
10503
+ "type": "string",
10504
+ "minLength": 1,
10505
+ "maxLength": 60
10506
+ },
10507
+ "placeholder": {
10508
+ "type": "string",
10509
+ "minLength": 1,
10510
+ "maxLength": 200
10511
+ },
10512
+ "fromField": {
10513
+ "type": "string",
10514
+ "minLength": 1
10515
+ }
10516
+ },
10517
+ "additionalProperties": false
10245
10518
  }
10246
10519
  }
10247
10520
  }
package/src/index.d.mts CHANGED
@@ -1,11 +1,14 @@
1
1
  export * from './runtime.mjs';
2
2
  export { takingWords, whenWords } from './lib/record/form-limits.mjs';
3
3
  export { isQuestion } from './lib/record/record-words.mjs';
4
+ export { checkTranslated, languageName, languagesAtFault, textIn, textOf } from './lib/record/languages-part.mjs';
4
5
  export { dayWords } from './lib/record/day-words.mjs';
5
6
  export { scheduleSlots, type MemorySchedule } from './lib/record/memory-schedules.mjs';
6
7
  export { alikeRecords, nameLikeness } from './lib/record/memory-duplicates.mjs';
7
- export { FieldSchema, FieldsSchema, LineFieldSchema, LinkedFieldSchema, LineKindsSchema, OptionSchema, PropertyDefinitionSchema, FilterConditionSchema, FilterItemSchema, MoneyLookSchema, ShrinkSchema, PERIODS, TimeZoneSchema, } from './lib/format/field.mjs';
8
- export { ModifierSchema, RolesSchema, CellRulesSchema, ToneWhenSchema, LayoutNodeSchema, RootLayoutSchema, ListNodeSchema, ListCellSchema, ListCalendarSchema, ListCardSchema, ListGallerySchema, FilterRangeSchema, FilterPeriodSchema, RelatedNodeSchema } from './lib/format/layout.mjs';
8
+ export { assistStandIn, polishText, readSignature, standInNumber, type StandInFound, type StandInOptions } from './lib/record/memory-assist.mjs';
9
+ export { gridClusters } from './lib/record/memory-clusters.mjs';
10
+ export { FieldSchema, FieldsSchema, LanguageTagSchema, LineFieldSchema, LinkedFieldSchema, LineKindsSchema, OptionSchema, PropertyDefinitionSchema, FilterConditionSchema, FilterItemSchema, MoneyLookSchema, ShrinkSchema, PERIODS, TimeZoneSchema, } from './lib/format/field.mjs';
11
+ export { ModifierSchema, RolesSchema, CellRulesSchema, ToneWhenSchema, LayoutNodeSchema, RootLayoutSchema, ListNodeSchema, ListCellSchema, ListCalendarSchema, ListCardSchema, ListGallerySchema, ListEditableSchema, FilterRangeSchema, FilterPeriodSchema, RelatedNodeSchema } from './lib/format/layout.mjs';
9
12
  export { PageSchema } from './lib/format/page.mjs';
10
13
  export { ActionStepSchema, PageEventsSchema } from './lib/format/actions.mjs';
11
14
  export { pageWarnings, validatePage } from './lib/format/validate.mjs';
@@ -16,10 +19,13 @@ export { PathPickerOptionsSchema, StateDotOptionsSchema } from './lib/format/pic
16
19
  export { PagePhoneSchema, PhoneOptionsSchema } from './lib/format/phone.mjs';
17
20
  export { SlotsOptionsSchema } from './lib/format/slots-options.mjs';
18
21
  export { SignatureOptionsSchema } from './lib/format/signature-options.mjs';
22
+ export { PhotosOptionsSchema } from './lib/format/photos-options.mjs';
23
+ export { SCAN_FORMATS, ScanFillSchema, ScanOptionSchema, ScanSettingsSchema } from './lib/format/scan-options.mjs';
19
24
  export { PageDuplicatesSchema } from './lib/format/duplicates.mjs';
20
25
  export { PageRecordsSchema } from './lib/format/records.mjs';
21
26
  export { PageEndingSchema } from './lib/format/endings.mjs';
22
27
  export { PageLimitsSchema } from './lib/format/limits.mjs';
28
+ export { PageApprovalSchema } from './lib/format/approval.mjs';
23
29
  export { DUPLICATE_KINDS, comparable } from './lib/format/duplicate-kinds.mjs';
24
30
  export { pageJsonSchema } from './lib/format/json-schema.mjs';
25
31
  export { AUTOFILL, AUTOFILL_CONTACT, AUTOFILL_NAMES, autofillProblem, autofillPurpose } from './lib/format/autofill.mjs';