nexus-shared 3.1.0 → 4.0.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 (234) hide show
  1. package/CHANGELOG.md +2268 -446
  2. package/LICENSE +21 -21
  3. package/README.md +1705 -1084
  4. package/dist/Client.Index.d.ts +17 -0
  5. package/dist/Client.Index.js +17 -0
  6. package/dist/Components/Documents/DocumentFrame.d.ts +50 -0
  7. package/dist/Components/Documents/DocumentFrame.js +83 -0
  8. package/dist/Components/Documents/Menu.d.ts +4 -0
  9. package/dist/Components/Documents/Menu.js +40 -24
  10. package/dist/Components/Documents/PrintDocument.d.ts +95 -0
  11. package/dist/Components/Documents/PrintDocument.js +62 -0
  12. package/dist/Components/Documents/Tabs.d.ts +59 -0
  13. package/dist/Components/Documents/Tabs.js +70 -0
  14. package/dist/Components/Forms/ApiForm.js +19 -2
  15. package/dist/Components/Forms/Crud.d.ts +2 -2
  16. package/dist/Components/Forms/Crud.js +871 -377
  17. package/dist/Components/Forms/CrudActions.d.ts +136 -0
  18. package/dist/Components/Forms/CrudActions.js +184 -0
  19. package/dist/Components/Forms/CrudHistory.d.ts +66 -0
  20. package/dist/Components/Forms/CrudHistory.js +140 -0
  21. package/dist/Components/Forms/CrudNarrowPicker.d.ts +31 -0
  22. package/dist/Components/Forms/CrudNarrowPicker.js +180 -0
  23. package/dist/Components/Forms/CrudParts.d.ts +30 -2
  24. package/dist/Components/Forms/CrudParts.js +56 -5
  25. package/dist/Components/Forms/CrudRowForms.d.ts +26 -0
  26. package/dist/Components/Forms/CrudRowForms.js +114 -0
  27. package/dist/Components/Forms/CrudScopes.d.ts +28 -0
  28. package/dist/Components/Forms/CrudScopes.js +76 -0
  29. package/dist/Components/Forms/CrudTree.d.ts +90 -0
  30. package/dist/Components/Forms/CrudTree.js +363 -0
  31. package/dist/Components/Forms/CrudWorkspace.d.ts +63 -0
  32. package/dist/Components/Forms/CrudWorkspace.js +169 -0
  33. package/dist/Components/Forms/ExcelImport.js +3 -3
  34. package/dist/Components/Forms/Form.d.ts +4 -4
  35. package/dist/Components/Forms/Form.js +125 -16
  36. package/dist/Components/Forms/FormLeaveGuard.d.ts +44 -0
  37. package/dist/Components/Forms/FormLeaveGuard.js +65 -0
  38. package/dist/Components/Forms/RecordFlows.d.ts +50 -0
  39. package/dist/Components/Forms/RecordFlows.js +282 -0
  40. package/dist/Components/Forms/SubmitForm.d.ts +37 -2
  41. package/dist/Components/Forms/SubmitForm.js +195 -10
  42. package/dist/Components/Inputs/CheckBox.js +1 -1
  43. package/dist/Components/Inputs/ChoiceField.d.ts +21 -1
  44. package/dist/Components/Inputs/ChoiceField.js +28 -2
  45. package/dist/Components/Inputs/CodeBox.d.ts +69 -0
  46. package/dist/Components/Inputs/CodeBox.js +316 -0
  47. package/dist/Components/Inputs/DatePicker.js +4 -1
  48. package/dist/Components/Inputs/DateRangePicker.js +4 -1
  49. package/dist/Components/Inputs/DateTimePicker.js +4 -1
  50. package/dist/Components/Inputs/Dropdown.d.ts +13 -0
  51. package/dist/Components/Inputs/Dropdown.js +8 -5
  52. package/dist/Components/Inputs/DropdownParts.d.ts +3 -1
  53. package/dist/Components/Inputs/DropdownParts.js +16 -4
  54. package/dist/Components/Inputs/Field.d.ts +7 -1
  55. package/dist/Components/Inputs/Field.js +2 -2
  56. package/dist/Components/Inputs/GroupForm.d.ts +6 -6
  57. package/dist/Components/Inputs/GroupForm.js +10 -11
  58. package/dist/Components/Inputs/InputRenderer.d.ts +9 -6
  59. package/dist/Components/Inputs/InputRenderer.js +39 -31
  60. package/dist/Components/Inputs/NumberBox.js +4 -2
  61. package/dist/Components/Inputs/PictureInput.d.ts +41 -0
  62. package/dist/Components/Inputs/PictureInput.js +70 -0
  63. package/dist/Components/Inputs/RadioGroup.d.ts +16 -3
  64. package/dist/Components/Inputs/RadioGroup.js +8 -3
  65. package/dist/Components/Inputs/RowsInput.d.ts +1 -1
  66. package/dist/Components/Inputs/RowsInput.js +18 -3
  67. package/dist/Components/Inputs/TabularForm.d.ts +5 -5
  68. package/dist/Components/Inputs/TabularForm.js +29 -29
  69. package/dist/Components/Inputs/TextArea.d.ts +6 -0
  70. package/dist/Components/Inputs/TextArea.js +14 -2
  71. package/dist/Components/Inputs/TextBox.js +4 -1
  72. package/dist/Components/Inputs/TextBoxTypes.d.ts +6 -0
  73. package/dist/Components/Inputs/TextBoxTypes.js +17 -0
  74. package/dist/Components/Inputs/TimePicker.js +4 -1
  75. package/dist/Components/Inputs/TreeView.d.ts +107 -6
  76. package/dist/Components/Inputs/TreeView.js +513 -30
  77. package/dist/Components/Layouts/MessageBox.d.ts +15 -2
  78. package/dist/Components/Layouts/MessageBox.js +56 -7
  79. package/dist/Components/Layouts/Popup.d.ts +13 -6
  80. package/dist/Components/Layouts/Popup.js +37 -9
  81. package/dist/Components/Layouts/PopupDock.d.ts +3 -1
  82. package/dist/Components/Layouts/PopupDock.js +2 -1
  83. package/dist/Components/Layouts/PopupHost.js +5 -4
  84. package/dist/Components/Layouts/ThemePicker.d.ts +3 -2
  85. package/dist/Components/Layouts/ThemePicker.js +16 -4
  86. package/dist/Components/Viewers/DataTable.js +205 -61
  87. package/dist/Components/Viewers/DataTableFilters.d.ts +1 -1
  88. package/dist/Components/Viewers/DataTableFilters.js +17 -2
  89. package/dist/Components/Viewers/DataTableParts.d.ts +46 -12
  90. package/dist/Components/Viewers/DataTableParts.js +62 -21
  91. package/dist/Components/Viewers/OwnerFiles.d.ts +175 -0
  92. package/dist/Components/Viewers/OwnerFiles.js +589 -0
  93. package/dist/Components/Viewers/QrCodeImage.d.ts +22 -0
  94. package/dist/Components/Viewers/QrCodeImage.js +15 -0
  95. package/dist/Components/Viewers/RecordCards.d.ts +16 -0
  96. package/dist/Components/Viewers/RecordCards.js +509 -0
  97. package/dist/Helpers/ApiModules.d.ts +3 -34
  98. package/dist/Helpers/ApiModules.js +3 -3
  99. package/dist/Helpers/ApiRoutes.d.ts +68 -26
  100. package/dist/Helpers/ApiRoutes.js +31 -27
  101. package/dist/Helpers/ArrayHelpers.d.ts +0 -0
  102. package/dist/Helpers/ArrayHelpers.js +2 -0
  103. package/dist/Helpers/BusyHooks.d.ts +6 -0
  104. package/dist/Helpers/BusyHooks.js +39 -0
  105. package/dist/Helpers/CodeHelpers.d.ts +97 -0
  106. package/dist/Helpers/CodeHelpers.js +332 -0
  107. package/dist/Helpers/CrudBackend.d.ts +114 -6
  108. package/dist/Helpers/CrudBackend.js +214 -11
  109. package/dist/Helpers/CrudColumns.d.ts +98 -0
  110. package/dist/Helpers/CrudColumns.js +160 -0
  111. package/dist/Helpers/CrudDetailsTabs.d.ts +58 -0
  112. package/dist/Helpers/CrudDetailsTabs.js +126 -0
  113. package/dist/Helpers/CrudHelpers.d.ts +130 -6
  114. package/dist/Helpers/CrudHelpers.js +304 -12
  115. package/dist/Helpers/CrudNarrowPick.d.ts +83 -0
  116. package/dist/Helpers/CrudNarrowPick.js +157 -0
  117. package/dist/Helpers/CrudRowForms.d.ts +15 -0
  118. package/dist/Helpers/CrudRowForms.js +43 -0
  119. package/dist/Helpers/CrudScopes.d.ts +32 -0
  120. package/dist/Helpers/CrudScopes.js +79 -0
  121. package/dist/Helpers/DropdownHelpers.d.ts +3 -1
  122. package/dist/Helpers/DropdownHelpers.js +6 -2
  123. package/dist/Helpers/ExcelHelpers.d.ts +1 -1
  124. package/dist/Helpers/ExcelHelpers.js +12 -11
  125. package/dist/Helpers/FileAdapter.d.ts +78 -0
  126. package/dist/Helpers/FileAdapter.js +102 -0
  127. package/dist/Helpers/FilePrimaries.d.ts +48 -0
  128. package/dist/Helpers/FilePrimaries.js +138 -0
  129. package/dist/Helpers/FormConfirm.d.ts +32 -0
  130. package/dist/Helpers/FormConfirm.js +40 -0
  131. package/dist/Helpers/FormStore.d.ts +90 -5
  132. package/dist/Helpers/FormStore.js +318 -22
  133. package/dist/Helpers/InputConditions.d.ts +50 -0
  134. package/dist/Helpers/InputConditions.js +168 -0
  135. package/dist/Helpers/InputMemory.d.ts +106 -0
  136. package/dist/Helpers/InputMemory.js +385 -0
  137. package/dist/Helpers/InputNarrowing.d.ts +18 -0
  138. package/dist/Helpers/InputNarrowing.js +67 -0
  139. package/dist/Helpers/InputParamsHelpers.d.ts +44 -1
  140. package/dist/Helpers/InputParamsHelpers.js +162 -71
  141. package/dist/Helpers/MessageBuilder.js +2 -0
  142. package/dist/Helpers/NexusDriveAdapter.d.ts +55 -0
  143. package/dist/Helpers/NexusDriveAdapter.js +207 -0
  144. package/dist/Helpers/NexusHelpers.d.ts +0 -0
  145. package/dist/Helpers/NexusHelpers.js +1 -0
  146. package/dist/Helpers/NumberHelpers.d.ts +95 -0
  147. package/dist/Helpers/NumberHelpers.js +126 -0
  148. package/dist/Helpers/Permissions.js +2 -1
  149. package/dist/Helpers/QrCode.d.ts +26 -0
  150. package/dist/Helpers/QrCode.js +463 -0
  151. package/dist/Helpers/RecordCards.d.ts +205 -0
  152. package/dist/Helpers/RecordCards.js +378 -0
  153. package/dist/Helpers/RequestCache.d.ts +47 -0
  154. package/dist/Helpers/RequestCache.js +132 -0
  155. package/dist/Helpers/RowsStore.d.ts +37 -2
  156. package/dist/Helpers/RowsStore.js +128 -10
  157. package/dist/Helpers/ServerPreview.d.ts +69 -0
  158. package/dist/Helpers/ServerPreview.js +99 -0
  159. package/dist/Helpers/TableColumns.js +4 -3
  160. package/dist/Helpers/TableExport.d.ts +7 -1
  161. package/dist/Helpers/TableExport.js +21 -15
  162. package/dist/Helpers/TableFilters.d.ts +1 -1
  163. package/dist/Helpers/TableFilters.js +24 -23
  164. package/dist/Helpers/TableHelpers.d.ts +24 -3
  165. package/dist/Helpers/TableHelpers.js +58 -12
  166. package/dist/Helpers/TableJoins.d.ts +83 -0
  167. package/dist/Helpers/TableJoins.js +284 -0
  168. package/dist/Helpers/TableStore.d.ts +26 -1
  169. package/dist/Helpers/TableStore.js +73 -7
  170. package/dist/Helpers/TreeStore.d.ts +306 -11
  171. package/dist/Helpers/TreeStore.js +1048 -90
  172. package/dist/Helpers/UserPreferences.d.ts +8 -0
  173. package/dist/Helpers/UserPreferences.js +17 -0
  174. package/dist/Interfaces/CrudInterfaces.d.ts +512 -14
  175. package/dist/Interfaces/FileInterfaces.d.ts +162 -0
  176. package/dist/Interfaces/FileInterfaces.js +4 -0
  177. package/dist/Interfaces/FormInterfaces.d.ts +393 -29
  178. package/dist/Interfaces/FormInterfaces.js +79 -1
  179. package/dist/Interfaces/InputInterfaces.d.ts +39 -3
  180. package/dist/Interfaces/MessageInterfaces.d.ts +1 -1
  181. package/dist/Interfaces/PreferenceInterfaces.d.ts +8 -0
  182. package/dist/Interfaces/PreferenceInterfaces.js +2 -5
  183. package/dist/Interfaces/RecordInterfaces.d.ts +367 -0
  184. package/dist/Interfaces/RecordInterfaces.js +1 -0
  185. package/dist/Interfaces/TableInterfaces.d.ts +160 -5
  186. package/dist/Services/ApiProxy.d.ts +36 -1
  187. package/dist/Services/ApiProxy.js +182 -52
  188. package/dist/Services/ApiProxyRules.d.ts +203 -0
  189. package/dist/Services/ApiProxyRules.js +426 -0
  190. package/dist/Services/ExcelApi.js +5 -0
  191. package/dist/Services/FileApi.d.ts +13 -0
  192. package/dist/Services/FileApi.js +29 -0
  193. package/dist/Services/ImageEditorLoader.d.ts +14 -0
  194. package/dist/Services/ImageEditorLoader.js +51 -0
  195. package/dist/Services/JoinSources.d.ts +80 -0
  196. package/dist/Services/JoinSources.js +150 -0
  197. package/dist/Services/ModuleImport.d.ts +7 -0
  198. package/dist/Services/ModuleImport.js +22 -0
  199. package/dist/Services/ServerApi.d.ts +13 -2
  200. package/dist/Services/ServerApi.js +8 -3
  201. package/dist/Shared.Index.d.ts +20 -0
  202. package/dist/Shared.Index.js +20 -0
  203. package/package.json +92 -85
  204. package/src/Styles/Nexus.Avatar.css +80 -79
  205. package/src/Styles/Nexus.Base.css +117 -117
  206. package/src/Styles/Nexus.Button.css +186 -180
  207. package/src/Styles/Nexus.Calendar.css +273 -273
  208. package/src/Styles/Nexus.Chat.css +1443 -1443
  209. package/src/Styles/Nexus.Choice.css +359 -343
  210. package/src/Styles/Nexus.Crud.css +542 -168
  211. package/src/Styles/Nexus.DateTime.css +81 -81
  212. package/src/Styles/Nexus.Dropdown.css +733 -725
  213. package/src/Styles/Nexus.Editor.css +295 -295
  214. package/src/Styles/Nexus.Excel.css +389 -389
  215. package/src/Styles/Nexus.Files.css +410 -0
  216. package/src/Styles/Nexus.Form.css +282 -279
  217. package/src/Styles/Nexus.Index.css +41 -37
  218. package/src/Styles/Nexus.Input.css +238 -4
  219. package/src/Styles/Nexus.Markdown.css +237 -237
  220. package/src/Styles/Nexus.Menu.css +246 -237
  221. package/src/Styles/Nexus.Popup.css +800 -724
  222. package/src/Styles/Nexus.Print.css +288 -0
  223. package/src/Styles/Nexus.QrCode.css +12 -0
  224. package/src/Styles/Nexus.Record.css +430 -0
  225. package/src/Styles/Nexus.Rows.css +637 -637
  226. package/src/Styles/Nexus.Slider.css +276 -276
  227. package/src/Styles/Nexus.Tab.Buttons.css +497 -432
  228. package/src/Styles/Nexus.Table.css +98 -35
  229. package/src/Styles/Nexus.Theme.Picker.css +59 -3
  230. package/src/Styles/Nexus.Themes.css +200 -194
  231. package/src/Styles/Nexus.Time.css +144 -144
  232. package/src/Styles/Nexus.Toast.css +263 -263
  233. package/src/Styles/Nexus.Tokens.css +94 -89
  234. package/src/Styles/Nexus.Tree.css +530 -431
