@fieldia/core 0.30.1 → 0.31.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 (551) hide show
  1. package/README.md +362 -1
  2. package/package.json +1 -1
  3. package/schema/page.schema.json +758 -1
  4. package/src/index.d.mts +13 -2
  5. package/src/index.d.ts +13 -2
  6. package/src/index.js +45 -2
  7. package/src/index.js.map +1 -1
  8. package/src/index.mjs +18 -2
  9. package/src/index.mjs.map +1 -1
  10. package/src/lib/format/actions.d.mts +16 -16
  11. package/src/lib/format/actions.d.ts +16 -16
  12. package/src/lib/format/actions.js +3 -0
  13. package/src/lib/format/actions.js.map +1 -1
  14. package/src/lib/format/actions.mjs +3 -0
  15. package/src/lib/format/actions.mjs.map +1 -1
  16. package/src/lib/format/address-search.js +3 -0
  17. package/src/lib/format/address-search.js.map +1 -1
  18. package/src/lib/format/address-search.mjs +3 -0
  19. package/src/lib/format/address-search.mjs.map +1 -1
  20. package/src/lib/format/duplicates.js +3 -0
  21. package/src/lib/format/duplicates.js.map +1 -1
  22. package/src/lib/format/duplicates.mjs +3 -0
  23. package/src/lib/format/duplicates.mjs.map +1 -1
  24. package/src/lib/format/endings.js +3 -0
  25. package/src/lib/format/endings.js.map +1 -1
  26. package/src/lib/format/endings.mjs +3 -0
  27. package/src/lib/format/endings.mjs.map +1 -1
  28. package/src/lib/format/field.d.mts +669 -0
  29. package/src/lib/format/field.d.ts +669 -0
  30. package/src/lib/format/field.js +42 -4
  31. package/src/lib/format/field.js.map +1 -1
  32. package/src/lib/format/field.mjs +42 -4
  33. package/src/lib/format/field.mjs.map +1 -1
  34. package/src/lib/format/flow-checks.d.mts +14 -0
  35. package/src/lib/format/flow-checks.d.ts +14 -0
  36. package/src/lib/format/flow-checks.js +61 -0
  37. package/src/lib/format/flow-checks.js.map +1 -0
  38. package/src/lib/format/flow-checks.mjs +58 -0
  39. package/src/lib/format/flow-checks.mjs.map +1 -0
  40. package/src/lib/format/flow.d.mts +43 -0
  41. package/src/lib/format/flow.d.ts +43 -0
  42. package/src/lib/format/flow.js +22 -0
  43. package/src/lib/format/flow.js.map +1 -0
  44. package/src/lib/format/flow.mjs +19 -0
  45. package/src/lib/format/flow.mjs.map +1 -0
  46. package/src/lib/format/from-schema.d.mts +70 -0
  47. package/src/lib/format/from-schema.d.ts +70 -0
  48. package/src/lib/format/from-schema.js +599 -0
  49. package/src/lib/format/from-schema.js.map +1 -0
  50. package/src/lib/format/from-schema.mjs +591 -0
  51. package/src/lib/format/from-schema.mjs.map +1 -0
  52. package/src/lib/format/jitless.d.mts +1 -0
  53. package/src/lib/format/jitless.d.ts +1 -0
  54. package/src/lib/format/jitless.js +27 -0
  55. package/src/lib/format/jitless.js.map +1 -0
  56. package/src/lib/format/jitless.mjs +24 -0
  57. package/src/lib/format/jitless.mjs.map +1 -0
  58. package/src/lib/format/json-schema.js +3 -0
  59. package/src/lib/format/json-schema.js.map +1 -1
  60. package/src/lib/format/json-schema.mjs +3 -0
  61. package/src/lib/format/json-schema.mjs.map +1 -1
  62. package/src/lib/format/json.js +3 -0
  63. package/src/lib/format/json.js.map +1 -1
  64. package/src/lib/format/json.mjs +3 -0
  65. package/src/lib/format/json.mjs.map +1 -1
  66. package/src/lib/format/languages-checks.d.mts +2 -1
  67. package/src/lib/format/languages-checks.d.ts +2 -1
  68. package/src/lib/format/languages-checks.js +8 -2
  69. package/src/lib/format/languages-checks.js.map +1 -1
  70. package/src/lib/format/languages-checks.mjs +8 -2
  71. package/src/lib/format/languages-checks.mjs.map +1 -1
  72. package/src/lib/format/later-checks.d.mts +3 -1
  73. package/src/lib/format/later-checks.d.ts +3 -1
  74. package/src/lib/format/later-checks.js +3 -1
  75. package/src/lib/format/later-checks.js.map +1 -1
  76. package/src/lib/format/later-checks.mjs +3 -1
  77. package/src/lib/format/later-checks.mjs.map +1 -1
  78. package/src/lib/format/layout.d.mts +13192 -7550
  79. package/src/lib/format/layout.d.ts +13192 -7550
  80. package/src/lib/format/layout.js +61 -3
  81. package/src/lib/format/layout.js.map +1 -1
  82. package/src/lib/format/layout.mjs +59 -1
  83. package/src/lib/format/layout.mjs.map +1 -1
  84. package/src/lib/format/layout.types.d.mts +3 -1
  85. package/src/lib/format/layout.types.d.ts +3 -1
  86. package/src/lib/format/limits.js +3 -0
  87. package/src/lib/format/limits.js.map +1 -1
  88. package/src/lib/format/limits.mjs +3 -0
  89. package/src/lib/format/limits.mjs.map +1 -1
  90. package/src/lib/format/list-checks.d.mts +1 -1
  91. package/src/lib/format/list-checks.d.ts +1 -1
  92. package/src/lib/format/list-checks.js +67 -22
  93. package/src/lib/format/list-checks.js.map +1 -1
  94. package/src/lib/format/list-checks.mjs +67 -22
  95. package/src/lib/format/list-checks.mjs.map +1 -1
  96. package/src/lib/format/list-rows-checks.d.mts +11 -0
  97. package/src/lib/format/list-rows-checks.d.ts +11 -0
  98. package/src/lib/format/list-rows-checks.js +62 -0
  99. package/src/lib/format/list-rows-checks.js.map +1 -0
  100. package/src/lib/format/list-rows-checks.mjs +59 -0
  101. package/src/lib/format/list-rows-checks.mjs.map +1 -0
  102. package/src/lib/format/media-options.d.mts +84 -0
  103. package/src/lib/format/media-options.d.ts +84 -0
  104. package/src/lib/format/media-options.js +86 -0
  105. package/src/lib/format/media-options.js.map +1 -0
  106. package/src/lib/format/media-options.mjs +80 -0
  107. package/src/lib/format/media-options.mjs.map +1 -0
  108. package/src/lib/format/outbox-checks.d.mts +11 -0
  109. package/src/lib/format/outbox-checks.d.ts +11 -0
  110. package/src/lib/format/outbox-checks.js +12 -0
  111. package/src/lib/format/outbox-checks.js.map +1 -0
  112. package/src/lib/format/outbox-checks.mjs +9 -0
  113. package/src/lib/format/outbox-checks.mjs.map +1 -0
  114. package/src/lib/format/page.d.mts +3057 -966
  115. package/src/lib/format/page.d.ts +3057 -966
  116. package/src/lib/format/page.js +15 -0
  117. package/src/lib/format/page.js.map +1 -1
  118. package/src/lib/format/page.mjs +15 -0
  119. package/src/lib/format/page.mjs.map +1 -1
  120. package/src/lib/format/part-checks.d.mts +3 -0
  121. package/src/lib/format/part-checks.d.ts +3 -0
  122. package/src/lib/format/payment-checks.d.mts +13 -0
  123. package/src/lib/format/payment-checks.d.ts +13 -0
  124. package/src/lib/format/payment-checks.js +30 -0
  125. package/src/lib/format/payment-checks.js.map +1 -0
  126. package/src/lib/format/payment-checks.mjs +27 -0
  127. package/src/lib/format/payment-checks.mjs.map +1 -0
  128. package/src/lib/format/payment.d.mts +37 -0
  129. package/src/lib/format/payment.d.ts +37 -0
  130. package/src/lib/format/payment.js +15 -0
  131. package/src/lib/format/payment.js.map +1 -0
  132. package/src/lib/format/payment.mjs +12 -0
  133. package/src/lib/format/payment.mjs.map +1 -0
  134. package/src/lib/format/phone.js +3 -0
  135. package/src/lib/format/phone.js.map +1 -1
  136. package/src/lib/format/phone.mjs +3 -0
  137. package/src/lib/format/phone.mjs.map +1 -1
  138. package/src/lib/format/picker-options.d.mts +12 -0
  139. package/src/lib/format/picker-options.d.ts +12 -0
  140. package/src/lib/format/picker-options.js +21 -3
  141. package/src/lib/format/picker-options.js.map +1 -1
  142. package/src/lib/format/picker-options.mjs +20 -2
  143. package/src/lib/format/picker-options.mjs.map +1 -1
  144. package/src/lib/format/prefill-checks.d.mts +13 -0
  145. package/src/lib/format/prefill-checks.d.ts +13 -0
  146. package/src/lib/format/prefill-checks.js +35 -0
  147. package/src/lib/format/prefill-checks.js.map +1 -0
  148. package/src/lib/format/prefill-checks.mjs +32 -0
  149. package/src/lib/format/prefill-checks.mjs.map +1 -0
  150. package/src/lib/format/prefill.d.mts +33 -0
  151. package/src/lib/format/prefill.d.ts +33 -0
  152. package/src/lib/format/prefill.js +20 -0
  153. package/src/lib/format/prefill.js.map +1 -0
  154. package/src/lib/format/prefill.mjs +17 -0
  155. package/src/lib/format/prefill.mjs.map +1 -0
  156. package/src/lib/format/quiz.d.mts +58 -0
  157. package/src/lib/format/quiz.d.ts +58 -0
  158. package/src/lib/format/quiz.js +24 -0
  159. package/src/lib/format/quiz.js.map +1 -0
  160. package/src/lib/format/quiz.mjs +21 -0
  161. package/src/lib/format/quiz.mjs.map +1 -0
  162. package/src/lib/format/records.js +3 -0
  163. package/src/lib/format/records.js.map +1 -1
  164. package/src/lib/format/records.mjs +3 -0
  165. package/src/lib/format/records.mjs.map +1 -1
  166. package/src/lib/format/references.d.mts +1 -1
  167. package/src/lib/format/references.d.ts +1 -1
  168. package/src/lib/format/references.js +56 -7
  169. package/src/lib/format/references.js.map +1 -1
  170. package/src/lib/format/references.mjs +57 -8
  171. package/src/lib/format/references.mjs.map +1 -1
  172. package/src/lib/format/schedule-checks.d.mts +8 -0
  173. package/src/lib/format/schedule-checks.d.ts +8 -0
  174. package/src/lib/format/schedule-checks.js +16 -0
  175. package/src/lib/format/schedule-checks.js.map +1 -0
  176. package/src/lib/format/schedule-checks.mjs +13 -0
  177. package/src/lib/format/schedule-checks.mjs.map +1 -0
  178. package/src/lib/format/signature-checks.d.mts +8 -0
  179. package/src/lib/format/signature-checks.d.ts +8 -0
  180. package/src/lib/format/signature-checks.js +21 -0
  181. package/src/lib/format/signature-checks.js.map +1 -1
  182. package/src/lib/format/signature-checks.mjs +20 -0
  183. package/src/lib/format/signature-checks.mjs.map +1 -1
  184. package/src/lib/format/signature-options.js +3 -0
  185. package/src/lib/format/signature-options.js.map +1 -1
  186. package/src/lib/format/signature-options.mjs +3 -0
  187. package/src/lib/format/signature-options.mjs.map +1 -1
  188. package/src/lib/format/slots-options.js +3 -0
  189. package/src/lib/format/slots-options.js.map +1 -1
  190. package/src/lib/format/slots-options.mjs +3 -0
  191. package/src/lib/format/slots-options.mjs.map +1 -1
  192. package/src/lib/format/templates-checks.d.mts +6 -0
  193. package/src/lib/format/templates-checks.d.ts +6 -0
  194. package/src/lib/format/templates-checks.js +16 -0
  195. package/src/lib/format/templates-checks.js.map +1 -0
  196. package/src/lib/format/templates-checks.mjs +13 -0
  197. package/src/lib/format/templates-checks.mjs.map +1 -0
  198. package/src/lib/format/translate.d.mts +2 -0
  199. package/src/lib/format/translate.d.ts +2 -0
  200. package/src/lib/format/translate.js +6 -2
  201. package/src/lib/format/translate.js.map +1 -1
  202. package/src/lib/format/translate.mjs +4 -2
  203. package/src/lib/format/translate.mjs.map +1 -1
  204. package/src/lib/format/typed-options.d.mts +43 -0
  205. package/src/lib/format/typed-options.d.ts +43 -0
  206. package/src/lib/format/typed-options.js +50 -0
  207. package/src/lib/format/typed-options.js.map +1 -0
  208. package/src/lib/format/typed-options.mjs +46 -0
  209. package/src/lib/format/typed-options.mjs.map +1 -0
  210. package/src/lib/format/upgrade.d.mts +5 -1
  211. package/src/lib/format/upgrade.d.ts +5 -1
  212. package/src/lib/format/upgrade.js +5 -1
  213. package/src/lib/format/upgrade.js.map +1 -1
  214. package/src/lib/format/upgrade.mjs +5 -1
  215. package/src/lib/format/upgrade.mjs.map +1 -1
  216. package/src/lib/format/validate.js +3 -0
  217. package/src/lib/format/validate.js.map +1 -1
  218. package/src/lib/format/validate.mjs +3 -0
  219. package/src/lib/format/validate.mjs.map +1 -1
  220. package/src/lib/format/verify-checks.d.mts +10 -0
  221. package/src/lib/format/verify-checks.d.ts +10 -0
  222. package/src/lib/format/verify-checks.js +44 -0
  223. package/src/lib/format/verify-checks.js.map +1 -0
  224. package/src/lib/format/verify-checks.mjs +41 -0
  225. package/src/lib/format/verify-checks.mjs.map +1 -0
  226. package/src/lib/format/version.d.mts +2 -2
  227. package/src/lib/format/version.d.ts +2 -2
  228. package/src/lib/format/version.js +2 -2
  229. package/src/lib/format/version.js.map +1 -1
  230. package/src/lib/format/version.mjs +2 -2
  231. package/src/lib/format/version.mjs.map +1 -1
  232. package/src/lib/format/week.d.mts +18 -0
  233. package/src/lib/format/week.d.ts +18 -0
  234. package/src/lib/format/week.js +58 -0
  235. package/src/lib/format/week.js.map +1 -0
  236. package/src/lib/format/week.mjs +55 -0
  237. package/src/lib/format/week.mjs.map +1 -0
  238. package/src/lib/record/approvals-part.d.mts +1 -1
  239. package/src/lib/record/approvals-part.d.ts +1 -1
  240. package/src/lib/record/approvals-part.js +2 -2
  241. package/src/lib/record/approvals-part.js.map +1 -1
  242. package/src/lib/record/approvals-part.mjs +1 -1
  243. package/src/lib/record/approvals-part.mjs.map +1 -1
  244. package/src/lib/record/data-source.d.mts +331 -0
  245. package/src/lib/record/data-source.d.ts +331 -0
  246. package/src/lib/record/data-source.js.map +1 -1
  247. package/src/lib/record/data-source.mjs.map +1 -1
  248. package/src/lib/record/day-words.d.mts +22 -1
  249. package/src/lib/record/day-words.d.ts +22 -1
  250. package/src/lib/record/day-words.js +29 -2
  251. package/src/lib/record/day-words.js.map +1 -1
  252. package/src/lib/record/day-words.mjs +24 -2
  253. package/src/lib/record/day-words.mjs.map +1 -1
  254. package/src/lib/record/files-part.d.mts +1 -0
  255. package/src/lib/record/files-part.d.ts +1 -0
  256. package/src/lib/record/files-part.js +7 -1
  257. package/src/lib/record/files-part.js.map +1 -1
  258. package/src/lib/record/files-part.mjs +5 -1
  259. package/src/lib/record/files-part.mjs.map +1 -1
  260. package/src/lib/record/form-approvals.d.mts +12 -17
  261. package/src/lib/record/form-approvals.d.ts +12 -17
  262. package/src/lib/record/form-approvals.js +14 -8
  263. package/src/lib/record/form-approvals.js.map +1 -1
  264. package/src/lib/record/form-approvals.mjs +13 -7
  265. package/src/lib/record/form-approvals.mjs.map +1 -1
  266. package/src/lib/record/form-limits.d.mts +4 -28
  267. package/src/lib/record/form-limits.d.ts +4 -28
  268. package/src/lib/record/form-limits.js +8 -5
  269. package/src/lib/record/form-limits.js.map +1 -1
  270. package/src/lib/record/form-limits.mjs +8 -5
  271. package/src/lib/record/form-limits.mjs.map +1 -1
  272. package/src/lib/record/form.d.mts +115 -3
  273. package/src/lib/record/form.d.ts +115 -3
  274. package/src/lib/record/form.js +262 -65
  275. package/src/lib/record/form.js.map +1 -1
  276. package/src/lib/record/form.mjs +263 -66
  277. package/src/lib/record/form.mjs.map +1 -1
  278. package/src/lib/record/history-steps.d.mts +38 -0
  279. package/src/lib/record/history-steps.d.ts +38 -0
  280. package/src/lib/record/history-steps.js +63 -0
  281. package/src/lib/record/history-steps.js.map +1 -0
  282. package/src/lib/record/history-steps.mjs +58 -0
  283. package/src/lib/record/history-steps.mjs.map +1 -0
  284. package/src/lib/record/history.d.mts +16 -0
  285. package/src/lib/record/history.d.ts +16 -0
  286. package/src/lib/record/history.js +3 -0
  287. package/src/lib/record/history.js.map +1 -0
  288. package/src/lib/record/history.mjs +2 -0
  289. package/src/lib/record/history.mjs.map +1 -0
  290. package/src/lib/record/input-rules.d.mts +2 -0
  291. package/src/lib/record/input-rules.d.ts +2 -0
  292. package/src/lib/record/input-rules.js +4 -1
  293. package/src/lib/record/input-rules.js.map +1 -1
  294. package/src/lib/record/input-rules.mjs +2 -0
  295. package/src/lib/record/input-rules.mjs.map +1 -1
  296. package/src/lib/record/joins.d.mts +143 -0
  297. package/src/lib/record/joins.d.ts +143 -0
  298. package/src/lib/record/joins.js +28 -0
  299. package/src/lib/record/joins.js.map +1 -0
  300. package/src/lib/record/joins.mjs +24 -0
  301. package/src/lib/record/joins.mjs.map +1 -0
  302. package/src/lib/record/limits.js +7 -4
  303. package/src/lib/record/limits.js.map +1 -1
  304. package/src/lib/record/limits.mjs +8 -5
  305. package/src/lib/record/limits.mjs.map +1 -1
  306. package/src/lib/record/link-values.d.mts +31 -0
  307. package/src/lib/record/link-values.d.ts +31 -0
  308. package/src/lib/record/link-values.js +132 -0
  309. package/src/lib/record/link-values.js.map +1 -0
  310. package/src/lib/record/link-values.mjs +125 -0
  311. package/src/lib/record/link-values.mjs.map +1 -0
  312. package/src/lib/record/live-later.d.mts +15 -0
  313. package/src/lib/record/live-later.d.ts +15 -0
  314. package/src/lib/record/live-later.js +10 -0
  315. package/src/lib/record/live-later.js.map +1 -0
  316. package/src/lib/record/live-later.mjs +7 -0
  317. package/src/lib/record/live-later.mjs.map +1 -0
  318. package/src/lib/record/live-part.d.mts +6 -0
  319. package/src/lib/record/live-part.d.ts +6 -0
  320. package/src/lib/record/live-part.js +12 -0
  321. package/src/lib/record/live-part.js.map +1 -0
  322. package/src/lib/record/live-part.mjs +7 -0
  323. package/src/lib/record/live-part.mjs.map +1 -0
  324. package/src/lib/record/live.d.mts +8 -0
  325. package/src/lib/record/live.d.ts +8 -0
  326. package/src/lib/record/live.js +133 -0
  327. package/src/lib/record/live.js.map +1 -0
  328. package/src/lib/record/live.mjs +129 -0
  329. package/src/lib/record/live.mjs.map +1 -0
  330. package/src/lib/record/locales/all.d.mts +5 -5
  331. package/src/lib/record/locales/all.d.ts +5 -5
  332. package/src/lib/record/locales/all.js +3 -3
  333. package/src/lib/record/locales/all.js.map +1 -1
  334. package/src/lib/record/locales/all.mjs +3 -3
  335. package/src/lib/record/locales/all.mjs.map +1 -1
  336. package/src/lib/record/locales/ar.js +8 -0
  337. package/src/lib/record/locales/ar.js.map +1 -1
  338. package/src/lib/record/locales/ar.mjs +8 -0
  339. package/src/lib/record/locales/ar.mjs.map +1 -1
  340. package/src/lib/record/locales/de.js +8 -0
  341. package/src/lib/record/locales/de.js.map +1 -1
  342. package/src/lib/record/locales/de.mjs +8 -0
  343. package/src/lib/record/locales/de.mjs.map +1 -1
  344. package/src/lib/record/locales/es.d.mts +8 -0
  345. package/src/lib/record/locales/es.d.ts +8 -0
  346. package/src/lib/record/locales/es.js +111 -0
  347. package/src/lib/record/locales/es.js.map +1 -0
  348. package/src/lib/record/locales/es.mjs +108 -0
  349. package/src/lib/record/locales/es.mjs.map +1 -0
  350. package/src/lib/record/locales/fa.d.mts +5 -0
  351. package/src/lib/record/locales/fa.d.ts +5 -0
  352. package/src/lib/record/locales/fa.js +117 -0
  353. package/src/lib/record/locales/fa.js.map +1 -0
  354. package/src/lib/record/locales/fa.mjs +114 -0
  355. package/src/lib/record/locales/fa.mjs.map +1 -0
  356. package/src/lib/record/locales/fr.js +8 -0
  357. package/src/lib/record/locales/fr.js.map +1 -1
  358. package/src/lib/record/locales/fr.mjs +8 -0
  359. package/src/lib/record/locales/fr.mjs.map +1 -1
  360. package/src/lib/record/locales/later.d.mts +8 -0
  361. package/src/lib/record/locales/later.d.ts +8 -0
  362. package/src/lib/record/locales/later.js +16 -0
  363. package/src/lib/record/locales/later.js.map +1 -0
  364. package/src/lib/record/locales/later.mjs +13 -0
  365. package/src/lib/record/locales/later.mjs.map +1 -0
  366. package/src/lib/record/locales/tr.d.mts +6 -0
  367. package/src/lib/record/locales/tr.d.ts +6 -0
  368. package/src/lib/record/locales/tr.js +118 -0
  369. package/src/lib/record/locales/tr.js.map +1 -0
  370. package/src/lib/record/locales/tr.mjs +115 -0
  371. package/src/lib/record/locales/tr.mjs.map +1 -0
  372. package/src/lib/record/locales/ur.d.mts +9 -0
  373. package/src/lib/record/locales/ur.d.ts +9 -0
  374. package/src/lib/record/locales/ur.js +118 -0
  375. package/src/lib/record/locales/ur.js.map +1 -0
  376. package/src/lib/record/locales/ur.mjs +115 -0
  377. package/src/lib/record/locales/ur.mjs.map +1 -0
  378. package/src/lib/record/memory-codes.d.mts +37 -0
  379. package/src/lib/record/memory-codes.d.ts +37 -0
  380. package/src/lib/record/memory-codes.js +50 -0
  381. package/src/lib/record/memory-codes.js.map +1 -0
  382. package/src/lib/record/memory-codes.mjs +47 -0
  383. package/src/lib/record/memory-codes.mjs.map +1 -0
  384. package/src/lib/record/memory-data-source.d.mts +56 -2
  385. package/src/lib/record/memory-data-source.d.ts +56 -2
  386. package/src/lib/record/memory-data-source.js +67 -1
  387. package/src/lib/record/memory-data-source.js.map +1 -1
  388. package/src/lib/record/memory-data-source.mjs +67 -1
  389. package/src/lib/record/memory-data-source.mjs.map +1 -1
  390. package/src/lib/record/memory-kept.d.mts +3 -1
  391. package/src/lib/record/memory-kept.d.ts +3 -1
  392. package/src/lib/record/memory-kept.js +7 -2
  393. package/src/lib/record/memory-kept.js.map +1 -1
  394. package/src/lib/record/memory-kept.mjs +7 -2
  395. package/src/lib/record/memory-kept.mjs.map +1 -1
  396. package/src/lib/record/memory-later.d.mts +3 -1
  397. package/src/lib/record/memory-later.d.ts +3 -1
  398. package/src/lib/record/memory-later.js +9 -5
  399. package/src/lib/record/memory-later.js.map +1 -1
  400. package/src/lib/record/memory-later.mjs +8 -4
  401. package/src/lib/record/memory-later.mjs.map +1 -1
  402. package/src/lib/record/memory-live.d.mts +8 -0
  403. package/src/lib/record/memory-live.d.ts +8 -0
  404. package/src/lib/record/memory-live.js +70 -0
  405. package/src/lib/record/memory-live.js.map +1 -0
  406. package/src/lib/record/memory-live.mjs +67 -0
  407. package/src/lib/record/memory-live.mjs.map +1 -0
  408. package/src/lib/record/memory-views.d.mts +11 -0
  409. package/src/lib/record/memory-views.d.ts +11 -0
  410. package/src/lib/record/memory-views.js +60 -0
  411. package/src/lib/record/memory-views.js.map +1 -0
  412. package/src/lib/record/memory-views.mjs +57 -0
  413. package/src/lib/record/memory-views.mjs.map +1 -0
  414. package/src/lib/record/messages.d.mts +21 -3
  415. package/src/lib/record/messages.d.ts +21 -3
  416. package/src/lib/record/messages.js +15 -2
  417. package/src/lib/record/messages.js.map +1 -1
  418. package/src/lib/record/messages.mjs +15 -2
  419. package/src/lib/record/messages.mjs.map +1 -1
  420. package/src/lib/record/order.d.mts +21 -0
  421. package/src/lib/record/order.d.ts +21 -0
  422. package/src/lib/record/order.js +129 -0
  423. package/src/lib/record/order.js.map +1 -0
  424. package/src/lib/record/order.mjs +122 -0
  425. package/src/lib/record/order.mjs.map +1 -0
  426. package/src/lib/record/outbox-form.d.mts +79 -0
  427. package/src/lib/record/outbox-form.d.ts +79 -0
  428. package/src/lib/record/outbox-form.js +291 -0
  429. package/src/lib/record/outbox-form.js.map +1 -0
  430. package/src/lib/record/outbox-form.mjs +286 -0
  431. package/src/lib/record/outbox-form.mjs.map +1 -0
  432. package/src/lib/record/outbox-part.d.mts +6 -0
  433. package/src/lib/record/outbox-part.d.ts +6 -0
  434. package/src/lib/record/outbox-part.js +13 -0
  435. package/src/lib/record/outbox-part.js.map +1 -0
  436. package/src/lib/record/outbox-part.mjs +7 -0
  437. package/src/lib/record/outbox-part.mjs.map +1 -0
  438. package/src/lib/record/pay-part.d.mts +6 -0
  439. package/src/lib/record/pay-part.d.ts +6 -0
  440. package/src/lib/record/pay-part.js +11 -0
  441. package/src/lib/record/pay-part.js.map +1 -0
  442. package/src/lib/record/pay-part.mjs +7 -0
  443. package/src/lib/record/pay-part.mjs.map +1 -0
  444. package/src/lib/record/payment-form.d.mts +25 -0
  445. package/src/lib/record/payment-form.d.ts +25 -0
  446. package/src/lib/record/payment-form.js +98 -0
  447. package/src/lib/record/payment-form.js.map +1 -0
  448. package/src/lib/record/payment-form.mjs +95 -0
  449. package/src/lib/record/payment-form.mjs.map +1 -0
  450. package/src/lib/record/prefill-part.d.mts +7 -0
  451. package/src/lib/record/prefill-part.d.ts +7 -0
  452. package/src/lib/record/prefill-part.js +15 -0
  453. package/src/lib/record/prefill-part.js.map +1 -0
  454. package/src/lib/record/prefill-part.mjs +8 -0
  455. package/src/lib/record/prefill-part.mjs.map +1 -0
  456. package/src/lib/record/press-undo.d.mts +42 -0
  457. package/src/lib/record/press-undo.d.ts +42 -0
  458. package/src/lib/record/press-undo.js +115 -0
  459. package/src/lib/record/press-undo.js.map +1 -0
  460. package/src/lib/record/press-undo.mjs +110 -0
  461. package/src/lib/record/press-undo.mjs.map +1 -0
  462. package/src/lib/record/quiz.d.mts +36 -0
  463. package/src/lib/record/quiz.d.ts +36 -0
  464. package/src/lib/record/quiz.js +90 -0
  465. package/src/lib/record/quiz.js.map +1 -0
  466. package/src/lib/record/quiz.mjs +87 -0
  467. package/src/lib/record/quiz.mjs.map +1 -0
  468. package/src/lib/record/record-words.js +1 -1
  469. package/src/lib/record/record-words.js.map +1 -1
  470. package/src/lib/record/record-words.mjs +1 -1
  471. package/src/lib/record/record-words.mjs.map +1 -1
  472. package/src/lib/record/run.d.mts +54 -2
  473. package/src/lib/record/run.d.ts +54 -2
  474. package/src/lib/record/run.js +30 -6
  475. package/src/lib/record/run.js.map +1 -1
  476. package/src/lib/record/run.mjs +28 -5
  477. package/src/lib/record/run.mjs.map +1 -1
  478. package/src/lib/record/survey-kit.d.mts +37 -0
  479. package/src/lib/record/survey-kit.d.ts +37 -0
  480. package/src/lib/record/survey-kit.js +99 -0
  481. package/src/lib/record/survey-kit.js.map +1 -0
  482. package/src/lib/record/survey-kit.mjs +96 -0
  483. package/src/lib/record/survey-kit.mjs.map +1 -0
  484. package/src/lib/record/survey.d.mts +16 -0
  485. package/src/lib/record/survey.d.ts +16 -0
  486. package/src/lib/record/survey.js +17 -0
  487. package/src/lib/record/survey.js.map +1 -0
  488. package/src/lib/record/survey.mjs +13 -0
  489. package/src/lib/record/survey.mjs.map +1 -0
  490. package/src/lib/record/surveyflow-part.d.mts +9 -0
  491. package/src/lib/record/surveyflow-part.d.ts +9 -0
  492. package/src/lib/record/surveyflow-part.js +20 -0
  493. package/src/lib/record/surveyflow-part.js.map +1 -0
  494. package/src/lib/record/surveyflow-part.mjs +10 -0
  495. package/src/lib/record/surveyflow-part.mjs.map +1 -0
  496. package/src/lib/record/timing.d.mts +76 -0
  497. package/src/lib/record/timing.d.ts +76 -0
  498. package/src/lib/record/timing.js +112 -0
  499. package/src/lib/record/timing.js.map +1 -0
  500. package/src/lib/record/timing.mjs +104 -0
  501. package/src/lib/record/timing.mjs.map +1 -0
  502. package/src/lib/record/undo-later.d.mts +9 -0
  503. package/src/lib/record/undo-later.d.ts +9 -0
  504. package/src/lib/record/undo-later.js +10 -0
  505. package/src/lib/record/undo-later.js.map +1 -0
  506. package/src/lib/record/undo-later.mjs +7 -0
  507. package/src/lib/record/undo-later.mjs.map +1 -0
  508. package/src/lib/record/undo-part.d.mts +8 -0
  509. package/src/lib/record/undo-part.d.ts +8 -0
  510. package/src/lib/record/undo-part.js +17 -0
  511. package/src/lib/record/undo-part.js.map +1 -0
  512. package/src/lib/record/undo-part.mjs +9 -0
  513. package/src/lib/record/undo-part.mjs.map +1 -0
  514. package/src/lib/record/upload-to-later.d.mts +10 -0
  515. package/src/lib/record/upload-to-later.d.ts +10 -0
  516. package/src/lib/record/upload-to-later.js +15 -0
  517. package/src/lib/record/upload-to-later.js.map +1 -0
  518. package/src/lib/record/upload-to-later.mjs +12 -0
  519. package/src/lib/record/upload-to-later.mjs.map +1 -0
  520. package/src/lib/record/uploads.d.mts +5 -0
  521. package/src/lib/record/uploads.d.ts +5 -0
  522. package/src/lib/record/uploads.js.map +1 -1
  523. package/src/lib/record/uploads.mjs.map +1 -1
  524. package/src/lib/record/values.d.mts +6 -0
  525. package/src/lib/record/values.d.ts +6 -0
  526. package/src/lib/record/values.js.map +1 -1
  527. package/src/lib/record/values.mjs.map +1 -1
  528. package/src/lib/record/verify-form.d.mts +24 -0
  529. package/src/lib/record/verify-form.d.ts +24 -0
  530. package/src/lib/record/verify-form.js +65 -0
  531. package/src/lib/record/verify-form.js.map +1 -0
  532. package/src/lib/record/verify-form.mjs +62 -0
  533. package/src/lib/record/verify-form.mjs.map +1 -0
  534. package/src/lib/record/verify-part.d.mts +6 -0
  535. package/src/lib/record/verify-part.d.ts +6 -0
  536. package/src/lib/record/verify-part.js +11 -0
  537. package/src/lib/record/verify-part.js.map +1 -0
  538. package/src/lib/record/verify-part.mjs +7 -0
  539. package/src/lib/record/verify-part.mjs.map +1 -0
  540. package/src/lib/record/words-chunks.d.mts +37 -0
  541. package/src/lib/record/words-chunks.d.ts +37 -0
  542. package/src/lib/record/words-chunks.js +94 -0
  543. package/src/lib/record/words-chunks.js.map +1 -0
  544. package/src/lib/record/words-chunks.mjs +86 -0
  545. package/src/lib/record/words-chunks.mjs.map +1 -0
  546. package/src/runtime.d.mts +28 -6
  547. package/src/runtime.d.ts +28 -6
  548. package/src/runtime.js +35 -6
  549. package/src/runtime.js.map +1 -1
  550. package/src/runtime.mjs +15 -3
  551. package/src/runtime.mjs.map +1 -1
