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
@@ -4,8 +4,10 @@ import { iconAlertCircle, iconArrowBackUp, iconPlus, InlineIcon } from "nexus-ic
4
4
  import { memo, useCallback, useEffect, useId, useImperativeHandle, useLayoutEffect, useRef, useState, useSyncExternalStore, } from "react";
5
5
  import { cx } from "../../Helpers/ClassHelpers.js";
6
6
  import { useDatePreferences } from "../../Helpers/DatePreferences.js";
7
+ import { browserInputMemory, FORM_SAVED_EVENT } from "../../Helpers/InputMemory.js";
7
8
  import { inputFieldName } from "../../Helpers/InputParamsHelpers.js";
8
9
  import { RowsStore } from "../../Helpers/RowsStore.js";
10
+ import { EInputTypes } from "../../Interfaces/FormInterfaces.js";
9
11
  import { Button } from "../Documents/Button.js";
10
12
  import { hasContent } from "./Field.js";
11
13
  import { isFirstInvalid } from "./InputField.js";
@@ -64,7 +66,14 @@ export function useRowsInput(props, fallbackItem, layoutRef) {
64
66
  });
65
67
  }, [store, syncValidity]);
66
68
  useEffect(syncValidity);
67
- // Inside a form: the rows go into its data as JSON under `name`, and a reset brings back the rows loaded last.
69
+ // Remembered row inputs (`remember`) read and keep their values in this browser: rows added from now on open on them.
70
+ // Given once drawn, so the server's draw and the first one in the browser are the same.
71
+ useLayoutEffect(() => {
72
+ if (inputs.some(params => params.remember))
73
+ store.attachMemory(browserInputMemory());
74
+ }, [store, inputs]);
75
+ // Inside a form: the rows go into its data as JSON under `name`, a reset brings back the rows loaded last, and a save
76
+ // (a SubmitForm's) keeps the remembered values of the row added last.
68
77
  useEffect(() => {
69
78
  const form = proxyRef.current?.form;
70
79
  if (!form)
@@ -79,11 +88,17 @@ export function useRowsInput(props, fallbackItem, layoutRef) {
79
88
  };
80
89
  // The reset event comes before the browser restores the fields.
81
90
  const onReset = () => setTimeout(() => store.reset());
91
+ const onSaved = () => {
92
+ if (!latest.current.disabled)
93
+ store.rememberAdded();
94
+ };
82
95
  form.addEventListener("formdata", onFormData);
83
96
  form.addEventListener("reset", onReset);
97
+ form.addEventListener(FORM_SAVED_EVENT, onSaved);
84
98
  return () => {
85
99
  form.removeEventListener("formdata", onFormData);
86
100
  form.removeEventListener("reset", onReset);
101
+ form.removeEventListener(FORM_SAVED_EVENT, onSaved);
87
102
  };
88
103
  }, [store, props.form, name]);