@@ -0,0 +1,18 @@
1
+ import type { InputNarrowing, InputParams } from "../Interfaces/FormInterfaces.ts";
2
+ import type { OptionValue } from "../Interfaces/InputInterfaces.ts";
3
+ /** The value that narrows, or null while the other input has none: an empty text, an empty list and `false` count as none. */
4
+ export declare function narrowingValue(value: unknown): OptionValue | null;
5
+ /** What a narrowed box says while the other input is empty: "Pick a group first". */
6
+ export declare function narrowingPlaceholder(narrowing: InputNarrowing, otherLabel: unknown): string;
7
+ /** A narrowing by a fixed value (`{ key, value }`), not by another input. */
8
+ export declare function isFixedNarrowing(narrowing: InputNarrowing): boolean;
9
+ /**
10
+ * An input's params narrowed by the other input's value as it is now (or by the fixed `value` the narrowing gives): static `options` filtered to the records whose
11
+ * `key` field holds it; `loadOptions` asked with `request.narrow` (crudPicker reads it: from the server when its
12
+ * endpoint takes the parent, else from the list it keeps, narrowed in the browser), and a `loadKey` of its own per
13
+ * value, so the list loads afresh when the other value changes. While the other input is empty, no option is offered
14
+ * and the box says what to pick first. Params without `narrowedBy` are answered as they are.
15
+ *
16
+ * @example narrowInputParams(packageParams, form.get("subscriptionGroupId"), "Group")
17
+ */
18
+ export declare function narrowInputParams(params: InputParams, otherValue: unknown, otherLabel?: unknown): InputParams;
@@ -0,0 +1,67 @@
1
+ /*
2
+ * Options narrowed by another input's value (`narrowedBy`): a Package list of the Group picked, a Sub-region list of the
3
+ * Country picked. The form reads the other value as it draws and hands the input its params narrowed by it (this file,
4
+ * pure, so Node tests run it); the form's store clears the input's value when the other one changes (FormStore).
5
+ */
6
+ /** The value that narrows, or null while the other input has none: an empty text, an empty list and `false` count as none. */
7
+ export function narrowingValue(value) {
8
+ if (value === null || value === undefined || value === "" || value === false)
9
+ return null;
10
+ if (Array.isArray(value))
11
+ return value.length === 1 ? narrowingValue(value[0]) : null;
12
+ if (typeof value === "string" || typeof value === "number")
13
+ return value;
14
+ return null;
15
+ }
16
+ /** What a narrowed box says while the other input is empty: "Pick a group first". */
17
+ export function narrowingPlaceholder(narrowing, otherLabel) {
18
+ if (narrowing.placeholder)
19
+ return narrowing.placeholder;
20
+ if (narrowing.name === undefined)
21
+ return "";
22
+ const label = typeof otherLabel === "string" && otherLabel.trim() ? otherLabel.trim().toLocaleLowerCase() : narrowing.name;
23
+ return `Pick ${/^[aeiou]/i.test(label) ? "an" : "a"} ${label} first`;
24
+ }
25
+ const EMPTY_PAGE = { items: [], total: 0, hasMore: false };
26
+ /** A narrowing by a fixed value (`{ key, value }`), not by another input. */
27
+ export function isFixedNarrowing(narrowing) {
28
+ return narrowing.name === undefined;
29
+ }
30
+ /**
31
+ * An input's params narrowed by the other input's value as it is now (or by the fixed `value` the narrowing gives): static `options` filtered to the records whose
32
+ * `key` field holds it; `loadOptions` asked with `request.narrow` (crudPicker reads it: from the server when its
33
+ * endpoint takes the parent, else from the list it keeps, narrowed in the browser), and a `loadKey` of its own per
34
+ * value, so the list loads afresh when the other value changes. While the other input is empty, no option is offered
35
+ * and the box says what to pick first. Params without `narrowedBy` are answered as they are.
36
+ *
37
+ * @example narrowInputParams(packageParams, form.get("subscriptionGroupId"), "Group")
38
+ */
39
+ export function narrowInputParams(params, otherValue, otherLabel) {
40
+ const narrowing = params.narrowedBy;
41
+ if (!narrowing)
42
+ return params;
43
+ const fixed = narrowing.name === undefined;
44
+ const key = narrowing.key ?? narrowing.name ?? "";
45
+ const value = narrowingValue(fixed ? narrowing.value : otherValue);
46
+ const orUnset = narrowing.orUnset === true;
47
+ const keeps = (item) => {
48
+ if (item === null || typeof item !== "object")
49
+ return false;
50
+ const field = item[key];
51
+ return (value !== null && String(field) === String(value)) || (orUnset && (field === null || field === undefined || field === ""));
52
+ };
53
+ const own = params;
54
+ const narrowed = { ...own, loadKey: `${own.loadKey === undefined ? "" : String(own.loadKey)}|${narrowing.name ?? key}=${value === null ? "" : String(value)}` };
55
+ const placeholder = value === null ? narrowingPlaceholder(narrowing, otherLabel) : "";
56
+ if (placeholder)
57
+ narrowed.placeholder = placeholder;
58
+ // Nothing to narrow by offers nothing, unless the options with no value in the field are offered too (`orUnset`).
59
+ const none = value === null && !orUnset;
60
+ if (Array.isArray(own.options))
61
+ narrowed.options = none ? [] : own.options.filter(keeps);
62
+ const load = own.loadOptions;
63
+ if (load) {
64
+ narrowed.loadOptions = (request) => (none ? Promise.resolve(EMPTY_PAGE) : load({ ...request, narrow: { key, value, ...(orUnset && { orUnset }) } }));
65
+ }
66
+ return narrowed;
67
+ }
@@ -1,8 +1,24 @@
1
- import type { InputParams, InputValidationContext, RowsInputProps, RowValue } from "../Interfaces/FormInterfaces.ts";
1
+ import { type InputParams, type InputValidationContext, type RowsInputProps, type RowValue } from "../Interfaces/FormInterfaces.ts";
2
2
  /** Keys that place an input in a form; a renderer leaves them out of the component's props. */