@@ -28,12 +28,13 @@ const line_choices_1 = require("./line-choices");
28
28
  const data_source_1 = require("./data-source");
29
29
  const taking_1 = require("./taking");
30
30
  const languages_1 = require("./languages");
31
- const approving_1 = require("./approving");
32
31
  const drafts_1 = require("./drafts");
33
32
  const waits_1 = require("./waits");
34
33
  const uploads_1 = require("./uploads");
35
34
  const scheduler_1 = require("./scheduler");
36
35
  const signed_1 = require("./signed");
36
+ const joins_1 = require("./joins");
37
+ const undo_later_1 = require("./undo-later");
37
38
  const run_1 = require("./run");
38
39
  const values_1 = require("./values");
39
40
  /**
@@ -95,7 +96,9 @@ function innerForm(options, within, place, outer) {
95
96
  // A field's label small inside a message's sentence where the page asks (`lowerLabels`).
96
97
  // …and a day written in the page's order where it says one (`look.dateOrder`): "can't be after Oct 20, 2026".
97
98
  const dateOrder = page.look?.dateOrder;
98
- const messages = page.lowerLabels || dateOrder ? { ...(options.messages ?? messages_1.MESSAGES.en), lowerLabels: page.lowerLabels, dateOrder } : (options.messages ?? messages_1.MESSAGES.en);
99
+ // The page's ask over the language's messages, each read through to them as it is said: a language whose words come in a
100
+ // chunk of their own fills its table in place once they have come (words-chunks.ts).
101
+ const messages = page.lowerLabels || dateOrder ? Object.assign(Object.create(options.messages ?? messages_1.MESSAGES.en), { lowerLabels: page.lowerLabels, dateOrder }) : (options.messages ?? messages_1.MESSAGES.en);
99
102
  /** One of the form's sentences in the words the page names its records by (`records`), else as the language says it plainly. */
