nexus-shared 3.2.0 → 4.1.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 (271) hide show
  1. package/CHANGELOG.md +2359 -0
  2. package/README.md +1911 -1123
  3. package/dist/Client.Index.d.ts +27 -0
  4. package/dist/Client.Index.js +27 -0
  5. package/dist/Components/Chats/ChatComposer.d.ts +7 -1
  6. package/dist/Components/Chats/ChatComposer.js +9 -6
  7. package/dist/Components/Chats/ChatParts.d.ts +15 -2
  8. package/dist/Components/Chats/ChatParts.js +15 -4
  9. package/dist/Components/Chats/ChatPopup.d.ts +46 -0
  10. package/dist/Components/Chats/ChatPopup.js +34 -0
  11. package/dist/Components/Chats/ChatThread.d.ts +9 -1
  12. package/dist/Components/Chats/ChatThread.js +54 -6
  13. package/dist/Components/Dashboards/DashboardBoard.d.ts +62 -0
  14. package/dist/Components/Dashboards/DashboardBoard.js +594 -0
  15. package/dist/Components/Dashboards/DashboardWidgets.d.ts +155 -0
  16. package/dist/Components/Dashboards/DashboardWidgets.js +159 -0
  17. package/dist/Components/Dashboards/WidgetFrame.d.ts +51 -0
  18. package/dist/Components/Dashboards/WidgetFrame.js +45 -0
  19. package/dist/Components/Documents/Button.d.ts +6 -1
  20. package/dist/Components/Documents/Button.js +2 -2
  21. package/dist/Components/Documents/DocumentFrame.d.ts +50 -0
  22. package/dist/Components/Documents/DocumentFrame.js +83 -0
  23. package/dist/Components/Documents/Menu.d.ts +4 -0
  24. package/dist/Components/Documents/Menu.js +40 -24
  25. package/dist/Components/Documents/PrintDocument.d.ts +95 -0
  26. package/dist/Components/Documents/PrintDocument.js +62 -0
  27. package/dist/Components/Documents/TabButtons.d.ts +6 -0
  28. package/dist/Components/Documents/TabButtons.js +5 -4
  29. package/dist/Components/Documents/Tabs.d.ts +59 -0
  30. package/dist/Components/Documents/Tabs.js +70 -0
  31. package/dist/Components/Domains/DomainCard.d.ts +98 -0
  32. package/dist/Components/Domains/DomainCard.js +182 -0
  33. package/dist/Components/Forms/ApiForm.js +24 -3
  34. package/dist/Components/Forms/Crud.d.ts +2 -2
  35. package/dist/Components/Forms/Crud.js +628 -247
  36. package/dist/Components/Forms/CrudActions.d.ts +137 -0
  37. package/dist/Components/Forms/CrudActions.js +214 -0
  38. package/dist/Components/Forms/CrudHistory.d.ts +6 -1
  39. package/dist/Components/Forms/CrudHistory.js +14 -6
  40. package/dist/Components/Forms/CrudNarrowPicker.d.ts +31 -0
  41. package/dist/Components/Forms/CrudNarrowPicker.js +180 -0
  42. package/dist/Components/Forms/CrudParts.d.ts +37 -2
  43. package/dist/Components/Forms/CrudParts.js +123 -7
  44. package/dist/Components/Forms/CrudRowForms.d.ts +26 -0
  45. package/dist/Components/Forms/CrudRowForms.js +174 -0
  46. package/dist/Components/Forms/CrudScopes.d.ts +28 -0
  47. package/dist/Components/Forms/CrudScopes.js +76 -0
  48. package/dist/Components/Forms/CrudTree.d.ts +90 -0
  49. package/dist/Components/Forms/CrudTree.js +363 -0
  50. package/dist/Components/Forms/CrudWorkspace.d.ts +73 -0
  51. package/dist/Components/Forms/CrudWorkspace.js +177 -0
  52. package/dist/Components/Forms/ExcelImport.js +3 -3
  53. package/dist/Components/Forms/Form.d.ts +6 -5
  54. package/dist/Components/Forms/Form.js +134 -21
  55. package/dist/Components/Forms/FormLeaveGuard.d.ts +44 -0
  56. package/dist/Components/Forms/FormLeaveGuard.js +65 -0
  57. package/dist/Components/Forms/FormQuestion.d.ts +6 -0
  58. package/dist/Components/Forms/FormQuestion.js +28 -0
  59. package/dist/Components/Forms/RecordFlows.d.ts +50 -0
  60. package/dist/Components/Forms/RecordFlows.js +282 -0
  61. package/dist/Components/Forms/SubmitForm.d.ts +37 -2
  62. package/dist/Components/Forms/SubmitForm.js +182 -10
  63. package/dist/Components/Inputs/CheckBox.js +1 -1
  64. package/dist/Components/Inputs/ChoiceField.d.ts +21 -1
  65. package/dist/Components/Inputs/ChoiceField.js +28 -2
  66. package/dist/Components/Inputs/ComputedInput.d.ts +51 -0
  67. package/dist/Components/Inputs/ComputedInput.js +179 -0
  68. package/dist/Components/Inputs/Dropdown.d.ts +13 -0
  69. package/dist/Components/Inputs/Dropdown.js +8 -6
  70. package/dist/Components/Inputs/DropdownParts.d.ts +3 -1
  71. package/dist/Components/Inputs/DropdownParts.js +16 -4
  72. package/dist/Components/Inputs/Field.d.ts +7 -1
  73. package/dist/Components/Inputs/Field.js +2 -2
  74. package/dist/Components/Inputs/GroupForm.d.ts +6 -6
  75. package/dist/Components/Inputs/GroupForm.js +12 -12
  76. package/dist/Components/Inputs/InputRenderer.d.ts +13 -6
  77. package/dist/Components/Inputs/InputRenderer.js +37 -32
  78. package/dist/Components/Inputs/MarkdownEditor.d.ts +6 -0
  79. package/dist/Components/Inputs/MarkdownEditor.js +32 -6
  80. package/dist/Components/Inputs/PictureInput.d.ts +41 -0
  81. package/dist/Components/Inputs/PictureInput.js +75 -0
  82. package/dist/Components/Inputs/RadioGroup.d.ts +16 -3
  83. package/dist/Components/Inputs/RadioGroup.js +8 -3
  84. package/dist/Components/Inputs/RowsInput.d.ts +15 -2
  85. package/dist/Components/Inputs/RowsInput.js +96 -8
  86. package/dist/Components/Inputs/TabularForm.d.ts +5 -5
  87. package/dist/Components/Inputs/TabularForm.js +45 -32
  88. package/dist/Components/Inputs/TextArea.d.ts +6 -0
  89. package/dist/Components/Inputs/TextArea.js +11 -2
  90. package/dist/Components/Inputs/TextBoxTypes.d.ts +6 -0
  91. package/dist/Components/Inputs/TextBoxTypes.js +17 -0
  92. package/dist/Components/Inputs/TreeView.d.ts +76 -2
  93. package/dist/Components/Inputs/TreeView.js +227 -16
  94. package/dist/Components/Layouts/MessageBox.d.ts +15 -2
  95. package/dist/Components/Layouts/MessageBox.js +56 -7
  96. package/dist/Components/Layouts/Popup.d.ts +34 -7
  97. package/dist/Components/Layouts/Popup.js +143 -13
  98. package/dist/Components/Layouts/PopupDock.d.ts +3 -1
  99. package/dist/Components/Layouts/PopupDock.js +2 -1
  100. package/dist/Components/Layouts/PopupHost.js +5 -4
  101. package/dist/Components/Messages/MailClient.d.ts +50 -0
  102. package/dist/Components/Messages/MailClient.js +410 -0
  103. package/dist/Components/Messages/MailColumns.d.ts +21 -0
  104. package/dist/Components/Messages/MailColumns.js +92 -0
  105. package/dist/Components/Messages/MailCompose.d.ts +46 -0
  106. package/dist/Components/Messages/MailCompose.js +154 -0
  107. package/dist/Components/Messages/MailReader.d.ts +43 -0
  108. package/dist/Components/Messages/MailReader.js +207 -0
  109. package/dist/Components/Messages/MailThread.d.ts +71 -0
  110. package/dist/Components/Messages/MailThread.js +185 -0
  111. package/dist/Components/Messages/MessageBell.d.ts +41 -0
  112. package/dist/Components/Messages/MessageBell.js +76 -0
  113. package/dist/Components/Viewers/DataTable.js +153 -49
  114. package/dist/Components/Viewers/DataTableColumns.d.ts +2 -2
  115. package/dist/Components/Viewers/DataTableColumns.js +2 -1
  116. package/dist/Components/Viewers/DataTableFilters.d.ts +1 -1
  117. package/dist/Components/Viewers/DataTableFilters.js +17 -2
  118. package/dist/Components/Viewers/DataTableParts.d.ts +23 -5
  119. package/dist/Components/Viewers/DataTableParts.js +26 -14
  120. package/dist/Components/Viewers/OwnerFiles.d.ts +227 -0
  121. package/dist/Components/Viewers/OwnerFiles.js +700 -0
  122. package/dist/Components/Viewers/QrCodeImage.d.ts +22 -0
  123. package/dist/Components/Viewers/QrCodeImage.js +15 -0
  124. package/dist/Components/Viewers/RecordCards.d.ts +16 -0
  125. package/dist/Components/Viewers/RecordCards.js +509 -0
  126. package/dist/Helpers/ApiModules.js +4 -0
  127. package/dist/Helpers/AuditEntries.d.ts +50 -0
  128. package/dist/Helpers/AuditEntries.js +96 -0
  129. package/dist/Helpers/BusyHooks.d.ts +6 -0
  130. package/dist/Helpers/BusyHooks.js +39 -0
  131. package/dist/Helpers/ChatBackend.d.ts +8 -1
  132. package/dist/Helpers/ChatBackend.js +18 -0
  133. package/dist/Helpers/ChatHelpers.d.ts +2 -0
  134. package/dist/Helpers/ChatHelpers.js +4 -1
  135. package/dist/Helpers/CrudBackend.d.ts +20 -2
  136. package/dist/Helpers/CrudBackend.js +46 -2
  137. package/dist/Helpers/CrudColumns.d.ts +91 -6
  138. package/dist/Helpers/CrudColumns.js +148 -7
  139. package/dist/Helpers/CrudDetailsTabs.d.ts +58 -0
  140. package/dist/Helpers/CrudDetailsTabs.js +126 -0
  141. package/dist/Helpers/CrudHelpers.d.ts +116 -2
  142. package/dist/Helpers/CrudHelpers.js +256 -0
  143. package/dist/Helpers/CrudNarrowPick.d.ts +83 -0
  144. package/dist/Helpers/CrudNarrowPick.js +157 -0
  145. package/dist/Helpers/CrudPickerPlan.d.ts +58 -0
  146. package/dist/Helpers/CrudPickerPlan.js +46 -0
  147. package/dist/Helpers/CrudRowForms.d.ts +32 -0
  148. package/dist/Helpers/CrudRowForms.js +76 -0
  149. package/dist/Helpers/CrudScopes.d.ts +32 -0
  150. package/dist/Helpers/CrudScopes.js +79 -0
  151. package/dist/Helpers/DashboardHelpers.d.ts +115 -0
  152. package/dist/Helpers/DashboardHelpers.js +305 -0
  153. package/dist/Helpers/DomainCards.d.ts +140 -0
  154. package/dist/Helpers/DomainCards.js +370 -0
  155. package/dist/Helpers/DropdownHelpers.d.ts +3 -1
  156. package/dist/Helpers/DropdownHelpers.js +6 -2
  157. package/dist/Helpers/ExcelHelpers.d.ts +1 -1
  158. package/dist/Helpers/ExcelHelpers.js +12 -11
  159. package/dist/Helpers/FileAdapter.d.ts +158 -0
  160. package/dist/Helpers/FileAdapter.js +173 -0
  161. package/dist/Helpers/FilePrimaries.d.ts +48 -0
  162. package/dist/Helpers/FilePrimaries.js +138 -0
  163. package/dist/Helpers/FormConfirm.d.ts +32 -0
  164. package/dist/Helpers/FormConfirm.js +40 -0
  165. package/dist/Helpers/FormStore.d.ts +100 -5
  166. package/dist/Helpers/FormStore.js +368 -25
  167. package/dist/Helpers/InputConditions.d.ts +56 -0
  168. package/dist/Helpers/InputConditions.js +192 -0
  169. package/dist/Helpers/InputMemory.d.ts +106 -0
  170. package/dist/Helpers/InputMemory.js +395 -0
  171. package/dist/Helpers/InputNarrowing.d.ts +50 -0
  172. package/dist/Helpers/InputNarrowing.js +148 -0
  173. package/dist/Helpers/InputParamsHelpers.d.ts +44 -1
  174. package/dist/Helpers/InputParamsHelpers.js +157 -74
  175. package/dist/Helpers/MailClientHelpers.d.ts +96 -0
  176. package/dist/Helpers/MailClientHelpers.js +211 -0
  177. package/dist/Helpers/MessageBackend.d.ts +152 -0
  178. package/dist/Helpers/MessageBackend.js +329 -0
  179. package/dist/Helpers/MessageHelpers.d.ts +160 -0
  180. package/dist/Helpers/MessageHelpers.js +573 -0
  181. package/dist/Helpers/MessageUnread.d.ts +95 -0
  182. package/dist/Helpers/MessageUnread.js +245 -0
  183. package/dist/Helpers/NexusDriveAdapter.d.ts +71 -0
  184. package/dist/Helpers/NexusDriveAdapter.js +236 -0
  185. package/dist/Helpers/NumberHelpers.d.ts +156 -0
  186. package/dist/Helpers/NumberHelpers.js +242 -0
  187. package/dist/Helpers/PagedPicker.d.ts +42 -0
  188. package/dist/Helpers/PagedPicker.js +85 -0
  189. package/dist/Helpers/Permissions.js +2 -1
  190. package/dist/Helpers/QrCode.d.ts +26 -0
  191. package/dist/Helpers/QrCode.js +463 -0
  192. package/dist/Helpers/RecordCards.d.ts +205 -0
  193. package/dist/Helpers/RecordCards.js +378 -0
  194. package/dist/Helpers/RequestCache.d.ts +14 -2
  195. package/dist/Helpers/RequestCache.js +22 -3
  196. package/dist/Helpers/RowsStore.d.ts +61 -2
  197. package/dist/Helpers/RowsStore.js +203 -16
  198. package/dist/Helpers/ServerPreview.d.ts +69 -0
  199. package/dist/Helpers/ServerPreview.js +99 -0
  200. package/dist/Helpers/TableColumns.js +4 -3
  201. package/dist/Helpers/TableExport.d.ts +7 -1
  202. package/dist/Helpers/TableExport.js +9 -3
  203. package/dist/Helpers/TableFilters.d.ts +1 -1
  204. package/dist/Helpers/TableFilters.js +24 -23
  205. package/dist/Helpers/TableHelpers.d.ts +38 -4
  206. package/dist/Helpers/TableHelpers.js +78 -10
  207. package/dist/Helpers/TableJoins.d.ts +13 -0
  208. package/dist/Helpers/TableJoins.js +34 -0
  209. package/dist/Helpers/TableStore.d.ts +28 -4
  210. package/dist/Helpers/TableStore.js +73 -11
  211. package/dist/Helpers/ToolbarFit.d.ts +23 -0
  212. package/dist/Helpers/ToolbarFit.js +30 -0
  213. package/dist/Helpers/TreeStore.d.ts +156 -6
  214. package/dist/Helpers/TreeStore.js +547 -18
  215. package/dist/Interfaces/ApiInterfaces.d.ts +10 -1
  216. package/dist/Interfaces/ApiInterfaces.js +10 -1
  217. package/dist/Interfaces/ChatInterfaces.d.ts +22 -0
  218. package/dist/Interfaces/CrudInterfaces.d.ts +539 -6
  219. package/dist/Interfaces/DashboardInterfaces.d.ts +123 -0
  220. package/dist/Interfaces/DashboardInterfaces.js +1 -0
  221. package/dist/Interfaces/DomainInterfaces.d.ts +145 -0
  222. package/dist/Interfaces/DomainInterfaces.js +1 -0
  223. package/dist/Interfaces/FileInterfaces.d.ts +183 -0
  224. package/dist/Interfaces/FileInterfaces.js +6 -0
  225. package/dist/Interfaces/FormInterfaces.d.ts +460 -32
  226. package/dist/Interfaces/FormInterfaces.js +79 -1
  227. package/dist/Interfaces/InputInterfaces.d.ts +22 -3
  228. package/dist/Interfaces/MailInterfaces.d.ts +192 -0
  229. package/dist/Interfaces/MailInterfaces.js +1 -0
  230. package/dist/Interfaces/RecordInterfaces.d.ts +367 -0
  231. package/dist/Interfaces/RecordInterfaces.js +1 -0
  232. package/dist/Interfaces/TableInterfaces.d.ts +102 -3
  233. package/dist/Services/ExcelApi.js +5 -0
  234. package/dist/Services/FileApi.d.ts +13 -0
  235. package/dist/Services/FileApi.js +29 -0
  236. package/dist/Services/ImageEditorLoader.d.ts +14 -0
  237. package/dist/Services/ImageEditorLoader.js +51 -0
  238. package/dist/Services/JoinSources.d.ts +79 -6
  239. package/dist/Services/JoinSources.js +132 -21
  240. package/dist/Services/MessageApi.d.ts +18 -0
  241. package/dist/Services/MessageApi.js +64 -0
  242. package/dist/Services/ModuleImport.d.ts +7 -0
  243. package/dist/Services/ModuleImport.js +22 -0
  244. package/dist/Shared.Index.d.ts +28 -0
  245. package/dist/Shared.Index.js +28 -0
  246. package/package.json +13 -2
  247. package/src/Styles/Nexus.Avatar.css +6 -5
  248. package/src/Styles/Nexus.Button.css +39 -4
  249. package/src/Styles/Nexus.Chat.css +114 -22
  250. package/src/Styles/Nexus.Choice.css +16 -0
  251. package/src/Styles/Nexus.Crud.css +486 -21
  252. package/src/Styles/Nexus.Dashboard.css +763 -0
  253. package/src/Styles/Nexus.Domain.css +384 -0
  254. package/src/Styles/Nexus.Dropdown.css +8 -0
  255. package/src/Styles/Nexus.Editor.css +20 -0
  256. package/src/Styles/Nexus.Files.css +437 -0
  257. package/src/Styles/Nexus.Form.css +5 -2
  258. package/src/Styles/Nexus.Index.css +7 -0
  259. package/src/Styles/Nexus.Input.css +73 -0
  260. package/src/Styles/Nexus.Mail.css +1062 -0
  261. package/src/Styles/Nexus.Menu.css +10 -1
  262. package/src/Styles/Nexus.Popup.css +135 -1
  263. package/src/Styles/Nexus.Print.css +288 -0
  264. package/src/Styles/Nexus.QrCode.css +12 -0
  265. package/src/Styles/Nexus.Record.css +430 -0
  266. package/src/Styles/Nexus.Tab.Buttons.css +87 -22
  267. package/src/Styles/Nexus.Table.css +1458 -1387
  268. package/src/Styles/Nexus.Theme.Picker.css +1 -0
  269. package/src/Styles/Nexus.Themes.css +12 -6
  270. package/src/Styles/Nexus.Tokens.css +8 -3
  271. package/src/Styles/Nexus.Tree.css +41 -1