3
3
  export declare const INPUT_LAYOUT_KEYS: readonly ["span", "width", "grow", "hidden"];
4
4
  /** Inputs whose value is `true` or `false`. */
5
5
  export declare const isBooleanInput: (params: InputParams) => params is import("../Shared.Index.ts").CheckBoxParams | import("../Shared.Index.ts").SwitchParams | import("../Shared.Index.ts").RadioParams;
6
+ /**
7
+ * The member name of an input type, for a message or a log: `inputTypeName(EInputTypes.RichText)` is "RichText". A number
8
+ * that is no member, such as one read from old data, comes back as its digits.
9
+ */
10
+ export declare const inputTypeName: (type: number) => string;
11
+ /**
12
+ * Whether an input holds a value of the form. A picture does not: it is the owner's file, changed at once through the
13
+ * file backend, so the form keeps no field for it and a save sends nothing under its name.
14
+ */
15
+ export declare const holdsValue: (params: InputParams) => params is import("../Shared.Index.ts").TextInputParams | import("../Shared.Index.ts").TextAreaParams | import("../Shared.Index.ts").NumberInputParams | import("../Shared.Index.ts").CodeInputParams | import("../Shared.Index.ts").CheckBoxParams | import("../Shared.Index.ts").SwitchParams | import("../Shared.Index.ts").RadioParams | import("../Shared.Index.ts").CheckBoxGroupParams | import("../Shared.Index.ts").RadioGroupParams | import("../Shared.Index.ts").DropdownParams | import("../Shared.Index.ts").DateParams | import("../Shared.Index.ts").DateRangeParams | import("../Shared.Index.ts").TimeParams | import("../Shared.Index.ts").DateTimeParams | import("../Shared.Index.ts").SliderParams | import("../Shared.Index.ts").RangeSliderParams | import("../Shared.Index.ts").MarkdownParams | import("../Shared.Index.ts").RichTextParams | import("../Shared.Index.ts").TreeParams | import("../Shared.Index.ts").TabularParams | import("../Shared.Index.ts").GroupParams;
16
+ /**
17
+ * Whether what is typed in an input is worth asking about before it is dropped: not a password or a one-time code (a
18
+ * `Code` box), which are typed again in a moment and never kept in a draft. Such a value alone makes no form ask
19
+ * "Discard your changes?" on Cancel or close, nor the page ask before it is left.
20
+ */
21
+ export declare const keepsTyping: (params: InputParams) => boolean;
6
22
  /** Inputs whose value is an array of rows. */