89
104
  function focusProblem(place) {
@@ -236,7 +251,7 @@ export function labelText(params) {
236
251
  export const RowCell = memo(function RowCell({ store, rowKey, params, index, error, layout, idPrefix, size, design, readOnly, disabled, lock }) {
237
252
  const [initial] = useState(() => store.get(rowKey, params.name));
238
253
  const onValueChange = useCallback((next) => store.set(rowKey, params.name, next, "input"), [store, rowKey, params.name]);
239
- const needsName = params.type === "radio-group" || params.type === "checkbox-group";
254
+ const needsName = params.type === EInputTypes.RadioGroup || params.type === EInputTypes.CheckBoxGroup;
240
255
  const overrides = {
241
256
  id: `${idPrefix}-${rowKey.replace(/[^A-Za-z0-9_-]/g, "_")}-${params.name}`,
242
257
  // Nothing goes into a parent form by itself: the rows go in whole, under the rows input's name.
@@ -257,7 +272,7 @@ export const RowCell = memo(function RowCell({ store, rowKey, params, index, err
257
272
  if (error !== undefined)
258
273
  overrides.error = error;
259
274
  // A required radio means one row has it on, which the rows check; each radio alone is not required.
260
- if (params.type === "radio")
275
+ if (params.type === EInputTypes.Radio)
261
276
  overrides.required = false;
262
277
  if (layout === "tabular") {
263
278
  overrides.label = undefined;
@@ -1,4 +1,4 @@
1
- import type { RowValue, TabularFormProps } from "../../Interfaces/FormInterfaces.ts";
1
+ import { type RowValue, type TabularFormProps } from "../../Interfaces/FormInterfaces.ts";
2
2
  /**
3
3
  * Rows of inputs in a table, one column per input: a person's emails or addresses, invoice lines, a salary sheet. The
4
4
  * value is an array of row objects, one value per input, with any other fields the rows came with (such as ids). Inputs
@@ -18,10 +18,10 @@ import type { RowValue, TabularFormProps } from "../../Interfaces/FormInterfaces
18
18
  *
19
19
  * @example
20
20
  * <TabularForm name="emails" label="Emails" itemLabel="Email" max={5} unique={["email"]} inputs={[
21
- * { type: "email", name: "email", label: "Email", required: true, pattern: TEXT_PATTERNS.email },
22
- * { type: "dropdown", name: "type", label: "Type", options: EMAIL_TYPES },
23
- * { type: "checkbox", name: "isVerified", label: "Verified" },
24
- * { type: "radio", name: "isPrimary", label: "Primary", required: true },
21
+ * { type: EInputTypes.Email, name: "email", label: "Email", required: true, pattern: TEXT_PATTERNS.email },
22
+ * { type: EInputTypes.Dropdown, name: "type", label: "Type", options: EMAIL_TYPES },
23
+ * { type: EInputTypes.CheckBox, name: "isVerified", label: "Verified" },
24
+ * { type: EInputTypes.Radio, name: "isPrimary", label: "Primary", required: true },
25
25
  * ]} />
26
26
  */
27
27
  export declare function TabularForm<TRow extends RowValue = RowValue>(props: TabularFormProps<TRow>): import("react").JSX.Element;
@@ -3,6 +3,8 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { iconArrowDown, iconArrowUp, iconCopy, iconDotsVertical, iconLock, iconLockOpen, iconRowInsertBottom, iconRowInsertTop, iconTrash, InlineIcon } from "nexus-icons";
4
4
  import { memo, useCallback, useLayoutEffect, useMemo, useRef, useState, } from "react";
5
5
  import { cx } from "../../Helpers/ClassHelpers.js";
6
+ import { isBooleanInput } from "../../Helpers/InputParamsHelpers.js";
7
+ import { EInputTypes } from "../../Interfaces/FormInterfaces.js";
6
8
  import { Menu } from "../Documents/Menu.js";
7
9
  import { firstFocusable, labelText, RowCell, RowsFooter, RowsLegend, useRowsFrame, useRowsInput, useRowVersion } from "./RowsInput.js";
8
10
  /** Height of a row: the input's box and the line under it. Measured from the first row once it renders. */
@@ -12,38 +14,36 @@ const OVERSCAN = 8;
12
14
  const DEFAULT_MAX_HEIGHT = 440;
13
15
  /** A column's width by input type, when its params give none. */
14
16
  const COLUMN_WIDTH = {
15
- text: "10rem",
16
- email: "13rem",
17
- password: "10rem",
18
- search: "10rem",
19
- tel: "9rem",
20
- url: "13rem",
21
- textarea: "14rem",
22
- number: "7.5rem",
23
- checkbox: "6rem",
24
- switch: "6rem",
25
- radio: "6rem",
26
- "checkbox-group": "16rem",
27
- "radio-group": "16rem",
28
- dropdown: "10rem",
29
- date: "10rem",
30
- "date-range": "15rem",
31
- time: "8rem",
32
- "date-time": "14rem",
33
- slider: "10rem",
34
- "range-slider": "12rem",
17
+ [EInputTypes.Text]: "10rem",
18
+ [EInputTypes.Email]: "13rem",
19
+ [EInputTypes.Password]: "10rem",
20
+ [EInputTypes.Search]: "10rem",
21
+ [EInputTypes.Tel]: "9rem",
22
+ [EInputTypes.Url]: "13rem",
23
+ [EInputTypes.TextArea]: "14rem",
24
+ [EInputTypes.Number]: "7.5rem",
25
+ [EInputTypes.CheckBox]: "6rem",
26
+ [EInputTypes.Switch]: "6rem",
27
+ [EInputTypes.Radio]: "6rem",
28
+ [EInputTypes.CheckBoxGroup]: "16rem",
29
+ [EInputTypes.RadioGroup]: "16rem",
30
+ [EInputTypes.Dropdown]: "10rem",
31
+ [EInputTypes.Date]: "10rem",
32
+ [EInputTypes.DateRange]: "15rem",
33
+ [EInputTypes.Time]: "8rem",
34
+ [EInputTypes.DateTime]: "14rem",
35
+ [EInputTypes.Slider]: "10rem",
36
+ [EInputTypes.RangeSlider]: "12rem",
35
37
  };
36
- /** Columns that keep their width instead of sharing the spare room. */
37
- const FIXED_TYPES = new Set(["checkbox", "switch", "radio"]);
38
38
  /** What a locked row's cells say when one is used. */
39
39
  const LOCKED_ROW = "Locked: unlock the row to change it.";
40
40
  const ENTER_MOVES = new Set(["text", "email", "tel", "url", "search", "password", "number"]);
41
41
  const cssLength = (value) => (typeof value === "number" ? `${value}px` : value);
42
42
  /** How a cell lines up: numbers at the end, checkboxes and radios in the middle, the rest at the start. */
43
43
  function cellKind(params) {
44
- if (params.type === "number")
44
+ if (params.type === EInputTypes.Number)
45
45
  return "number";
46
- if (FIXED_TYPES.has(params.type))
46
+ if (isBooleanInput(params))
47
47
  return "check";
48
48
  return "text";
49
49
  }
@@ -105,10 +105,10 @@ const TabularRow = memo(function TabularRow({ store, rowKey, index, count, colum
105
105
  *
106
106
  * @example
107
107
  * <TabularForm name="emails" label="Emails" itemLabel="Email" max={5} unique={["email"]} inputs={[
108
- * { type: "email", name: "email", label: "Email", required: true, pattern: TEXT_PATTERNS.email },
109
- * { type: "dropdown", name: "type", label: "Type", options: EMAIL_TYPES },
110
- * { type: "checkbox", name: "isVerified", label: "Verified" },
111
- * { type: "radio", name: "isPrimary", label: "Primary", required: true },
108
+ * { type: EInputTypes.Email, name: "email", label: "Email", required: true, pattern: TEXT_PATTERNS.email },
109
+ * { type: EInputTypes.Dropdown, name: "type", label: "Type", options: EMAIL_TYPES },
110
+ * { type: EInputTypes.CheckBox, name: "isVerified", label: "Verified" },
111
+ * { type: EInputTypes.Radio, name: "isPrimary", label: "Primary", required: true },
112
112
  * ]} />
113
113
  */
114
114
  export function TabularForm(props) {
@@ -359,7 +359,7 @@ export function TabularForm(props) {
359
359
  const template = [
360
360
  numbered ? numberWidth : null,
361
361
  ...columns.map((params, index) => {
362
- const grow = params.grow ?? (FIXED_TYPES.has(params.type) ? 0 : 1);
362
+ const grow = params.grow ?? (isBooleanInput(params) ? 0 : 1);
363
363
  return grow > 0 ? `minmax(${widths[index]}, ${grow}fr)` : widths[index];
364
364
  }),
365
365
  actionsWidth,
@@ -22,6 +22,12 @@ export interface TextAreaProps extends NativeTextAreaProps, TextRules {
22
22
  maxRows?: number;
23
23
  /** Shows the character count, and the limit when `maxLength` is set. */
24
24
  showCount?: boolean;
25
+ /**
26
+ * Text that is code (HTML, JSON): the monospace font, lines kept as typed (no wrapping, a long line scrolls sideways
27
+ * inside the box), a tab two spaces wide, and no spelling, capitals, corrections, suggestions or translation. Tab still
28
+ * leaves the box, so a keyboard is never trapped in it.
29
+ */
30
+ code?: boolean;
25
31
  /** What a read-only field says when someone tries to change it. Default "Read-only: this field cannot be changed." */
26
32
  readOnlyMessage?: string;
27
33
  /** Name used in messages. Default: the label, when it is text. */
@@ -4,13 +4,25 @@ import { cx } from "../../Helpers/ClassHelpers.js";
4
4
  import { Field } from "./Field.js";
5
5
  import { useReadOnlyNotice } from "./ReadOnlyNotice.js";
6
6
  import { useTextField } from "./TextField.js";
7
+ import { useInputDesign } from "../../Helpers/UserPreferences.js";
8
+ /** A `code` text area's attributes: lines kept as typed, and nothing that would change what was typed. A page's own props win. */
9
+ const CODE_PROPS = {
10
+ wrap: "off",
11
+ spellCheck: false,
12
+ autoCapitalize: "off",
13
+ autoCorrect: "off",
14
+ autoComplete: "off",
15
+ translate: "no",
16
+ };
7
17
  /**
8
18
  * A multi-line text input with the same label, hint, validation, and designs as `TextBox`.
9
19
  *
10
20
  * @example <TextArea label="Description" maxLength={500} showCount autoResize />
11
21
  */
12
22
  export function TextArea(props) {
13
- const { label, hint, error, design = "standard", size = "md", icon, rows = 3, autoResize = false, maxRows = 12, showCount = false, readOnlyMessage = "Read-only: this field cannot be changed.", fieldName, validateOn, onValueChange, className, textAreaClassName, style, required, minLength, maxLength, pattern, patternMessage, validate, placeholder, disabled, readOnly, ref, onChange, onBlur, onInvalid, onKeyDown, onClick, ...textAreaProps } = props;
23
+ const { label, hint, error, design: ownDesign, size = "md", icon, rows = 3, autoResize = false, maxRows = 12, showCount = false, code = false, readOnlyMessage = "Read-only: this field cannot be changed.", fieldName, validateOn, onValueChange, className, textAreaClassName, style, required, minLength, maxLength, pattern, patternMessage, validate, placeholder, disabled, readOnly, ref, onChange, onBlur, onInvalid, onKeyDown, onClick, ...textAreaProps } = props;
24
+ // The person's input design (the quick preferences) when this page and its form name none, for a labelled input.
25
+ const design = useInputDesign(ownDesign, Boolean(label));
14
26
  const field = useTextField(props);
15
27
  const rowsStyle = { "--nx-field-rows": rows, "--nx-field-max-rows": Math.max(rows, maxRows) };
16
28
  // A lock at the top end of the box, and a note under it when someone tries to change the text, say why nothing happens.
@@ -27,5 +39,5 @@ export function TextArea(props) {
27
39
  readOnlyNotice.hide();
28
40
  field.controlProps.onBlur(event);
29
41
  }
30
- return (_jsxs(_Fragment, { children: [_jsx(Field, { controlId: field.controlId, messageId: field.messageId, label: label, required: required, design: design, size: size, hint: hint, error: field.error, icon: icon, actions: readOnlyNotice.lock, aside: field.count, disabled: disabled, readOnly: readOnly, raiseLabel: Boolean(placeholder), multiline: true, className: className, style: { ...rowsStyle, ...style }, children: _jsx("textarea", { ...textAreaProps, ...field.controlProps, className: cx("nx-field__control", autoResize && "nx-field__control--auto", textAreaClassName), rows: rows, placeholder: placeholder || " ", disabled: disabled, readOnly: readOnly, onClick: handleClick, onBlur: handleBlur, onKeyDown: handleKeyDown }) }), readOnlyNotice.notice] }));
42
+ return (_jsxs(_Fragment, { children: [_jsx(Field, { controlId: field.controlId, messageId: field.messageId, label: label, required: required, design: design, size: size, hint: hint, error: field.error, icon: icon, actions: readOnlyNotice.lock, aside: field.count, disabled: disabled, readOnly: readOnly, raiseLabel: Boolean(placeholder), multiline: true, className: className, style: { ...rowsStyle, ...style }, children: _jsx("textarea", { ...(code ? CODE_PROPS : null), ...textAreaProps, ...field.controlProps, className: cx("nx-field__control", autoResize && "nx-field__control--auto", code && "nx-field__control--code", textAreaClassName), rows: rows, placeholder: placeholder || " ", disabled: disabled, readOnly: readOnly, onClick: handleClick, onBlur: handleBlur, onKeyDown: handleKeyDown }) }), readOnlyNotice.notice] }));
31
43
  }
@@ -7,6 +7,7 @@ import { Field, hasContent } from "./Field.js";
7
7
  import { setInputValue } from "./InputField.js";
8
8
  import { useReadOnlyNotice } from "./ReadOnlyNotice.js";
9
9
  import { useTextField } from "./TextField.js";
10
+ import { useInputDesign } from "../../Helpers/UserPreferences.js";
10
11
  // Values that are not prose: no red spell-check underline, no capital first letter on phones.
11
12
  const PLAIN_TYPES = new Set(["email", "password", "tel", "url"]);
12
13
  /**
@@ -17,7 +18,9 @@ const PLAIN_TYPES = new Set(["email", "password", "tel", "url"]);
17
18
  * @example <TextBox label="Email" type="email" required pattern={TEXT_PATTERNS.email} icon={<InlineIcon icon={iconMail} />} />
18
19
  */
19
20
  export function TextBox(props) {
20
- const { type = "text", label, hint, error, design = "standard", size = "md", icon, iconEnd, prefix, suffix, actionsStart, clearable = false, showCount = false, readOnlyMessage = "Read-only: this field cannot be changed.", fieldName, validateOn, onValueChange, className, inputClassName, style, required, minLength, maxLength, pattern, patternMessage, validate, placeholder, disabled, readOnly, ref, onChange, onBlur, onInvalid, onKeyDown, onClick, ...inputProps } = props;
21
+ const { type = "text", label, hint, error, design: ownDesign, size = "md", icon, iconEnd, prefix, suffix, actionsStart, clearable = false, showCount = false, readOnlyMessage = "Read-only: this field cannot be changed.", fieldName, validateOn, onValueChange, className, inputClassName, style, required, minLength, maxLength, pattern, patternMessage, validate, placeholder, disabled, readOnly, ref, onChange, onBlur, onInvalid, onKeyDown, onClick, ...inputProps } = props;
22
+ // The person's input design (the quick preferences) when this page and its form name none, for a labelled input.
23
+ const design = useInputDesign(ownDesign, Boolean(label));
21
24
  const field = useTextField(props);
22
25
  const [revealed, setRevealed] = useState(false);
23
26
  const editable = !disabled && !readOnly;
@@ -0,0 +1,6 @@
1
+ import { EInputTypes, type TextInputType } from "../../Interfaces/FormInterfaces.ts";
2
+ import type { TextBoxType } from "./TextBox.tsx";
3
+ /** The HTML type of each text box kind. */
4
+ export declare const TEXT_BOX_TYPES: Readonly<Record<TextInputType, TextBoxType>>;
5
+ /** Whether a `TextBox` renders this input type, e.g. `true` for `EInputTypes.Email`, `false` for `EInputTypes.TextArea`. */
6
+ export declare const isTextInputType: (type: EInputTypes) => type is TextInputType;
@@ -0,0 +1,17 @@
1
+ import { EInputTypes } from "../../Interfaces/FormInterfaces.js";
2
+ /*
3
+ * Which input types a `TextBox` renders, and the HTML type each one gets: the one place an input type becomes a string.
4
+ * `renderInput` reads it; it is its own file, not exported from the package, so the unit suites can check it without
5
+ * a browser (scripts/test-form-store.mts).
6
+ */
7
+ /** The HTML type of each text box kind. */
8
+ export const TEXT_BOX_TYPES = {
9
+ [EInputTypes.Text]: "text",
10
+ [EInputTypes.Email]: "email",
11
+ [EInputTypes.Password]: "password",
12
+ [EInputTypes.Search]: "search",
13
+ [EInputTypes.Tel]: "tel",
14
+ [EInputTypes.Url]: "url",
15
+ };
16
+ /** Whether a `TextBox` renders this input type, e.g. `true` for `EInputTypes.Email`, `false` for `EInputTypes.TextArea`. */
17
+ export const isTextInputType = (type) => Object.hasOwn(TEXT_BOX_TYPES, type);
@@ -12,6 +12,7 @@ import { Field, hasContent } from "./Field.js";
12
12
  import { setInputValue, useInputField } from "./InputField.js";
13
13
  import { useReadOnlyNotice } from "./ReadOnlyNotice.js";
14
14
  import { TimePanel } from "./TimePanel.js";
15
+ import { useInputDesign } from "../../Helpers/UserPreferences.js";
15
16
  /**
16
17
  * A time input: type a time on either clock ("2:30 pm", "1430"), or pick one from the panel that opens under the box.
17
18
  * Written in the user's time format, 12- or 24-hour, and always held as an ISO time with no date and no zone, which a
@@ -20,7 +21,9 @@ import { TimePanel } from "./TimePanel.js";
20
21
  * @example <TimePicker name="arrival" label="Arrival" min="12:00" max="22:00" step={1800} view="list" />
21
22
  */
22
23
  export function TimePicker(props) {
23
- const { label, hint, error, design = "standard", size = "md", icon, prefix, view = "columns", clearable = true, fieldName, readOnlyMessage = "Read-only: this time cannot be changed.", validateOn, value, defaultValue, onValueChange, isTimeDisabled, className, inputClassName, style, required, min, max, step, validate, name, form, placeholder, disabled, readOnly, ref, onChange, onBlur, onFocus, onInvalid, onKeyDown, onClick, ...inputProps } = props;
24
+ const { label, hint, error, design: ownDesign, size = "md", icon, prefix, view = "columns", clearable = true, fieldName, readOnlyMessage = "Read-only: this time cannot be changed.", validateOn, value, defaultValue, onValueChange, isTimeDisabled, className, inputClassName, style, required, min, max, step, validate, name, form, placeholder, disabled, readOnly, ref, onChange, onBlur, onFocus, onInvalid, onKeyDown, onClick, ...inputProps } = props;
25
+ // The person's input design (the quick preferences) when this page and its form name none, for a labelled input.
26
+ const design = useInputDesign(ownDesign, Boolean(label));
24
27
  const preferences = useDatePreferences();
25
28
  const script = props.script ?? (usesDevanagari(preferences.calendar, preferences.script) ? "devanagari" : "latin");
26
29
  const seconds = normalizeTimeStep(step) % 60 !== 0;
@@ -1,7 +1,17 @@
1
1
  import { type CSSProperties, type ReactNode, type Ref } from "react";
2
- import { type TreeItem, type TreeValue, type TreeValueMode } from "../../Helpers/TreeStore.ts";
2
+ import { type TreeChangeRules, type TreeChildrenPage, type TreeChildrenRequest, type TreeItem, type TreeItemChange, type TreeValue, type TreeValueMode } from "../../Helpers/TreeStore.ts";
3
+ import type { TableRowAction } from "../../Interfaces/TableInterfaces.ts";
3
4
  import type { Size } from "../../Interfaces/TypeInterfaces.ts";
4
5
  export type TreeAction = "create" | "update" | "delete";
6
+ /**
7
+ * An action of the page's own on one item: an icon button on its row when `inline` (shown under the pointer or with
8
+ * focus, always on a touch screen), and an entry of the row's context menu either way. The row is busy while a
9
+ * promise `onSelect` returns runs.
10
+ */
11
+ export interface TreeRowAction<TItem extends TreeItem = TreeItem> extends TableRowAction<TItem> {
12
+ /** The key that runs it on the focused row, as Insert adds, F2 renames and Delete deletes in a tree that edits its own items. */
13
+ shortcut?: "Insert" | "F2" | "Delete";
14
+ }
5
15
  export interface TreeCreateRequest<TItem extends TreeItem = TreeItem> {
6
16
  /** The item the new one goes under, or `null` at the top level. */
7
17
  parent: TItem | null;
@@ -31,7 +41,10 @@ export interface TreeViewHandle<TItem extends TreeItem = TreeItem> {
31
41
  /** Expands an item and its parents. */
32
42
  expand: (value: TreeValue) => void;
33
43
  collapse: (value: TreeValue) => void;
34
- /** Expands the parents of an item, scrolls to it, and focuses it unless `focus` is false. */
44
+ /**
45
+ * Expands the parents of an item, scrolls to it, and focuses it unless `focus` is false. An item not loaded yet is
46
+ * revealed when the page that brings it comes (opened by `expand`, or Load more), unless the user moves on first.
47
+ */
35
48
  reveal: (value: TreeValue, focus?: boolean) => void;
36
49
  getValue: () => TreeValue[];
37
50
  /** Checks exactly these values, locked items included. For a tree without `value`. */
@@ -40,6 +53,8 @@ export interface TreeViewHandle<TItem extends TreeItem = TreeItem> {
40
53
  checkAll: (checked: boolean) => void;
41
54
  /** Every item in tree order, with the changes made in the tree. */
42
55
  getItems: () => TItem[];
56
+ /** The item of a value, as the tree holds it now; `undefined` when it is not loaded. */
57
+ getItem: (value: TreeValue) => TItem | undefined;
43
58
  /** Opens the editor for a new item under `parentValue`, or at the top level for `null`. */
44
59
  startCreate: (parentValue: TreeValue | null) => void;
45
60
  startRename: (value: TreeValue) => void;
@@ -47,13 +62,52 @@ export interface TreeViewHandle<TItem extends TreeItem = TreeItem> {
47
62
  remove: (value: TreeValue) => Promise<boolean>;
48
63
  /** Focuses the focused row, or the first. */
49
64
  focus: () => void;
65
+ /**
66
+ * With `loadChildren`: drops the pages kept for the whole tree, or for one item and everything under it, and loads
67
+ * again only what is on screen - the top level and the open items with rows in view. An open item out of view loads
68
+ * when it scrolls in, a closed one when it is next expanded. What is drawn stays until the fresh pages replace it.
69
+ */
70
+ refresh: (value?: TreeValue) => void;
71
+ /**
72
+ * Writes changes made elsewhere into this tree, as `writeTreeChanges` does into every tree with a `cacheKey` (which
73
+ * calls this): items placed, moved and taken out, the parents' counts and chevrons, and focus kept on its row, or on the
74
+ * row in its place when the item left. `rules` gives `compare`, the order of siblings.
75
+ */
76
+ apply: (changes: readonly TreeItemChange<TItem>[], rules?: TreeChangeRules<TItem>) => void;
50
77
  }
51
78
  export interface TreeViewProps<TItem extends TreeItem = TreeItem> {
52
79
  /**
53
80
  * The items, flat: each names its parent through `parentKey`, and siblings keep this order. Keep the array stable
54
- * (state, a constant, or `useMemo`): a different array, or one with different items, builds the tree again.
81
+ * (state, a constant, or `useMemo`): a different array, or one with different items, builds the tree again. With
82
+ * `loadChildren`, leave it out to load the top level too, or give the top level and let the children load.
83
+ */
84
+ items?: readonly TItem[];
85
+ /**
86
+ * Loads children from a server, a page at a time: when an item is expanded the first time, when Load more is
87
+ * pressed, and for the top level when no `items` are given. It answers `{ items, total?, hasMore? }`, at once or in
88
+ * a promise; the children go under the item asked for, whatever their own parent field says. Values must be unique
89
+ * across the whole tree: map items whose ids could repeat between levels (`"c" + countryId`, `"r" + regionId`).
90
+ * A thrown error or rejected promise shows "Could not load the items." with Retry.
91
+ */
92
+ loadChildren?: (request: TreeChildrenRequest<TItem>) => TreeChildrenPage<TItem> | PromiseLike<TreeChildrenPage<TItem>>;
93
+ /** With `loadChildren`: children asked for at a time (the request's `take`). Default 50. */
94
+ childPageSize?: number;
95
+ /**
96
+ * With `loadChildren`: the item field saying whether it has children, before they are loaded - a boolean or a count,
97
+ * such as `childCount`. An item without it shows a chevron until its first page answers, and loses it if the page
98
+ * is empty. With `checkable` and `cascade`, an item known to have none can be checked before it is opened.
99
+ */
100
+ hasChildrenKey?: string;
101
+ /**
102
+ * With `loadChildren`: keeps the pages loaded in a cache shared by every tree on the page with the same key, for
103
+ * `cacheLifetime`: leaving the page and coming back, or a second tree, makes no call, and a request on its way is
104
+ * shared. Name the source, e.g. `"administrative-regions"`. Without it, pages are kept only in this tree.
55
105
  */
56
- items: readonly TItem[];
106
+ cacheKey?: string;
107
+ /** How long a kept page is used, in milliseconds. Default 5 minutes. */
108
+ cacheLifetime?: number;
109
+ /** What a click on an item whose items are not all loaded says, with `checkable` and `cascade`. */
110
+ partialMessage?: string;
57
111
  /** The item field that holds its value. Default `id`. */
58
112
  valueKey?: string;
59
113
  /** The item field that holds its parent's value; empty for a top-level item. Default `parentId`. */
@@ -96,7 +150,10 @@ export interface TreeViewProps<TItem extends TreeItem = TreeItem> {
96
150
  form?: string;
97
151
  /** With `checkable` and `cascade`: a parent shows how many of its items are checked, as "3/5". Default true. */
98
152
  counts?: boolean;
99
- /** What is expanded at the start: `"all"`, a number of levels, or the values of items to open. */
153
+ /**
154
+ * What is expanded at the start: `"all"`, a number of levels, or the values of items to open. With `loadChildren`,
155
+ * only items whose children are given in `items`: nothing is asked for at the start but the top level.
156
+ */
100
157
  defaultExpanded?: "all" | number | readonly TreeValue[];
101
158
  /** Items can be added: a + on each row adds under it, and Add in the toolbar adds at the top level. */
102
159
  creatable?: boolean;
@@ -115,10 +172,38 @@ export interface TreeViewProps<TItem extends TreeItem = TreeItem> {
115
172
  onUpdate?: (request: TreeUpdateRequest<TItem>) => TItem | void | Promise<TItem | void>;
116
173
  /** Deletes an item and everything under it. A thrown error keeps the items and shows the message. */
117
174
  onDelete?: (request: TreeDeleteRequest<TItem>) => void | Promise<void>;
118
- /** After an item is added, renamed, or deleted: every item in tree order. Passing this array back as `items` does not rebuild the tree. */
175
+ /**
176
+ * After an item is added, renamed, or deleted: every item in tree order. Passing this array back as `items` does not
177
+ * rebuild the tree. With `loadChildren` it holds the loaded children too, whose own parent fields may not name the
178
+ * item they were loaded under: read it, but keep passing the `items` you gave.
179
+ */
119
180
  onItemsChange?: (items: TItem[]) => void;
120
181
  /** Asks before deleting. Default true; needs `<PopupHost />` on the page. */
121
182
  confirmDelete?: boolean;
183
+ /**
184
+ * Actions of the page's own on each item - Add under it, Edit, Move to trash - for a tree whose items are records
185
+ * changed through forms rather than renamed in the row: icon buttons on the row for the `inline` ones, all of them in
186
+ * the row's context menu, and the key each names. Not offered on locked items, nor in a read-only or disabled tree.
187
+ */
188
+ rowActions?: (item: TItem) => readonly TreeRowAction<TItem>[];
189
+ /**
190
+ * A button of the page's own at the end of the toolbar, such as Add New for a form. Its `description` is its tooltip
191
+ * and what a screen reader hears after its name. `disabled` with a `description` says why it cannot be pressed yet: it
192
+ * stays in the Tab order, looks unavailable, and a press - a click, a tap, Enter - shows the description in a note under
193
+ * it rather than doing nothing.
194
+ */
195
+ add?: {
196
+ label: ReactNode;
197
+ onClick: () => void;
198
+ disabled?: boolean;
199
+ description?: string;
200
+ };
201
+ /**
202
+ * The row shown as selected: the item the page picked - through `onItemClick`, say - marked `aria-selected` with a tint
203
+ * that stays when focus moves on. The page decides it: moving focus, a chevron, and opening or closing a row leave it
204
+ * where it is. Not on a `checkable` tree, whose rows are checked instead.
205
+ */
206
+ selectedValue?: TreeValue | null;
122
207
  /** The longest name the editor takes. Default 100. */
123
208
  maxLabelLength?: number;
124
209
  /** A click on a row without a checkbox, or Enter on it. Without it, a click expands or collapses a parent. */
@@ -133,6 +218,12 @@ export interface TreeViewProps<TItem extends TreeItem = TreeItem> {
133
218
  height?: number | string;
134
219
  /** The tallest the rows' area grows before it scrolls. Default 420. */
135
220
  maxHeight?: number | string;
221
+ /**
222
+ * Takes the height it is given, as a data table's `fill` does: the toolbar stays on top and the rows scroll inside
223
+ * under it, so the page around it never has to. `height` and `maxHeight` are ignored while it is on. Give it a cell
224
+ * that has a height: a side of an `AdminSplit` on an `AdminPage` with `fill` (nexus-admin), or a parent of your own.
225
+ */
226
+ fill?: boolean;
136
227
  /** Can be browsed, expanded, and focused, but not changed. A lock follows the label, and a try shows a note. */
137
228
  readOnly?: boolean;
138
229
  /** What a read-only tree says when someone tries to change it. Default "Read-only: this tree cannot be changed." */
@@ -154,7 +245,17 @@ export interface TreeViewProps<TItem extends TreeItem = TreeItem> {
154
245
  * Keys: arrows move and expand, Home and End jump, letters find a row, Space checks, Enter opens, `*` expands the
155
246
  * siblings, F2 renames, Delete deletes, Insert adds under the focused row, and Shift+F10 opens the actions menu.
156
247
  *
248
+ * With `loadChildren` the children come from a server, a page at a time, when an item is first expanded: a loading
249
+ * row while they come, a row that says the page failed with Retry, and Load more with how many are left. Those rows
250
+ * are rows like the others, reached with the arrows and pressed with Enter or Space. What is loaded stays (collapse
251
+ * and expand again asks nothing), `cacheKey` shares it with the next tree, and the handle's `refresh` loads again what
252
+ * is on screen. With `cascade`, an item whose items are not all loaded cannot be checked as a whole: the value can only
253
+ * hold items that were loaded, so its check would silently leave the rest out.
254
+ *
157
255
  * @example
158
256
  * <TreeView label="Permissions" items={permissions} checkable name="actionIds" defaultExpanded={1} isItemDisabled={item => !item.canAssign} />
257
+ *
258
+ * <TreeView label="Regions" items={countries} hasChildrenKey="childCount" cacheKey="regions"
259
+ * loadChildren={({ parent, skip, take, signal }) => loadRegions(parent, skip, take, signal)} />
159
260
  */
160
261
  export declare function TreeView<TItem extends TreeItem = TreeItem>(props: TreeViewProps<TItem>): import("react").JSX.Element;