@@ -0,0 +1,192 @@
1
+ import { EInputTypes } from "../Interfaces/FormInterfaces.js";
2
+ import { formatNumber } from "./NumberHelpers.js";
3
+ /*
4
+ * When an input shows (`showWhen`), when it is read-only (`readOnlyWhen`), what it is called (`labelWhen`), how wide it
5
+ * is (`spanWhen`) and what it shows when it is worked out from others (`compute`): declared in its params on other
6
+ * inputs' values, so a page never writes a getter for `hidden`, `readOnly`, `label` or `span`. The form gives each such
7
+ * input a live `hidden` / `readOnly` / `label` / `span` that reads its store, and follows the inputs they name as
8
+ * `dependsOn` would (this file, pure, so Node tests run it).
9
+ */
10
+ /** No value: null, undefined, an empty or blank text, an empty list. `false` and `0` are values. */
11
+ export function isEmptyValue(value) {
12
+ if (value === null || value === undefined)
13
+ return true;
14
+ if (typeof value === "string")
15
+ return value.trim() === "";
16
+ return Array.isArray(value) && value.length === 0;
17
+ }
18
+ /** The same value whatever its type on the way: 1 and "1" match, as a radio group's and a dropdown's do. */
19
+ const same = (a, b) => a === b || (a !== null && a !== undefined && b !== null && b !== undefined && String(a) === String(b));
20
+ /**
21
+ * Whether one condition holds for the other input's value. A list value (a multiple choice) holds `in` when any of its
22
+ * items is listed, and `notIn` when none is. Every key the condition has must hold; one with none holds always.
23
+ */
24
+ export function conditionHolds(condition, value) {
25
+ const items = Array.isArray(value) ? value : [value];
26
+ if (condition.in && !items.some(item => condition.in.some(wanted => same(item, wanted))))
27
+ return false;
28
+ if (condition.notIn && items.some(item => condition.notIn.some(unwanted => same(item, unwanted))))
29
+ return false;
30
+ if (condition.filled !== undefined && condition.filled === isEmptyValue(value))
31
+ return false;
32
+ return true;
33
+ }
34
+ /** The conditions of a `showWhen` or a `readOnlyWhen`, as a list. */
35
+ export function conditionsOf(conditions) {
36
+ if (!conditions)
37
+ return [];
38
+ return Array.isArray(conditions) ? conditions : [conditions];
39
+ }
40
+ /** Whether every condition holds, reading the other inputs' values with `read`. None holds always. */
41
+ export function conditionsHold(conditions, read) {
42
+ return conditionsOf(conditions).every(condition => conditionHolds(condition, read(condition.name)));
43
+ }
44
+ /** Whether an input with this `showWhen` shows, reading the other inputs' values with `read`: every condition must hold. */
45
+ export function inputShown(showWhen, read) {
46
+ return conditionsHold(showWhen, read);
47
+ }
48
+ /** Whether an input with this `readOnlyWhen` is read-only, reading the other inputs' values with `read`: every condition must hold. */
49
+ export function inputReadOnly(readOnlyWhen, read) {
50
+ return Boolean(readOnlyWhen) && conditionsHold(readOnlyWhen, read);
51
+ }
52
+ /** The text of `texts` for the other input's value (compared as text), or undefined when none is listed for it. */
53
+ export function textFor(texts, value) {
54
+ if (!texts || value === null || value === undefined || Array.isArray(value))
55
+ return undefined;
56
+ return Object.prototype.hasOwnProperty.call(texts, String(value)) ? texts[String(value)] : undefined;
57
+ }
58
+ /** The label an input with this `labelWhen` shows for the other input's value: listed, else `otherwise`, else its own. */
59
+ export function labelFor(labelWhen, value, own) {
60
+ return textFor(labelWhen.labels, value) ?? labelWhen.otherwise ?? own;
61
+ }
62
+ /**
63
+ * The columns an input with this `spanWhen` spans, reading the other inputs' values with `read`: `spanWhen.span` while
64
+ * every condition of `when` holds, else its own `span` (none: undefined, the whole row).
65
+ */
66
+ export function spanFor(spanWhen, read, own) {
67
+ return spanWhen && conditionsHold(spanWhen.when, read) ? spanWhen.span : own;
68
+ }
69
+ /** The params' own value of `key` - a value or a getter, asked on the copy so `this` is the copy. */
70
+ function ownValue(params, copy, key) {
71
+ const own = Object.getOwnPropertyDescriptor(params, key);
72
+ return () => (own?.get ? own.get.call(copy) : own?.value);
73
+ }
74
+ /** The params' own value of `key` - a value or a getter, asked on the copy so `this` is the copy - as a boolean. */
75
+ function ownFlag(params, copy, key) {
76
+ const own = Object.getOwnPropertyDescriptor(params, key);
77
+ return () => Boolean(own?.get ? own.get.call(copy) : own?.value);
78
+ }
79
+ /**
80
+ * The inputs with a live `hidden` for each one that has `showWhen`, a live `readOnly` for each one that has
81
+ * `readOnlyWhen` - its own `hidden` / `readOnly` (a value or a getter), or else the conditions, read through `read` as
82
+ * the values are now - a live `label` (and `placeholder`) for each one that has `labelWhen`, and a live `span` for each
83
+ * one that has `spanWhen` (its own `span`, a value or a getter, while the conditions do not hold); and its `dependsOn`
84
+ * joined by the names they read (and by the inputs a `compute` is worked out from), so the form draws it again (and asks
85
+ * its rule again) when they change. The other params are copied with their getters as they are. The same array when no
86
+ * input has any.
87
+ *
88
+ * @example withInputConditions(inputs, name => store.get(name))
89
+ */
90
+ export function withInputConditions(inputs, read) {
91
+ if (!inputs.some(params => params.showWhen || params.readOnlyWhen || params.labelWhen || params.spanWhen || params.compute))
92
+ return inputs;
93
+ return inputs.map(params => {
94
+ if (!params.showWhen && !params.readOnlyWhen && !params.labelWhen && !params.spanWhen && !params.compute)
95
+ return params;
96
+ const copy = Object.defineProperties({}, Object.getOwnPropertyDescriptors(params));
97
+ const names = [...conditionsOf(params.showWhen), ...conditionsOf(params.readOnlyWhen)].map(condition => condition.name);
98
+ if (params.labelWhen)
99
+ names.push(params.labelWhen.name);
100
+ // A width that follows values draws again when they change; its own name, when listed, follows its own typing.
101
+ if (params.spanWhen)
102
+ names.push(...conditionsOf(params.spanWhen.when).map(condition => condition.name));
103
+ // A worked-out input draws again, and is worked out again, when an input it is worked out from changes.
104
+ if (params.compute)
105
+ names.push(...params.compute.from);
106
+ const follows = [...new Set([...(params.dependsOn ?? []), ...names])];
107
+ if (params.showWhen) {
108
+ const ownHidden = ownFlag(params, copy, "hidden");
109
+ Object.defineProperty(copy, "hidden", { get: () => ownHidden() || !inputShown(copy.showWhen, read), enumerable: true, configurable: true });
110
+ }
111
+ if (params.readOnlyWhen) {
112
+ const ownReadOnly = ownFlag(params, copy, "readOnly");
113
+ Object.defineProperty(copy, "readOnly", { get: () => ownReadOnly() || inputReadOnly(copy.readOnlyWhen, read), enumerable: true, configurable: true });
114
+ }
115
+ if (params.labelWhen) {
116
+ const ownLabel = ownValue(params, copy, "label");
117
+ const ownPlaceholder = ownValue(params, copy, "placeholder");
118
+ Object.defineProperty(copy, "label", { get: () => (copy.labelWhen ? labelFor(copy.labelWhen, read(copy.labelWhen.name), ownLabel()) : ownLabel()), enumerable: true, configurable: true });
119
+ if (params.labelWhen.placeholders) {
120
+ Object.defineProperty(copy, "placeholder", { get: () => (copy.labelWhen ? (textFor(copy.labelWhen.placeholders, read(copy.labelWhen.name)) ?? ownPlaceholder()) : ownPlaceholder()), enumerable: true, configurable: true });
121
+ }
122
+ }
123
+ if (params.spanWhen) {
124
+ const ownSpan = ownValue(params, copy, "span");
125
+ Object.defineProperty(copy, "span", { get: () => spanFor(copy.spanWhen, read, ownSpan()), enumerable: true, configurable: true });
126
+ }
127
+ Object.defineProperty(copy, "dependsOn", { value: follows, enumerable: true, configurable: true, writable: true });
128
+ return copy;
129
+ });
130
+ }
131
+ /* Inputs worked out from others (`compute`) */
132
+ const joinedSources = new WeakMap();
133
+ /**
134
+ * The inputs with each worked-out one's `dependsOn` joined by the inputs it is worked out from (`compute.from`), so what
135
+ * follows `dependsOn` - a row's cells (`RowsStore`), as a form's do through `withInputConditions` - draws it again when
136
+ * one of them changes. The same array when none is worked out from another, and the same copy for the same array.
137
+ */
138
+ export function withComputeSources(inputs) {
139
+ if (!inputs.some(params => params.compute?.from.length))
140
+ return inputs;
141
+ let joined = joinedSources.get(inputs);
142
+ if (!joined) {
143
+ joined = inputs.map(params => {
144
+ if (!params.compute?.from.length)
145
+ return params;
146
+ // Descriptors, never a spread: a getter (`get readOnly()`) is still read as the input draws.
147
+ const copy = Object.defineProperties({}, Object.getOwnPropertyDescriptors(params));
148
+ const follows = [...new Set([...(params.dependsOn ?? []), ...params.compute.from])];
149
+ Object.defineProperty(copy, "dependsOn", { value: follows, enumerable: true, configurable: true, writable: true });
150
+ return copy;
151
+ });
152
+ joinedSources.set(inputs, joined);
153
+ }
154
+ return joined;
155
+ }
156
+ /** Whether the input is worked out from others (`compute`): it holds no value of the form's and is never typed in. */
157
+ export function isComputedInput(params) {
158
+ return Boolean(params?.compute);
159
+ }
160
+ /**
161
+ * What a worked-out input (`compute`) shows for these values and the form's `computeWith`. A page's rule that throws
162
+ * shows nothing, and says so in the console, so one bad figure never takes the form down with it.
163
+ */
164
+ export function computedValue(params, values, withValue) {
165
+ if (!params.compute)
166
+ return undefined;
167
+ try {
168
+ return params.compute.value(values, withValue);
169
+ }
170
+ catch (error) {
171
+ console.error(`The worked-out value of "${params.name}" failed:`, error);
172
+ return undefined;
173
+ }
174
+ }
175
+ /**
176
+ * A worked-out value as its box writes it: a Number input's figure with its `decimals` always written (1,073.50), grouped,
177
+ * in `locale` (the person's, unless the params name their own); any other input's value as text. Null, undefined, "",
178
+ * NaN, or a figure that is not finite, write nothing, so the box is blank rather than "NaN" or "0.00".
179
+ */
180
+ export function computedText(params, value, locale) {
181
+ if (value === null || value === undefined)
182
+ return "";
183
+ if (typeof value === "number" && !Number.isFinite(value))
184
+ return "";
185
+ if (params.type !== EInputTypes.Number)
186
+ return String(value).trim();
187
+ const figure = typeof value === "number" ? value : typeof value === "string" && value.trim() !== "" ? Number(value) : Number.NaN;
188
+ if (!Number.isFinite(figure))
189
+ return "";
190
+ const { decimals, fixedDecimals, grouping } = params;
191
+ return formatNumber(figure, { decimals, fixedDecimals: fixedDecimals ?? decimals !== undefined, grouping: grouping ?? true, locale: params.locale ?? locale });
192
+ }
@@ -0,0 +1,106 @@
1
+ import { type InputParams, type InputRemember } from "../Interfaces/FormInterfaces.ts";
2
+ /** Where an input's value is kept: `nx-input:{key}:{viewer}`, or `nx-input:{key}-{per value}:{viewer}` with `per`. */
3
+ export declare const INPUT_MEMORY_PREFIX = "nx-input:";
4
+ /** Reads another value beside the input: the form's values for a form's input, the row's for an input in rows. */
5
+ export type InputMemoryRead = (name: string) => unknown;
6
+ /**
7
+ * The other values a remembered input's opening is judged on: the input that narrows its options (`narrowedBy`), the one
8
+ * its value is kept per (`per`), and the ones its `when` names. A picker's late answer opens nothing once any of them
9
+ * changed since it was asked: it answered for values the form no longer holds.
10
+ */
11
+ export declare function rememberDependencies(params: InputParams): string[];
12
+ /** Whether the input remembers among these values: its `when` holds (none: always). */
13
+ export declare function remembersHere(remember: InputRemember | null | undefined, read?: InputMemoryRead): boolean;
14
+ /**
15
+ * The storage key of a remembered input, or null when nothing is kept here: no key, no viewer to keep it for, its `when`
16
+ * does not hold, or its `per` input holds no single value. With `per`, the other value ends the key: one value kept per
17
+ * group, `nx-input:subscription-package-{group}:{viewer}`.
18
+ */
19
+ export declare function inputMemoryKey(remember: InputRemember | null | undefined, read?: InputMemoryRead): string | null;
20
+ /** What `getItem`/`setItem`/`removeItem` a memory needs: `localStorage`, or a map in a test. */
21
+ export type InputMemoryStorage = Pick<Storage, "getItem" | "setItem" | "removeItem">;
22
+ /** This browser's local storage, or nothing where it cannot be reached (on a server, storage switched off). */
23
+ export declare function browserInputMemory(): InputMemoryStorage | null;
24
+ /**
25
+ * The event a `SubmitForm` sends its `<form>` once a save went through, before the form resets: the rows inside it keep
26
+ * their remembered values then (`RowsStore.rememberAdded`), as the form's own inputs do.
27
+ */
28
+ export declare const FORM_SAVED_EVENT = "nx-form-saved";
29
+ /** The value kept for this input, or undefined: none kept, no viewer, or storage that cannot be read. */
30
+ export declare function readInputMemory(storage: InputMemoryStorage | null, remember: InputRemember | null | undefined, read?: InputMemoryRead): unknown;
31
+ /** Keeps a saved value for the input; an empty one forgets it. Storage that cannot be written keeps nothing. */
32
+ export declare function writeInputMemory(storage: InputMemoryStorage | null, params: InputParams, value: unknown, read?: InputMemoryRead): void;
33
+ /** Forgets the input's kept value: one its list no longer offers. */
34
+ export declare function forgetInputMemory(storage: InputMemoryStorage | null, remember: InputRemember | null | undefined, read?: InputMemoryRead): void;
35
+ /** Whether a value is the input's empty one: nothing, "", an empty list, or a switch that is off. */
36
+ export declare function isEmptyInputValue(params: InputParams, value: unknown): boolean;
37
+ /**
38
+ * The part of a value the input offers now, or undefined when it offers none of it. An input with a list of its own
39
+ * (radio and checkbox groups, a dropdown's `options`) must list it, neither disabled nor inactive; a list of values
40
+ * keeps the ones it lists. An input whose options come from a server, or that has no options, takes any value here: a
41
+ * picker is asked by `keptStandingNow` / `findKeptStanding`.
42
+ */
43
+ export declare function offeredInputValue(params: InputParams, value: unknown): unknown;
44
+ /** A dropdown whose options come from `loadOptions` and that has no list of its own: it is asked what it offers. */
45
+ export declare function isPickerInput(params: InputParams): boolean;
46
+ /** How a kept (or preferred) value stands with its input now. */
47
+ export type KeptStanding =
48
+ /** Offered: open on it (for a list of values, the part offered). */
49
+ {
50
+ status: "offered";
51
+ value: unknown;
52
+ }
53
+ /** Not offered - gone, inactive, disabled, or outside the narrowing: open nothing, and forget a kept value. */
54
+ | {
55
+ status: "gone";
56
+ }
57
+ /** Could not be told now (the picker could not be read, nothing to narrow by yet): open nothing, keep it for next time. */
58
+ | {
59
+ status: "unknown";
60
+ };
61
+ /**
62
+ * How a value stands with the input at once, with no call: an input's own list (narrowed as its `narrowedBy` says among
63
+ * these values) offers it or not; a picker by what it holds already (`peekOption`, fresh only); any other input takes
64
+ * it. Null when a picker must be asked (`findKeptStanding`).
65
+ */
66
+ export declare function keptStandingNow(params: InputParams, value: unknown, read?: InputMemoryRead): KeptStanding | null;
67
+ /**
68
+ * How a value stands with the input, asking a picker when it must: by the value's key (`resolveOptions`, as a saved
69
+ * value is named) - a record found is judged on its own state and narrowing field - and, for a key it did not answer or
70
+ * a record without its narrowing's field, through its own pages narrowed as the form narrows them (a picker that names
71
+ * only what it already holds, such as a `crudPicker` with another `valueKey` and no `find`, answers nothing for a list
72
+ * not loaded yet: its pages tell). Never rejects: a picker that cannot be read answers `unknown`.
73
+ */
74
+ export declare function findKeptStanding(params: InputParams, value: unknown, read: InputMemoryRead, signal: AbortSignal): Promise<KeptStanding>;
75
+ /** What a remembered input opens on. */
76
+ export interface KeptOpening {
77
+ /** The value it opens on; undefined: none (it keeps its own default). */
78
+ value: unknown;
79
+ /** The kept choice is no longer offered: forget it. */
80
+ forget: boolean;
81
+ /** A picker must be asked first (`findRememberedOpening`); nothing opens until it answers. */
82
+ ask: boolean;
83
+ }
84
+ /**
85
+ * What a remembered input opens on among these values, at once where it can be told: the company's `preferred` value
86
+ * while the input offers it, else the person's last saved choice while it offers that, else none. `ask` when a picker
87
+ * must be asked first (`findRememberedOpening`). Nothing while its `when` does not hold.
88
+ */
89
+ export declare function rememberedOpeningNow(params: InputParams, stored: unknown, read?: InputMemoryRead): KeptOpening;
90
+ /**
91
+ * The same, asking a picker by the values' keys where it must (`findKeptStanding`). Never rejects: a picker that could
92
+ * not be read opens nothing and forgets nothing.
93
+ */
94
+ export declare function findRememberedOpening(params: InputParams, stored: unknown, read: InputMemoryRead, signal: AbortSignal): Promise<KeptOpening>;
95
+ /**
96
+ * What a remembered input opens on when the form's values leave it empty, from its own list alone: the company's
97
+ * `preferred` value while the input offers it, else the person's last saved choice while it offers that, else undefined
98
+ * (the input keeps its own default). A value no longer offered is dropped without a word, never shown as a broken one.
99
+ * A picker's values are taken as they are here; a form asks the picker (`rememberedOpeningNow`).
100
+ */
101
+ export declare function rememberedOpening(params: InputParams, stored: unknown): unknown;
102
+ /**
103
+ * The row of a list a save keeps a row input's value from: the one added last that is still there, else none (no row
104
+ * was added, so no new choice was made). Keys in the order they were added.
105
+ */
106
+ export declare function lastAddedRowKey(added: readonly string[], present: (key: string) => boolean): string | null;