7
23
  export declare const isRowsInput: (params: InputParams) => params is import("../Shared.Index.ts").TabularParams | import("../Shared.Index.ts").GroupParams;
8
24
  /**
@@ -23,6 +39,33 @@ export declare function normalizeInputValue(params: InputParams, value: unknown)
23
39
  export declare function isEmptyInputValue(value: unknown): boolean;
24
40
  /** Equal values: the same primitive, or arrays with the same items in the same order. */
25
41
  export declare function inputValuesEqual(a: unknown, b: unknown): boolean;
42
+ /**
43
+ * The inputs with some of them fixed for one opening of a form: each input `locked` names (input name -> why) turns
44
+ * read-only and says why on any try to change it (`readOnlyMessage`), the lock-and-note look every input has. Its value
45
+ * stays in the form and is sent as before. A required input with no value in `values` stays free: fixed empty, the form
46
+ * would never ask for it, since read-only inputs are not checked. Names a form does not have are skipped.
47
+ *
48
+ * Each fixed input is a copy made from its own property descriptors, never a spread: a spread would read a getter once
49
+ * (`get readOnly()` or `get options()` following other values through `dependsOn`) and freeze it.
50
+ *
51
+ * To show fixed inputs disabled instead (dimmed, out of the Tab order, no note), write `disabled` for `readOnly` in the
52
+ * copy below.
53
+ *
54
+ * `known` are records the caller holds for the fixed values - the row picked in another list that a new record is added
55
+ * for: a fixed dropdown whose value one of them holds (by the dropdown's `valueKey`) gets it as a selected option, so its
56
+ * box names the value at once, with no lookup.
57
+ *
58
+ * @example lockInputs(REGION_INPUTS, { countryId: "Added inside Bagmati." }, { countryId: "c7" })
59
+ */
60
+ export declare function lockInputs(inputs: readonly InputParams[], locked: Readonly<Record<string, string>>, values?: Readonly<Record<string, unknown>>, known?: readonly Readonly<Record<string, unknown>>[]): InputParams[];
61
+ /**
62
+ * A form's `onFieldChange` that never writes the inputs fixed for an opening (`lockInputs`): a rule such as "a province
63
+ * sits right under its country" still changes a free field, and leaves a fixed one as the form opened it. With nothing
64
+ * fixed, or no rule, the rule as it is.
65
+ *
66
+ * @example lockedFieldChange(form.onFieldChange, ["countryId", "parentId"])
67
+ */
68
+ export declare function lockedFieldChange<TValues extends Record<string, unknown>>(onFieldChange: ((name: string, value: unknown, values: TValues) => Partial<TValues> | null | undefined | void) | undefined, fixed: readonly string[]): ((name: string, value: unknown, values: TValues) => Partial<TValues> | null | undefined | void) | undefined;
26
69
  /**
27
70
  * Checks a value against its input's rules and returns the first message, or `null` when it is valid: the same
28
71
  * message the input shows. Pure, so a form can check thousands of values on submit, including rows not on screen.
@@ -1,4 +1,6 @@
1
1
  import { DEFAULT_DATE_PREFERENCES } from "../Interfaces/DateInterfaces.js";
2
+ import { EInputTypes } from "../Interfaces/FormInterfaces.js";
3
+ import { formatCode, loadCode, validateCode } from "./CodeHelpers.js";
2
4
  import { formatDate, formatDateRange, toDateRange, toIsoDate, usesDevanagari } from "./DateHelpers.js";
3
5
  import { formatDateTime, toUtcDateTime } from "./DateTimeHelpers.js";
4
6
  import { formatNumber, parseNumber } from "./NumberHelpers.js";
@@ -14,9 +16,27 @@ import { chooseRowMessage, duplicateRowMessage, maxRowsMessage, minRowsMessage,
14
16
  /** Keys that place an input in a form; a renderer leaves them out of the component's props. */