100
103
  const named = (noun, plain) => (0, record_words_1.recordSentence)(page.records, noun, plain, messages.locale);
101
104
  /** The app's functions the page's expressions call: a name none may call is refused now. */
@@ -192,7 +195,23 @@ function innerForm(options, within, place, outer) {
192
195
  placeholderOf('#title', page.layout.title);
193
196
  /** Whether any rule only warns: without one, there are never warnings to look for. */
194
197
  const warns = [...nodeRules.values()].some((rules) => rules.some((compiled) => compiled.rule.level === 'warning'));
195
- const steps = page.layout.type === 'wizard' ? page.layout.children.map((step) => step.id) : [];
198
+ const layoutSteps = page.layout.type === 'wizard' ? page.layout.children.map((step) => step.id) : [];
199
+ /** The wizard's steps in the order shown: the page's, or the order drawn for this respondent (`state.order`). */
200
+ let steps = layoutSteps;
201
+ /**
202
+ * The parts that join this form where its page or its source asks (`formJoins`: an offline outbox, the fields its link
203
+ * fills, proof by a code, a payment, a survey's flow, a record's approvals, the record made live), each made as it
204
+ * comes — at once where it has — and kept in their order: holes until then. While one has not come, a send waits for it
205
+ * (`joining`); a draft laid before one came is laid on it as it does (`laid`).
206
+ */
207
+ const joins = [];
208
+ const joinParts = (0, joins_1.formJoins)(page, options).filter((part) => !outer || part.name !== 'approvals');
209
+ let joining;
210
+ let laid = null;
211
+ /** A part's side of this form, by its name, once it came. */
212
+ const joined = (name) => (joins[joinParts.findIndex((part) => part.name === name)] ?? null);
213
+ /** Whether a part that joins the form says so of a part of the page, or of a field. */
214
+ const anyJoin = (says) => joins.some((join) => join && says(join));
196
215
  const storeKey = () => `fieldia:draft:${page.id}:${state.recordId ?? 'new'}`;
197
216
  /** Today, on the clock of the page's time zone (the browser's own when it names none). */
198
217
  const today = () => (0, zones_1.dayIn)(options.now?.() ?? new Date(), page.timeZone);
@@ -370,6 +389,9 @@ function innerForm(options, within, place, outer) {
370
389
  limits: null,
371
390
  resume: null,
372
391
  approval: null,
392
+ order: null,
393
+ timers: {},
394
+ timeUp: [],
373
395
  };
374
396
  started = true;
375
397
  /**
@@ -462,6 +484,8 @@ function innerForm(options, within, place, outer) {
462
484
  filesChanged();
463
485
  },
464
486
  track,
487
+ // Through the parts that join the form: a photo taken without signal kept as its bytes, on a page with an outbox.
488
+ through,
465
489
  });
466
490
  /**
467
491
  * Files on their way changed, here or in a saved form placed here: the
@@ -559,6 +583,87 @@ function innerForm(options, within, place, outer) {
559
583
  const listed = (0, line_choices_1.listedColumns)(page.fields);
560
584
  /** Whether the values set now are a change someone made (`writeValues`), after which a line's choice no longer offered is cleared. */
561
585
  let edit = false;
586
+ /**
587
+ * The one kit the parts that work inside the form are given of it (joins.ts): the parts that join it, its limits, the
588
+ * undo part's press.
589
+ */
590
+ const inner = {
591
+ get form() {
592
+ return form;
593
+ },
594
+ page,
595
+ fields,
596
+ options,
597
+ messages,
598
+ scheduler,
599
+ state: () => state,
600
+ set,
601
+ reading,
602
+ sending: () => (page.data.kind === 'responses' ? answersSent() : sentValues()),
603
+ baseline: () => baseline,
604
+ same: (name, one, other) => sameValue(fields[name], one, other),
605
+ conflictOf,
606
+ store,
607
+ settled: savesSettled,
608
+ track,
609
+ shownNow,
610
+ generation: () => generation,
611
+ emit,
612
+ replaced,
613
+ clock,
614
+ started: () => started,
615
+ listened: () => listeners.size > 0,
616
+ disposed: () => disposed,
617
+ keep: () => void ((options.drafts || onServer()) && scheduleDraft()),
618
+ order: (list) => void (steps = list ?? layoutSteps),
619
+ refuse(name, message) {
620
+ // Said until the field changes from what it holds, as a refused save's words are.
621
+ serverErrors[name] = { message, value: JSON.stringify(state.values[name] ?? null) };
622
+ set({ errors: { ...state.errors, [name]: message } });
623
+ },
624
+ reload: () => load(true),
625
+ };
626
+ /** The person's changes to the record shown, as made (history.ts); and whether one is being taken back or made again now. */
627
+ let noted = [];
628
+ let replaying = false;
629
+ /**
630
+ * A person's change written to `field` (on `line`), noted for Undo with what it held `before`: typing on joins it
631
+ * (`joins`). The undo part takes them as they come, asked for with the first: in by the time the person presses Ctrl+Z.
632
+ */
633
+ const noteChange = (field, line, before, joins) => {
634
+ if (replaying)
635
+ return;
636
+ noted.push([field, line, before ?? null, state.values[field] ?? null, joins]);
637
+ const part = undo_later_1.pressUndoPart.loaded;
638
+ if (part)
639
+ part.takeNoted(noted, inner.same);
640
+ // Kept while it comes; where it cannot, the oldest let go.
641
+ else if (noted.length > 500)
642
+ noted.shift();
643
+ else
644
+ undo_later_1.pressUndoPart.load().catch(() => undefined);
645
+ };
646
+ /**
647
+ * Undo (`back`) or Redo, once the undo part has come: the change taken, written as the person's own change back —
648
+ * the page's `change` steps and the source's onchange run as for any — once its field still holds what the change
649
+ * left and may be changed.
650
+ */
651
+ function replay(back) {
652
+ const step = editing ? undo_later_1.pressUndoPart.loaded?.takeStep(noted, inner.same, back, (one, left) => !form.fieldReadonly(one.field) && sameValue(fields[one.field], state.values[one.field], left)) : null;
653
+ if (!step)
654
+ return null;
655
+ const { value, ...taken } = step;
656
+ replaying = true;
657
+ try {
658
+ writeValues({ ...state.values, [taken.field]: (0, values_1.structuredCopy)(value) });
659
+ afterEdit(taken.field);
660
+ changed(taken.field, 'person', taken.line === undefined ? {} : { line: taken.line });
661
+ }
662
+ finally {
663
+ replaying = false;
664
+ }
665
+ return taken;
666
+ }
562
667
  function set(patch) {
563
668
  const was = state.values;
564
669
  const choicesWas = state.choices;
@@ -592,6 +697,10 @@ function innerForm(options, within, place, outer) {
592
697
  part.inner.show(inside(state.errors, part.name));
593
698
  for (const listener of [...listeners])
594
699
  listener(state);
700
+ // What the parts that join the form follow of it: the record shown, watched for changes made elsewhere and for who
701
+ // else has it open, asked again as that changes.
702
+ for (const join of joins)
703
+ join?.changed?.();
595
704
  // Choices that change with a value that just changed are asked for again.
596
705
  if (state.values !== was) {
597
706
  // After someone's change, a choice its new choices do not offer is taken out and said, as a line's is.
@@ -631,6 +740,7 @@ function innerForm(options, within, place, outer) {
631
740
  /** Another record is shown: nothing of the last one's is the person's work any more, and its files on their way stop. */
632
741
  function newGeneration() {
633
742
  generation++;
743
+ noted = [];
634
744
  // Another record's lines ask the source anew.
635
745
  lineAsks = new Map();
636
746
  answers = new Map();
@@ -743,6 +853,9 @@ function innerForm(options, within, place, outer) {
743
853
  return;
744
854
  told = step;
745
855
  emit('step', { step });
856
+ // A step with a time limit: its clock starts as it is first entered.
857
+ for (const join of joins)
858
+ join?.entered?.(step);
746
859
  const list = page.on?.show?.[step];
747
860
  if (list)
748
861
  void track(moment(`on.show.${step}`, list, chain, true));
@@ -1114,13 +1227,13 @@ function innerForm(options, within, place, outer) {
1114
1227
  if (!node)
1115
1228
  throw new Error(`The page has no element "${id}"`);
1116
1229
  const { context: ctx, env } = reading();
1117
- const hidden = (at) => (at ? !(0, roles_1.rolesAllow)(at.roles, userRoles) || at.invisible.evaluate(ctx, env) : false);
1230
+ const hidden = (at) => (at ? anyJoin((join) => join.hides?.(at.id)) || !(0, roles_1.rolesAllow)(at.roles, userRoles) || at.invisible.evaluate(ctx, env) : false);
1118
1231
  let invisible = hidden(node);
1119
1232
  for (let parent = node.parent; !invisible && parent; parent = index.get(parent)?.parent ?? null) {
1120
1233
  invisible = hidden(index.get(parent));
1121
1234
  }
1122
- // A section read-only right now makes everything inside it read-only too.
1123
- let readonly = node.readonly.evaluate(ctx, env);
1235
+ // A section read-only right now makes everything inside it read-only too; a page's, or a step's, time run out too.
1236
+ let readonly = node.readonly.evaluate(ctx, env) || anyJoin((join) => join.locks?.(id));
1124
1237
  for (let parent = node.parent; !readonly && parent; parent = index.get(parent)?.parent ?? null) {
1125
1238
  readonly = index.get(parent)?.readonly.evaluate(ctx, env) ?? false;
1126
1239
  }
@@ -1138,7 +1251,7 @@ function innerForm(options, within, place, outer) {
1138
1251
  if (answer !== undefined && signedNow().has(answer))
1139
1252
  readonly = true;
1140
1253
  // A record waiting for approval: locked but for the fields the page leaves open (the approvals part).
1141
- if (answer !== undefined && approvalKit?.locks(answer))
1254
+ if (answer !== undefined && anyJoin((join) => join.locksField?.(answer)))
1142
1255
  readonly = true;
1143
1256
  return {
1144
1257
  invisible,
@@ -1280,6 +1393,9 @@ function innerForm(options, within, place, outer) {
1280
1393
  const errors = {};
1281
1394
  const seen = new Set();
1282
1395
  for (const node of visibleFieldNodes(root)) {
1396
+ // The answers of a time run out go as they stood: their checks refuse nothing.
1397
+ if (anyJoin((join) => join.locks?.(node.id)))
1398
+ continue;
1283
1399
  const name = node.field;
1284
1400
  seen.add(name);
1285
1401
  const end = rangeEnd(node);
@@ -1588,6 +1704,7 @@ function innerForm(options, within, place, outer) {
1588
1704
  return {
1589
1705
  values,
1590
1706
  ...(steps.length ? { step: state.step, skipped: [...state.skipped] } : {}),
1707
+ ...Object.assign({}, ...joins.map((join) => join?.kept?.())),
1591
1708
  ...(Object.keys(state.unread).length ? { unread: (0, values_1.structuredCopy)(state.unread) } : {}),
1592
1709
  answered: Object.keys(fields).filter((name) => state.dirty.includes(name)),
1593
1710
  savedAt: new Date(clock()).toISOString(),
@@ -1643,6 +1760,10 @@ function innerForm(options, within, place, outer) {
1643
1760
  /** A draft laid on the form: its answers as a starting point, its wizard step (or the nearest before it that applies), its text that does not read. */
1644
1761
  function applyDraft(draft) {
1645
1762
  found = null;
1763
+ // Its draw and its clocks, by the survey flow's part: now, or once it came.
1764
+ laid = draft;
1765
+ for (const join of joins)
1766
+ join?.lay?.(draft);
1646
1767
  writeValues(withDraft(draft.values ?? {}), { draft: null }, true);
1647
1768
  const known = (draft.skipped ?? []).filter((id) => steps.includes(id));
1648
1769
  // Text typed that did not read stays as typed, said as it was, where its field is still on the page.
@@ -1737,27 +1858,8 @@ function innerForm(options, within, place, outer) {
1737
1858
  function limitsMade(part) {
1738
1859
  if (limitsKit || disposed)
1739
1860
  return limitsKit;
1740
- const kit = part.formLimits({
1741
- page,
1742
- dataSource: options.dataSource,
1743
- user: options.user,
1744
- messages,
1745
- scheduler,
1746
- state: () => state,
1747
- set,
1748
- clock,
1749
- started: () => started,
1750
- shownNow,
1751
- generation: () => generation,
1752
- replaced: () => named(messages.recordReplacedNoun, messages.recordReplaced),
1753
- listened: () => listeners.size > 0,
1754
- disposed: () => disposed,
1755
- refuse(name, message) {
1756
- // Said until the field changes from what it holds, as a refused save's words are.
1757
- serverErrors[name] = { message, value: JSON.stringify(state.values[name] ?? null) };
1758
- set({ errors: { ...state.errors, [name]: message } });
1759
- },
1760
- });
1861
+ // The one kit, made at the limits' own moment: once the form knows it keeps them (joins.ts).
1862
+ const kit = part.formLimits(inner);
1761
1863
  limitsKit = kit;
1762
1864
  kit.show();
1763
1865
  if (kit.asks() && (state.recordId == null || loadedOnce))
@@ -1778,15 +1880,6 @@ function innerForm(options, within, place, outer) {
1778
1880
  }
1779
1881
  /** A choice of a full option, picked by the person, refused under its field: the field keeps what it held. */
1780
1882
  const refusedFull = (name, value) => !!limitsKit?.refusedFull(name, value);
1781
- // ---- a record's approvals (the approvals part: form-approvals.ts) ---------------------------------------------------
1782
- /** The approvals made for this form from the approvals part, once it came: none before, nor on a page without them. */
1783
- let approvalKit = null;
1784
- /** Whether the form asks for approvals: a page with `approval` (a record's own, as its check says), its source telling them. */
1785
- const keepsApprovals = !outer && !!page.approval && !!options.dataSource?.approvals;
1786
- /** The approvals, made from their part once it came; null without them, or where it could not come. */
1787
- const approvalsCode = () => keepsApprovals ? approving_1.formApprovalsPart.load().then((part) => (approvalKit ??= part.formApprovals({ form, dataSource: options.dataSource, messages, set, reload: () => load(true) })), () => null) : Promise.resolve(null);
1788
- /** Ask the record shown's approvals, once their part came; nothing on a page without them. */
1789
- const askApprovals = () => approvalsCode().then((kit) => kit?.ask());
1790
1883
  function scheduleAutosave() {
1791
1884
  const autosave = options.autosave;
1792
1885
  // A record the person may not change is never saved unasked: it would only be refused.
@@ -1863,9 +1956,24 @@ function innerForm(options, within, place, outer) {
1863
1956
  }
1864
1957
  return shown;
1865
1958
  }
1959
+ /** A response's answers as they go: those shown, and what the parts that join the form add (a link's hidden fields). */
1960
+ function answersSent() {
1961
+ const values = shownValues();
1962
+ for (const join of joins)
1963
+ join.values?.(values);
1964
+ return values;
1965
+ }
1866
1966
  async function save(chain = [], yes) {
1867
1967
  return (await saving(chain, yes)) === null;
1868
1968
  }
1969
+ /** A send — a response's, a save's, an upload's — through the parts that join the form, each around the next. Null: kept, not sent. */
1970
+ function through(kind, sent, send) {
1971
+ return joins.reduce((go, join) => (join.around ? (one) => join.around(kind, one, go) : go), send)(sent);
1972
+ }
1973
+ /** Started again, or another record opened: the parts that join the form let go of what the one before had. */
1974
+ const joinsReset = () => joins.forEach((join) => join.reset?.());
1975
+ /** The record loaded, or saved: what the parts that join the form ask again (a record's approvals). */
1976
+ const joinsLoaded = () => joins.forEach((join) => join.loaded?.());
1869
1977
  /** Every value, for a source that saves whole records: those of fields hidden from the person, which they never had, left out. */
1870
1978
  function sentValues() {
1871
1979
  const values = (0, values_1.structuredCopy)(state.values);
@@ -1973,8 +2081,22 @@ function innerForm(options, within, place, outer) {
1973
2081
  const refused = await stillTaking(asked);
1974
2082
  if (refused)
1975
2083
  return refused;
1976
- // A file that did not reach the store stops it, under its field, with the form's own checks.
2084
+ // The parts that join the form (`formJoins`), waited for where they have not come.
2085
+ if (joining) {
2086
+ await joining;
2087
+ if (asked !== generation)
2088
+ return elsewhere();
2089
+ }
2090
+ // A file that did not reach the store stops it, under its field, with the form's own checks — and what the parts that
2091
+ // join the form find: an email or a phone not proved by a code; a payment not taken sends nothing.
1977
2092
  const errors = { ...collectErrors(), ...fileProblems() };
2093
+ for (const join of joins) {
2094
+ // A part that never came (a hole) has nothing to say.
2095
+ if ((await join?.before?.(errors)) === false)
2096
+ return { reason: 'save' };
2097
+ if (asked !== generation)
2098
+ return elsewhere();
2099
+ }
1978
2100
  if (Object.keys(errors).length) {
1979
2101
  set({ errors, ...unstored(errors) });
1980
2102
  return { reason: 'save', message: Object.values(errors)[0] };
@@ -2004,13 +2126,18 @@ function innerForm(options, within, place, outer) {
2004
2126
  if (page.data.kind === 'responses') {
2005
2127
  if (!source?.submit)
2006
2128
  throw new Error('This page has no data source to send its answers to');
2007
- const sent = shownValues();
2129
+ const sent = answersSent();
2008
2130
  const before = state.values;
2009
2131
  at = generation;
2010
2132
  const resetAt = resets;
2011
2133
  const seen = botReport();
2134
+ // A quiz's marking, in before the answers go: what the person sees of their results.
2012
2135
  // What the source answered: the id it gave the response, and the values it added — what an ending reads.
2013
- const answer = (await source.submit({ pageId: page.id, values: sent, ...(seen ? { bot: seen } : {}), ...draft })) ?? {};
2136
+ const request = { pageId: page.id, values: sent, ...(seen ? { bot: seen } : {}), ...draft };
2137
+ // Through the parts that join the form: kept on the device where an outbox finds no signal (null), the form going
2138
+ // on as though it went.
2139
+ const got = await through('submit', request, (one) => source.submit(one));
2140
+ const answer = got ?? {};
2014
2141
  // The captcha's token is spent once sent: the next send waits for a new one.
2015
2142
  if (seen?.captcha)
2016
2143
  bot.captcha = null;
@@ -2022,8 +2149,13 @@ function innerForm(options, within, place, outer) {
2022
2149
  sentAs = before;
2023
2150
  const added = answer.values && typeof answer.values === 'object' ? (0, values_1.structuredCopy)(answer.values) : {};
2024
2151
  // Started again meanwhile (`reset`): a new response is on screen, and no ending is the old one's.
2025
- set({ status: 'saved', unsent: unsentNow(), ...(resets === resetAt ? { sent: { id: answer.id ?? null, values: { ...(0, values_1.structuredCopy)(sent), ...added } } } : {}) });
2152
+ // A quiz's results: the source's marking, else the page's, on the answers as sent.
2153
+ const quiz = answer.quiz ?? joined('surveyflow')?.marked(sent);
2154
+ set({ status: 'saved', unsent: unsentNow(), ...(resets === resetAt ? { sent: { id: answer.id ?? null, values: { ...(0, values_1.structuredCopy)(sent), ...added }, ...(quiz ? { quiz } : {}) } } : {}) });
2026
2155
  emit('send', { values: sent, ...(seen ? { bot: seen } : {}) });
2156
+ // Kept, not sent: its counts and its after-save steps wait for a send that went.
2157
+ if (got === null)
2158
+ return null;
2027
2159
  // Counted again: one response fewer to take, this person's sent.
2028
2160
  if (asksLimits())
2029
2161
  void track(askLimits());
@@ -2036,7 +2168,7 @@ function innerForm(options, within, place, outer) {
2036
2168
  const sent = state.values;
2037
2169
  at = generation;
2038
2170
  const resetAt = resets;
2039
- const result = await source.save({
2171
+ const request = {
2040
2172
  model: page.data.model,
2041
2173
  id: state.recordId,
2042
2174
  fields,
@@ -2045,7 +2177,10 @@ function innerForm(options, within, place, outer) {
2045
2177
  // The version it was opened at, for a source that refuses a save over someone else's.
2046
2178
  ...(state.recordId != null && state.version ? { version: state.version } : {}),
2047
2179
  ...draft,
2048
- });
2180
+ };
2181
+ const got = await through('save', request, (one) => source.save(one));
2182
+ // Kept on the device (null): the record as it was, its version too.
2183
+ const result = got ?? { id: state.recordId, version: state.version ?? undefined };
2049
2184
  // Answered for a record no longer shown — another opened, or this one loaded again: the source has it, and the
2050
2185
  // form lays nothing of it over the record it shows now.
2051
2186
  if (at !== generation)
@@ -2064,11 +2199,11 @@ function innerForm(options, within, place, outer) {
2064
2199
  scheduleAutosave();
2065
2200
  }
2066
2201
  // A save may have sent it for approval, or moved it on: its approvals asked again.
2067
- if (keepsApprovals)
2068
- void track(askApprovals());
2202
+ joinsLoaded();
2069
2203
  // The record as this save left it: a change made while it was on its way is no value of it.
2070
2204
  emit('save', { recordId: state.recordId, values: baseline });
2071
- void track(moment('on.afterSave', page.on?.afterSave, chain, false));
2205
+ if (got)
2206
+ void track(moment('on.afterSave', page.on?.afterSave, chain, false));
2072
2207
  return null;
2073
2208
  }
2074
2209
  catch (error) {
@@ -2174,7 +2309,8 @@ function innerForm(options, within, place, outer) {
2174
2309
  }
2175
2310
  function addLine(field, values, by) {
2176
2311
  const def = lineField(field);
2177
- const current = state.values[field] ?? [];
2312
+ const before = state.values[field];
2313
+ const current = before ?? [];
2178
2314
  // A key no line holds: lines given (a line's own lines, back from its form) may hold new-… keys already.
2179
2315
  let key = `new-${++lineKeys}`;
2180
2316
  while (current.some((line) => line.key === key))
@@ -2187,6 +2323,8 @@ function innerForm(options, within, place, outer) {
2187
2323
  }
2188
2324
  const lines = [...current, line];
2189
2325
  writeValues({ ...state.values, [field]: lines });
2326
+ if (by === 'person')
2327
+ noteChange(field, key, before, false);
2190
2328
  afterEdit(field);
2191
2329
  changed(field, by, by === 'person' ? { line: key } : { keep: true });
2192
2330
  return key;
@@ -2331,8 +2469,7 @@ function innerForm(options, within, place, outer) {
2331
2469
  if (asksLimits())
2332
2470
  void track(askLimits());
2333
2471
  // Its approvals: where it stands, what was decided, what this person may decide — its fields locked while it waits.
2334
- if (keepsApprovals)
2335
- void track(askApprovals());
2472
+ joinsLoaded();
2336
2473
  if (again)
2337
2474
  return;
2338
2475
  offerDraft();
@@ -2368,6 +2505,7 @@ function innerForm(options, within, place, outer) {
2368
2505
  const fresh = { dirty: [], errors: {}, warning: null, warningField: null, error: null, draft: null, step: steps[0] ?? null, skipped: [], saveProblem: null, version: null, can: null, conflict: null, setAside: null, unsent: [], unread: {}, takenOut: {}, resume: null, approval: null };
2369
2506
  if (id != null) {
2370
2507
  set({ ...fresh, recordId: id, status: 'idle' });
2508
+ joinsReset();
2371
2509
  await load();
2372
2510
  return true;
2373
2511
  }
@@ -2375,6 +2513,7 @@ function innerForm(options, within, place, outer) {
2375
2513
  baseline = startFrom(startingValues(true, false));
2376
2514
  const values = syncParts((0, values_1.structuredCopy)(baseline), 'start');
2377
2515
  set({ ...fresh, recordId: null, status: 'ready', values, warnings: withValues(values, collectWarnings) });
2516
+ joinsReset();
2378
2517
  if (asksLimits())
2379
2518
  void track(askLimits());
2380
2519
  offerDraft();
@@ -2699,8 +2838,12 @@ function innerForm(options, within, place, outer) {
2699
2838
  const builtin = 'builtin' in source && !list.length ? source.builtin : undefined;
2700
2839
  if (builtin)
2701
2840
  list.push({ do: builtin });
2702
- const asked = builtin === 'archive' ? named(messages.archiveConfirmNoun, messages.archiveConfirm) : builtin === 'delete' ? named(messages.deleteConfirmNoun, messages.deleteConfirm) : undefined;
2841
+ // Undo after it, in place of asking first: a built-in with `undo` asks nothing unless it says so.
2842
+ const offers = 'undo' in source ? source.undo : undefined;
2843
+ const asked = offers !== undefined ? undefined : builtin === 'archive' ? named(messages.archiveConfirmNoun, messages.archiveConfirm) : builtin === 'delete' ? named(messages.deleteConfirmNoun, messages.deleteConfirm) : undefined;
2703
2844
  const confirm = 'confirm' in source && source.confirm !== undefined ? source.confirm : asked;
2845
+ if (offers !== undefined)
2846
+ scope.taken = (0, run_1.takenNow)(state.values);
2704
2847
  // Its question's Yes, and its ask steps', say what it does: its own words, else Archive or Delete.
2705
2848
  scope.yes ??= source.label || (builtin === 'archive' ? messages.archiveYes : builtin === 'delete' ? messages.deleteYes : undefined);
2706
2849
  // On the record it was pressed on: another shown while its question is asked, it does nothing to that one.
@@ -2734,9 +2877,21 @@ function innerForm(options, within, place, outer) {
2734
2877
  return result;
2735
2878
  }
2736
2879
  }
2737
- return runTop(list, scope);
2880
+ const result = await runTop(list, scope);
2881
+ if (scope.taken)
2882
+ offerUndo(source, scope, result, offers);
2883
+ return result;
2738
2884
  })());
2739
2885
  }
2886
+ /**
2887
+ * A press that offers Undo has ended: its words said — the last with Undo, where what it did can be taken back — by
2888
+ * the undo part (press-undo.ts), which a page whose buttons offer Undo asks for first; plainly where it cannot come.
2889
+ */
2890
+ function offerUndo(source, scope, result, offers) {
2891
+ const taken = scope.taken;
2892
+ scope.taken = undefined;
2893
+ void track(undo_later_1.pressUndoPart.load().then((part) => part.offerUndo(inner, { kit: runner.kit, source, scope, taken, result, offers }), () => taken.said.forEach((words) => options.host?.say(words.message, words.tone))));
2894
+ }
2740
2895
  const form = {
2741
2896
  page,
2742
2897
  ...(table ? { functions: table } : {}),
@@ -2761,7 +2916,10 @@ function innerForm(options, within, place, outer) {
2761
2916
  // A choice whose places are all taken is shown, and refused when the person picks it: said under its field.
2762
2917
  if ((how?.by ?? 'person') === 'person' && refusedFull(name, value))
2763
2918
  return;
2919
+ const before = state.values[name];
2764
2920
  writeValues({ ...state.values, [name]: (0, values_1.structuredCopy)(value) });
2921
+ if ((how?.by ?? 'person') === 'person')
2922
+ noteChange(name, undefined, before, true);
2765
2923
  afterEdit(name);
2766
2924
  changed(name, how?.by ?? 'person');
2767
2925
  },
@@ -2786,7 +2944,7 @@ function innerForm(options, within, place, outer) {
2786
2944
  // Nothing of the record changed; what shows of it may have.
2787
2945
  set({});
2788
2946
  },
2789
- fieldReadonly: (name) => lockedField(fieldDef(name)) || state.can?.edit === false || state.can?.readonlyFields?.includes(name) === true || signedNow().has(name) || !!approvalKit?.locks(name),
2947
+ fieldReadonly: (name) => lockedField(fieldDef(name)) || state.can?.edit === false || state.can?.readonlyFields?.includes(name) === true || signedNow().has(name) || anyJoin((join) => join.locksField?.(name)),
2790
2948
  loadChoices: (field) => loadChoices(field),
2791
2949
  loadDefinitions,
2792
2950
  addDefinition,
@@ -2827,8 +2985,9 @@ function innerForm(options, within, place, outer) {
2827
2985
  return null;
2828
2986
  if (state.unread[name])
2829
2987
  return state.unread[name].message;
2830
- // A property's text left unread answers for its field.
2831
- if (page.fields[name].type === 'properties') {
2988
+ // A property's text left unread answers for its field, and so does a box of a value drawn in parts (a repeat
2989
+ // rule's number, an opening hour's time: `field.part`).
2990
+ if (['properties', 'json', 'char'].includes(page.fields[name].type)) {
2832
2991
  const row = Object.keys(state.unread).find((path) => path.startsWith(`${name}.`));
2833
2992
  if (row)
2834
2993
  return state.unread[row].message;
@@ -2842,7 +3001,9 @@ function innerForm(options, within, place, outer) {
2842
3001
  const field = path.split('.')[0];
2843
3002
  // A line's cell (`field.lineKey.subfield`), or a property (`field.property`).
2844
3003
  const def = fieldDef(field);
2845
- if (path.includes('.') && def.type !== 'properties')
3004
+ // A line's cell, a property, or one of the boxes a value is drawn in (a repeat rule's number, an opening hour's
3005
+ // time: `field.part`, of a char or a json field).
3006
+ if (path.includes('.') && def.type !== 'properties' && !((def.type === 'json' || def.type === 'char') && path.split('.').length === 2))
2846
3007
  lineField(field);
2847
3008
  const had = state.unread[path];
2848
3009
  if (!unread && !had)
@@ -2865,6 +3026,7 @@ function innerForm(options, within, place, outer) {
2865
3026
  set({ unread: next, errors });
2866
3027
  },
2867
3028
  boxLeft(path) {
3029
+ noted.push([path.split('.')[0]]);
2868
3030
  const problem = leftProblem(path);
2869
3031
  if (!problem || state.errors[path] === problem)
2870
3032
  return;
@@ -2887,10 +3049,11 @@ function innerForm(options, within, place, outer) {
2887
3049
  if (seen.captcha !== undefined)
2888
3050
  bot.captcha = seen.captcha;
2889
3051
  },
3052
+ joined: (name) => (joins[joinParts.findIndex((part) => part.name === name)] ?? null),
2890
3053
  reading: () => readingNow > 0 || [...attached.values()].some((part) => part.inner.form.reading()),
2891
- validate() {
3054
+ validate(within) {
2892
3055
  readTyped();
2893
- const errors = collectErrors();
3056
+ const errors = collectErrors(within);
2894
3057
  set({ errors });
2895
3058
  return Object.keys(errors).length === 0;
2896
3059
  },
@@ -2983,6 +3146,7 @@ function innerForm(options, within, place, outer) {
2983
3146
  holding = setWhen.holding(baseline);
2984
3147
  // The person's own Discard: nothing of theirs is left at risk, and a save on its way lands as the record it stored.
2985
3148
  resets++;
3149
+ noted = [];
2986
3150
  personal.clear();
2987
3151
  personalLines.clear();
2988
3152
  filed.clear();
@@ -2991,6 +3155,9 @@ function innerForm(options, within, place, outer) {
2991
3155
  bot = { ...bot, honeypot: false, since: clock() };
2992
3156
  const values = syncParts((0, values_1.structuredCopy)(baseline), 'start');
2993
3157
  set({ values, dirty: [], errors: {}, warnings: withValues(values, collectWarnings), warning: null, warningField: null, draft: null, step: steps[0] ?? null, skipped: [], saveProblem: null, conflict: null, unsent: [], unread: {}, takenOut: {}, sent: null });
3158
+ // Started again: a new response proves and pays its own; a new respondent is drawn anew (unless the app or the
3159
+ // person's id is the seed), on the first step drawn, no clock running.
3160
+ joinsReset();
2994
3161
  // Started again: whether the page takes another response, and each choice's places, asked again.
2995
3162
  if (asksLimits())
2996
3163
  void track(askLimits());
@@ -3010,8 +3177,10 @@ function innerForm(options, within, place, outer) {
3010
3177
  const def = lineField(field);
3011
3178
  if (!def.fields[name])
3012
3179
  throw new Error(`The lines of "${field}" have no field "${name}"`);
3013
- const lines = (state.values[field] ?? []).map((line) => line.key === key ? { ...line, values: { ...line.values, [name]: (0, values_1.structuredCopy)(value) } } : line);
3180
+ const before = state.values[field];
3181
+ const lines = (before ?? []).map((line) => line.key === key ? { ...line, values: { ...line.values, [name]: (0, values_1.structuredCopy)(value) } } : line);
3014
3182
  writeValues({ ...state.values, [field]: lines });
3183
+ noteChange(field, key, before, true);
3015
3184
  afterEdit(field);
3016
3185
  changed(field, 'person', { line: key });
3017
3186
  },
@@ -3041,7 +3210,9 @@ function innerForm(options, within, place, outer) {
3041
3210
  const value = trusted ? (i >= low && i <= high ? pool[i - low] : line.values[sequence]) : i + 1;
3042
3211
  return value === line.values[sequence] ? line : { ...line, values: { ...line.values, [sequence]: value } };
3043
3212
  });
3213
+ const was = state.values[field];
3044
3214
  writeValues({ ...state.values, [field]: renumbered });
3215
+ noteChange(field, undefined, was, false);
3045
3216
  afterEdit(field);
3046
3217
  changed(field, 'person');
3047
3218
  },
@@ -3055,8 +3226,10 @@ function innerForm(options, within, place, outer) {
3055
3226
  throw new Error(`The line "${key}" of "${field}" cannot be deleted now: its table's lineDelete does not hold on it`);
3056
3227
  }
3057
3228
  }
3058
- const lines = (state.values[field] ?? []).filter((line) => line.key !== key);
3229
+ const before = state.values[field];
3230
+ const lines = (before ?? []).filter((line) => line.key !== key);
3059
3231
  writeValues({ ...state.values, [field]: lines });
3232
+ noteChange(field, key, before, false);
3060
3233
  afterEdit(field);
3061
3234
  changed(field, 'person', { line: key });
3062
3235
  },
@@ -3123,6 +3296,8 @@ function innerForm(options, within, place, outer) {
3123
3296
  set({ step: previous, errors: {} });
3124
3297
  return true;
3125
3298
  },
3299
+ startTimer: () => joined('surveyflow')?.start(),
3300
+ countdown: () => joined('surveyflow')?.countdown() ?? null,
3126
3301
  skip() {
3127
3302
  const current = state.step;
3128
3303
  if (!current || !optionalStep(current))
@@ -3284,14 +3459,18 @@ function innerForm(options, within, place, outer) {
3284
3459
  return saved;
3285
3460
  },
3286
3461
  refreshLimits: () => askLimits(),
3287
- refreshApprovals: askApprovals,
3462
+ async refreshApprovals() {
3463
+ await joining;
3464
+ await joined('approvals')?.ask();
3465
+ },
3288
3466
  async decide(level, decision, reason) {
3289
- const kit = await approvalsCode();
3467
+ await joining;
3468
+ const kit = joined('approvals');
3290
3469
  if (!kit)
3291
3470
  throw new Error('No approvals on this page');
3292
3471
  return track(kit.decide(level, decision, reason));
3293
3472
  },
3294
- approvalLock: (name) => approvalKit?.lockWords(name) ?? null,
3473
+ approvalLock: (name) => joined('approvals')?.lockWords(name) ?? null,
3295
3474
  async reloadTheirs() {
3296
3475
  // A save on its way first: its answer is not dropped by the load.
3297
3476
  const asked = shownNow();
@@ -3391,6 +3570,9 @@ function innerForm(options, within, place, outer) {
3391
3570
  if (state.setAside)
3392
3571
  set({ setAside: null });
3393
3572
  },
3573
+ undo: () => replay(true),
3574
+ redo: () => replay(false),
3575
+ history: () => undo_later_1.pressUndoPart.loaded?.nextSteps(noted, inner.same) ?? { undo: null, redo: null },
3394
3576
  async settled() {
3395
3577
  while (pending.size)
3396
3578
  await Promise.allSettled([...pending]);
@@ -3457,6 +3639,8 @@ function innerForm(options, within, place, outer) {
3457
3639
  dispose() {
3458
3640
  // An answer that lands after is for no record shown.
3459
3641
  disposed = true;
3642
+ for (const join of joins)
3643
+ join?.dispose?.();
3460
3644
  newGeneration();
3461
3645
  clearFiles();
3462
3646
  if (draftTimer !== null)
@@ -3476,9 +3660,22 @@ function innerForm(options, within, place, outer) {
3476
3660
  // choice's places as the source tells them: a record's own once it is loaded, its own choices not counted against it.
3477
3661
  if (keepsLimits())
3478
3662
  void track(limitsCode());
3479
- // A record's approvals: their part asked for as the form is made, ready by the time its record is loaded.
3480
- if (keepsApprovals)
3481
- void track(approvalsCode());
3663
+ // The parts its page or its source asks to join it — a survey's draw made before a draft is laid, which lays its own
3664
+ // draw over it; a record's approvals ready by the time its record is loaded; the record made live — each made at once
3665
+ // where it has come, else as it does, a draft laid meanwhile laid on it.
3666
+ if (joinParts.length) {
3667
+ const made = (at) => (part) => {
3668
+ if (disposed || joins[at])
3669
+ return;
3670
+ const join = (joins[at] = part.join(inner));
3671
+ if (laid)
3672
+ join.lay?.(laid);
3673
+ // Its record loaded before it came: what it asks of a loaded record, asked now.
3674
+ if (loadedOnce)
3675
+ join.loaded?.();
3676
+ };
3677
+ joining = Promise.all(joinParts.map((part, at) => (part.loaded ? made(at)(part.loaded) : track(part.load().then(made(at), () => undefined)))));
3678
+ }
3482
3679
  // A new form has its values now — a draft continued from its key once it is laid — and opens once whoever made it
3483
3680
  // has had the chance to listen.
3484
3681
  if (state.recordId == null) {