15
17
  export const INPUT_LAYOUT_KEYS = ["span", "width", "grow", "hidden"];
16
18
  /** Inputs whose value is `true` or `false`. */
17
- export const isBooleanInput = (params) => params.type === "checkbox" || params.type === "switch" || params.type === "radio";
19
+ export const isBooleanInput = (params) => params.type === EInputTypes.CheckBox || params.type === EInputTypes.Switch || params.type === EInputTypes.Radio;
20
+ /** Each `EInputTypes` number with its member name. */
21
+ const INPUT_TYPE_NAMES = new Map(Object.entries(EInputTypes).map(([name, value]) => [value, name]));
22
+ /**
23
+ * The member name of an input type, for a message or a log: `inputTypeName(EInputTypes.RichText)` is "RichText". A number
24
+ * that is no member, such as one read from old data, comes back as its digits.
25
+ */
26
+ export const inputTypeName = (type) => INPUT_TYPE_NAMES.get(type) ?? String(type);
27
+ /**
28
+ * Whether an input holds a value of the form. A picture does not: it is the owner's file, changed at once through the
29
+ * file backend, so the form keeps no field for it and a save sends nothing under its name.
30
+ */
31
+ export const holdsValue = (params) => params.type !== EInputTypes.Picture;
32
+ /**
33
+ * Whether what is typed in an input is worth asking about before it is dropped: not a password or a one-time code (a
34
+ * `Code` box), which are typed again in a moment and never kept in a draft. Such a value alone makes no form ask
35
+ * "Discard your changes?" on Cancel or close, nor the page ask before it is left.
36
+ */
37
+ export const keepsTyping = (params) => params.type !== EInputTypes.Password && params.type !== EInputTypes.Code;
18
38
  /** Inputs whose value is an array of rows. */
19
- export const isRowsInput = (params) => params.type === "tabular" || params.type === "group";
39
+ export const isRowsInput = (params) => params.type === EInputTypes.Tabular || params.type === EInputTypes.Group;
20
40
  /**
21
41
  * The name an input's messages use, as the input itself picks it: `fieldName`, or the label when it is text. A checkbox's
22
42
  * label is usually a sentence, so it uses `fieldName` only.
@@ -25,35 +45,36 @@ export function inputFieldName(params) {
25
45
  const { fieldName } = params;
26
46
  if (fieldName)
27
47
  return fieldName;
28
- if (params.type === "checkbox" || params.type === "switch")
48
+ if (params.type === EInputTypes.CheckBox || params.type === EInputTypes.Switch)
29
49
  return undefined;
30
50
  return typeof params.label === "string" ? params.label : undefined;
31
51
  }
32
52
  /** The value of an input with nothing in it: "" for text, `null` for a number or a date, `false`, `[]`, and so on. */
33
53
  export function emptyInputValue(params) {
34
54
  switch (params.type) {
35
- case "number":
36
- case "date":
37
- case "time":
38
- case "date-time":
39
- case "radio-group":
55
+ case EInputTypes.Number:
56
+ case EInputTypes.Date:
57
+ case EInputTypes.Time:
58
+ case EInputTypes.DateTime:
59
+ case EInputTypes.RadioGroup:
60
+ case EInputTypes.Picture:
40
61
  return null;
41
- case "checkbox":
42
- case "switch":
43
- case "radio":
62
+ case EInputTypes.CheckBox:
63
+ case EInputTypes.Switch:
64
+ case EInputTypes.Radio:
44
65
  return false;
45
- case "checkbox-group":
46
- case "tree":
47
- case "tabular":
48
- case "group":
66
+ case EInputTypes.CheckBoxGroup:
67
+ case EInputTypes.Tree:
68
+ case EInputTypes.Tabular:
69
+ case EInputTypes.Group:
49
70
  return [];
50
- case "dropdown":
71
+ case EInputTypes.Dropdown:
51
72
  return params.multiple ? [] : null;
52
- case "date-range":
73
+ case EInputTypes.DateRange:
53
74
  return [null, null];
54
- case "slider":
75
+ case EInputTypes.Slider:
55
76
  return params.min ?? 0;
56
- case "range-slider":
77
+ case EInputTypes.RangeSlider:
57
78
  return [params.min ?? 0, params.max ?? 100];
58
79
  default:
59
80
  return "";
@@ -76,38 +97,41 @@ export function normalizeInputValue(params, value) {
76
97
  return emptyInputValue(params);
77
98
  }
78
99
  switch (params.type) {
79
- case "number": {
100
+ case EInputTypes.Number: {
80
101
  if (typeof value === "number")
81
102
  return Number.isNaN(value) ? null : value;
82
103
  return typeof value === "string" ? parseNumber(value, params.locale) : null;
83
104
  }
84
- case "checkbox":
85
- case "switch":
86
- case "radio":
105
+ case EInputTypes.CheckBox:
106
+ case EInputTypes.Switch:
107
+ case EInputTypes.Radio:
87
108
  return value === true || value === "true" || value === 1;
88
- case "date":
109
+ case EInputTypes.Date:
89
110
  return toIsoDate(value) ?? (typeof value === "string" ? value : null);
90
- case "date-range":
111
+ case EInputTypes.DateRange:
91
112
  return toDateRange(Array.isArray(value) ? value : null);
92
- case "time":
113
+ case EInputTypes.Time:
93
114
  return toIsoTime(value, normalizeTimeStep(params.step) % 60 !== 0) ?? (typeof value === "string" ? value : null);
94
- case "date-time":
115
+ case EInputTypes.DateTime:
95
116
  return toUtcDateTime(value) ?? (typeof value === "string" ? value : null);
96
- case "checkbox-group":
97
- case "tree":
98
- case "tabular":
99
- case "group":
117
+ case EInputTypes.CheckBoxGroup:
118
+ case EInputTypes.Tree:
119
+ case EInputTypes.Tabular:
120
+ case EInputTypes.Group:
100
121
  return Array.isArray(value) ? value : [];
101
- case "dropdown":
122
+ case EInputTypes.Dropdown:
102
123
  if (params.multiple)
103
124
  return Array.isArray(value) ? value : [value];
104
125
  return Array.isArray(value) ? (value[0] ?? null) : value;
105
- case "slider":
126
+ case EInputTypes.Slider:
106
127
  return typeof value === "number" ? value : (parseNumber(String(value)) ?? params.min ?? 0);
107
- case "range-slider":
128
+ case EInputTypes.RangeSlider:
108
129
  return Array.isArray(value) && value.length === 2 ? value : emptyInputValue(params);
109
- case "radio-group":
130
+ case EInputTypes.RadioGroup:
110
131
  return value;
132
+ case EInputTypes.Code:
133
+ // Only separators and case: a saved code that does not fit stays as it is, so its check refuses the save.
134
+ return loadCode(value, params);
111
135
  default:
112
136
  return typeof value === "string" ? value : String(value);
113
137
  }
@@ -130,6 +154,67 @@ export function inputValuesEqual(a, b) {
130
154
  return false;
131
155
  return a.every((item, index) => Object.is(item, b[index]));
132
156
  }
157
+ /**
158
+ * The inputs with some of them fixed for one opening of a form: each input `locked` names (input name -> why) turns
159
+ * read-only and says why on any try to change it (`readOnlyMessage`), the lock-and-note look every input has. Its value
160
+ * stays in the form and is sent as before. A required input with no value in `values` stays free: fixed empty, the form
161
+ * would never ask for it, since read-only inputs are not checked. Names a form does not have are skipped.
162
+ *
163
+ * Each fixed input is a copy made from its own property descriptors, never a spread: a spread would read a getter once
164
+ * (`get readOnly()` or `get options()` following other values through `dependsOn`) and freeze it.
165
+ *
166
+ * To show fixed inputs disabled instead (dimmed, out of the Tab order, no note), write `disabled` for `readOnly` in the
167
+ * copy below.
168
+ *
169
+ * `known` are records the caller holds for the fixed values - the row picked in another list that a new record is added
170
+ * for: a fixed dropdown whose value one of them holds (by the dropdown's `valueKey`) gets it as a selected option, so its
171
+ * box names the value at once, with no lookup.
172
+ *
173
+ * @example lockInputs(REGION_INPUTS, { countryId: "Added inside Bagmati." }, { countryId: "c7" })
174
+ */
175
+ export function lockInputs(inputs, locked, values = {}, known = []) {
176
+ return inputs.map(params => {
177
+ const reason = locked[params.name];
178
+ if (reason === undefined)
179
+ return params;
180
+ const required = params.required === true;
181
+ if (required && isEmptyInputValue(values[params.name]))
182
+ return params;
183
+ const fixed = {
184
+ ...Object.getOwnPropertyDescriptors(params),
185
+ readOnly: { value: true, enumerable: true, writable: true, configurable: true },
186
+ readOnlyMessage: { value: reason, enumerable: true, writable: true, configurable: true },
187
+ };
188
+ const value = values[params.name];
189
+ if (params.type === EInputTypes.Dropdown && !params.multiple && !isEmptyInputValue(value)) {
190
+ const valueKey = params.valueKey ?? "value";
191
+ const record = known.find(item => String(item[valueKey]) === String(value));
192
+ if (record)
193
+ fixed.selectedOptions = { value: [...(params.selectedOptions ?? []), record], enumerable: true, writable: true, configurable: true };
194
+ }
195
+ return Object.create(Object.getPrototypeOf(params), fixed);
196
+ });
197
+ }
198
+ /**
199
+ * A form's `onFieldChange` that never writes the inputs fixed for an opening (`lockInputs`): a rule such as "a province
200
+ * sits right under its country" still changes a free field, and leaves a fixed one as the form opened it. With nothing
201
+ * fixed, or no rule, the rule as it is.
202
+ *
203
+ * @example lockedFieldChange(form.onFieldChange, ["countryId", "parentId"])
204
+ */
205
+ export function lockedFieldChange(onFieldChange, fixed) {
206
+ if (!onFieldChange || fixed.length === 0)
207
+ return onFieldChange;
208
+ return (name, value, values) => {
209
+ const patch = onFieldChange(name, value, values);
210
+ if (!patch)
211
+ return patch;
212
+ const kept = { ...patch };
213
+ for (const field of fixed)
214
+ delete kept[field];
215
+ return kept;
216
+ };
217
+ }
133
218
  function dateSettings(params, preferences) {
134
219
  return {
135
220
  calendar: params.calendar ?? preferences.calendar,
@@ -160,35 +245,35 @@ export function validateInput(params, value, context = {}) {
160
245
  const name = inputFieldName(params);
161
246
  const preferences = context.preferences ?? DEFAULT_DATE_PREFERENCES;
162
247
  switch (params.type) {
163
- case "number":
248
+ case EInputTypes.Number:
164
249
  return validateNumber(value, params, name, limit => formatNumber(limit, { locale: params.locale, grouping: true }));
165
- case "checkbox":
166
- case "switch":
250
+ case EInputTypes.CheckBox:
251
+ case EInputTypes.Switch:
167
252
  return validateCheck(value === true, params, params.fieldName);
168
- case "radio":
253
+ case EInputTypes.Radio:
169
254
  // One row at a time can have it on; whether one must is the rows' rule.
170
255
  return null;
171
- case "checkbox-group":
256
+ case EInputTypes.CheckBoxGroup:
172
257
  return validateSelection(asArray(value), params, name);
173
- case "radio-group": {
258
+ case EInputTypes.RadioGroup: {
174
259
  const { validate } = params;
175
260
  return validateSelection(asArray(value), { required: params.required, validate: validate && (values => validate(values[0] ?? null)) }, name);
176
261
  }
177
- case "dropdown":
262
+ case EInputTypes.Dropdown:
178
263
  return validateSelection(asArray(value), { required: params.required, min: params.min, max: params.max, validate: params.validate }, name);
179
- case "date": {
264
+ case EInputTypes.Date: {
180
265
  const settings = dateSettings(params, preferences);
181
266
  return validateDate(value, params, name, iso => formatDate(iso, settings));
182
267
  }
183
- case "date-range": {
268
+ case EInputTypes.DateRange: {
184
269
  const settings = dateSettings(params, preferences);
185
270
  return validateDateRange(value, params, name, iso => formatDate(iso, settings));
186
271
  }
187
- case "time": {
272
+ case EInputTypes.Time: {
188
273
  const settings = timeSettings(params, preferences);
189
274
  return validateTime(value, params, name, iso => formatTime(iso, settings));
190
275
  }
191
- case "date-time": {
276
+ case EInputTypes.DateTime: {
192
277
  const seconds = normalizeTimeStep(params.step) % 60 !== 0;
193
278
  return validateDateTime(value, params, name, {
194
279
  ...dateSettings(params, preferences),
@@ -197,21 +282,24 @@ export function validateInput(params, value, context = {}) {
197
282
  seconds,
198
283
  });
199
284
  }
200
- case "slider":
285
+ case EInputTypes.Code:
286
+ return validateCode(value, params, name);
287
+ case EInputTypes.Slider:
201
288
  return params.validate?.(value) || null;
202
- case "range-slider":
289
+ case EInputTypes.RangeSlider:
203
290
  return params.validate?.(value) || null;
204
- case "tree":
291
+ case EInputTypes.Tree:
292
+ case EInputTypes.Picture:
205
293
  return null;
206
- case "rich-text":
294
+ case EInputTypes.RichText:
207
295
  return validateRichText(value, params, name);
208
- case "tabular":
209
- case "group": {
296
+ case EInputTypes.Tabular:
297
+ case EInputTypes.Group: {
210
298
  const result = validateRows(asArray(value), params, context);
211
299
  if (result.message)
212
300
  return result.message;
213
301
  const first = result.cells[0];
214
- return first ? `${rowsItemNames(params, params.type === "tabular" ? "Row" : "Item").title} ${first.index + 1}: ${first.message}` : null;
302
+ return first ? `${rowsItemNames(params, params.type === EInputTypes.Tabular ? "Row" : "Item").title} ${first.index + 1}: ${first.message}` : null;
215
303
  }
216
304
  default:
217
305
  return validateText(value, params, name);
@@ -257,7 +345,7 @@ export function rowsMessage(rows, rules, fallback = "Row") {
257
345
  if (rules.max !== undefined && count > rules.max)
258
346
  return maxRowsMessage(rules.max, names.item, names.items);
259
347
  for (const params of rules.inputs) {
260
- if (params.type !== "radio" || !params.required || params.hidden)
348
+ if (params.type !== EInputTypes.Radio || !params.required || params.hidden)
261
349
  continue;
262
350
  if (!rows.some(row => row[params.name] === true))
263
351
  return chooseRowMessage(radioName(params), names.item);
@@ -342,45 +430,48 @@ export function formatInputValue(params, value, context = {}) {
342
430
  return "";
343
431
  const preferences = context.preferences ?? DEFAULT_DATE_PREFERENCES;
344
432
  switch (params.type) {
345
- case "number": {
433
+ case EInputTypes.Number: {
346
434
  const text = formatNumber(value, { ...params, grouping: params.grouping ?? true });
347
435
  const prefix = typeof params.prefix === "string" ? params.prefix + " " : "";
348
436
  const suffix = typeof params.suffix === "string" ? " " + params.suffix : "";
349
437
  return prefix + text + suffix;
350
438
  }
351
- case "checkbox":
352
- case "switch":
353
- case "radio":
439
+ case EInputTypes.CheckBox:
440
+ case EInputTypes.Switch:
441
+ case EInputTypes.Radio:
354
442
  return typeof params.label === "string" ? params.label : "";
355
- case "dropdown":
443
+ case EInputTypes.Dropdown:
356
444
  return asArray(value)
357
445
  .map(item => optionLabel(params.options, item, params.valueKey, params.labelKey))
358
446
  .join(", ");
359
- case "checkbox-group":
360
- case "radio-group":
447
+ case EInputTypes.CheckBoxGroup:
448
+ case EInputTypes.RadioGroup:
361
449
  return asArray(value)
362
450
  .map(item => optionLabel(params.options, item))
363
451
  .join(", ");
364
- case "date":
452
+ case EInputTypes.Date:
365
453
  return formatDate(value, dateSettings(params, preferences));
366
- case "date-range":
454
+ case EInputTypes.DateRange:
367
455
  return formatDateRange(value, dateSettings(params, preferences));
368
- case "time":
456
+ case EInputTypes.Time:
369
457
  return formatTime(value, timeSettings(params, preferences));
370
- case "date-time":
458
+ case EInputTypes.DateTime:
371
459
  return formatDateTime(value, { ...dateSettings(params, preferences), timeFormat: params.timeFormat ?? preferences.timeFormat, timeZone: params.timeZone });
372
- case "slider":
460
+ case EInputTypes.Code:
461
+ return formatCode(value, params);
462
+ case EInputTypes.Slider:
373
463
  return formatNumber(value, params);
374
- case "range-slider":
464
+ case EInputTypes.RangeSlider:
375
465
  return asArray(value)
376
466
  .map(item => formatNumber(item, params))
377
467
  .join(" – ");
378
- case "tree":
379
- case "tabular":
380
- case "group":
468
+ case EInputTypes.Tree:
469
+ case EInputTypes.Tabular:
470
+ case EInputTypes.Group:
471
+ case EInputTypes.Picture:
381
472
  return "";
382
473
  default: {
383
- const text = params.type === "rich-text" ? richTextToPlainText(String(value)) : String(value).trim();
474
+ const text = params.type === EInputTypes.RichText ? richTextToPlainText(String(value)) : String(value).trim();
384
475
  const line = text.split("\n", 1)[0] ?? "";
385
476
  return line.length > 60 ? line.slice(0, 57) + "…" : line;
386
477
  }
@@ -17,6 +17,8 @@ const DEFAULT_WORDS = {
17
17
  unflag: { verb: "unflag", done: "unflagged", doing: "Unflagging", object: "the record" },
18
18
  pin: { verb: "pin", done: "pinned", doing: "Pinning", object: "the record" },
19
19
  unpin: { verb: "unpin", done: "unpinned", doing: "Unpinning", object: "the record" },
20
+ favorite: { verb: "add {object} to the favourites", done: "added to the favourites", doing: "Adding {object} to the favourites", object: "the record" },
21
+ unfavorite: { verb: "remove {object} from the favourites", done: "removed from the favourites", doing: "Removing {object} from the favourites", object: "the record" },
20
22
  send: { verb: "send", done: "sent", doing: "Sending", object: "the message", sendsValues: true },
21
23
  submit: { verb: "submit", done: "submitted", doing: "Submitting", object: "the form", sendsValues: true },
22
24
  upload: { verb: "upload", done: "uploaded", doing: "Uploading", object: "the file", sendsValues: true },
@@ -0,0 +1,55 @@
1
+ import type { ApiClient } from "./ApiClient.ts";
2
+ import { FileAdapter } from "./FileAdapter.ts";
3
+ import { type ApiModuleValue, type ApiResult } from "../Interfaces/ApiInterfaces.ts";
4
+ import type { FileCallOptions, FileCopy, FileOwner, FileUpload, OwnerFiles, StoredFile } from "../Interfaces/FileInterfaces.ts";
5
+ /**
6
+ * Why an owner's files are read only when its module refuses a write ticket with a 404 but a read ticket finds it: the
7
+ * owner is not in use now (pending, ended, in the trash or deleted). Its files stay where they are.
8
+ */
9
+ export declare const OWNER_NOT_IN_USE_REASON = "This record is not in use now, so its files can be seen but not changed.";
10
+ /** What the adapter sends its calls with: the app's `api` (nexus-shared/client), so its token and headers go with them. */
11
+ export type FileApiClient = Pick<ApiClient<{
12
+ toast?: false;
13
+ }>, "send">;
14
+ export interface NexusDriveAdapterOptions {
15
+ /** The client the calls go through: `api` from nexus-shared/client. */
16
+ client: FileApiClient;
17
+ /** Reads the editor's pointer file. Default the browser's `fetch`. */
18
+ fetch?: typeof fetch;
19
+ /** The app's Drive module. Default `NexusModule.Drive`. */
20
+ drive?: ApiModuleValue;
21
+ /** The pointer file that names the current editor. Default `nexus-image-editor.txt` (Drive's `copy-image-editor.mjs`). */
22
+ editorPointer?: string;
23
+ }
24
+ /**
25
+ * The Nexus Drive (`Nexus.Drives`, `App/Api/File/...`) behind the owner modules' tickets (`App/Api/Files/...`).
26
+ * Register another with `defineFileAdapter` to keep files elsewhere.
27
+ */
28
+ export declare class NexusDriveAdapter extends FileAdapter {
29
+ readonly drive: ApiModuleValue;
30
+ readonly editorPointer: string;
31
+ private readonly tickets;
32
+ private readonly client;
33
+ private readonly fetcher;
34
+ constructor(options: NexusDriveAdapterOptions);
35
+ private driveEndpoint;
36
+ /** A write ticket for the owner, kept while it is good. */
37
+ private writeTicket;
38
+ /** Calls Drive with the owner's write ticket, asking for a fresh one once when Drive says it ran out. */
39
+ private withTicket;
40
+ /** A read ticket for several owners of one category. */
41
+ private readTicket;
42
+ list(owner: FileOwner<ApiModuleValue>, options?: FileCallOptions): Promise<ApiResult<OwnerFiles>>;
43
+ primaries(module: ApiModuleValue, category: string, ownerIds: readonly string[], options?: FileCallOptions): Promise<ApiResult<(StoredFile | null)[]>>;
44
+ upload(owner: FileOwner<ApiModuleValue>, upload: FileUpload, options?: FileCallOptions): Promise<ApiResult<StoredFile>>;
45
+ setPrimary(owner: FileOwner<ApiModuleValue>, fileId: string | null, options?: FileCallOptions): Promise<ApiResult<unknown>>;
46
+ rename(owner: FileOwner<ApiModuleValue>, fileId: string, name: string, options?: FileCallOptions): Promise<ApiResult<unknown>>;
47
+ remove(owner: FileOwner<ApiModuleValue>, fileId: string, options?: FileCallOptions): Promise<ApiResult<unknown>>;
48
+ fileUrl(file: StoredFile, copy: FileCopy): string;
49
+ /** Reads Drive's pointer file (`Assets/File/nexus-image-editor.txt`), which names the versioned module beside it. */
50
+ editorModuleUrl(signal?: AbortSignal): Promise<string>;
51
+ }
52
+ /** Reads one of Drive's `FileResponseContract`s; null when it is not one. */
53
+ export declare function readStoredFile(value: unknown): StoredFile | null;
54
+ /** Reads Drive's `FileListResponseContract`. */
55
+ export declare function readOwnerFiles(value: unknown): OwnerFiles;