@multiplatform.one/frappe-ui 7.7.6 → 7.10.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 (538) hide show
  1. package/dist/cjs/ChartCard.native.js.map +1 -1
  2. package/dist/cjs/FileBrowser/AttachLibrary.native.js.map +1 -1
  3. package/dist/cjs/FileBrowser/folderTree.native.js.map +1 -1
  4. package/dist/cjs/FileBrowser/index.native.js.map +1 -1
  5. package/dist/cjs/FileBrowser/types.native.js.map +1 -1
  6. package/dist/cjs/FileBrowser/viewPersistence.native.js.map +1 -1
  7. package/dist/cjs/FormSidebar.cjs +7 -7
  8. package/dist/cjs/FormSidebar.native.js +7 -7
  9. package/dist/cjs/FormSidebar.native.js.map +1 -1
  10. package/dist/cjs/FrappeAssignment.native.js.map +1 -1
  11. package/dist/cjs/FrappeCalendar.cjs +20 -17
  12. package/dist/cjs/FrappeCalendar.native.js +22 -21
  13. package/dist/cjs/FrappeCalendar.native.js.map +1 -1
  14. package/dist/cjs/FrappeChartCard.cjs +29 -3
  15. package/dist/cjs/FrappeChartCard.native.js +29 -3
  16. package/dist/cjs/FrappeChartCard.native.js.map +1 -1
  17. package/dist/cjs/FrappeConnectionIndicator.native.js.map +1 -1
  18. package/dist/cjs/FrappeDashboard.native.js.map +1 -1
  19. package/dist/cjs/FrappeForm.cjs +1 -1
  20. package/dist/cjs/FrappeForm.native.js +2 -2
  21. package/dist/cjs/FrappeForm.native.js.map +1 -1
  22. package/dist/cjs/FrappeGantt.cjs +25 -34
  23. package/dist/cjs/FrappeGantt.native.js +27 -38
  24. package/dist/cjs/FrappeGantt.native.js.map +1 -1
  25. package/dist/cjs/FrappeImageView.cjs +4 -2
  26. package/dist/cjs/FrappeImageView.native.js +8 -4
  27. package/dist/cjs/FrappeImageView.native.js.map +1 -1
  28. package/dist/cjs/FrappeKPICard.cjs +29 -3
  29. package/dist/cjs/FrappeKPICard.native.js +29 -3
  30. package/dist/cjs/FrappeKPICard.native.js.map +1 -1
  31. package/dist/cjs/FrappeKanban.cjs +16 -17
  32. package/dist/cjs/FrappeKanban.native.js +18 -21
  33. package/dist/cjs/FrappeKanban.native.js.map +1 -1
  34. package/dist/cjs/FrappeLikedBy.cjs +1 -1
  35. package/dist/cjs/FrappeLikedBy.native.js +1 -1
  36. package/dist/cjs/FrappeLikedBy.native.js.map +1 -1
  37. package/dist/cjs/FrappeList.cjs +2 -2
  38. package/dist/cjs/FrappeList.native.js +2 -2
  39. package/dist/cjs/FrappeList.native.js.map +1 -1
  40. package/dist/cjs/FrappeListView.cjs +6 -6
  41. package/dist/cjs/FrappeListView.native.js +6 -6
  42. package/dist/cjs/FrappeListView.native.js.map +1 -1
  43. package/dist/cjs/FrappeProvider.native.js.map +1 -1
  44. package/dist/cjs/FrappeReconnectIndicator.native.js.map +1 -1
  45. package/dist/cjs/FrappeReportBuilder.cjs +2 -2
  46. package/dist/cjs/FrappeReportBuilder.native.js +2 -2
  47. package/dist/cjs/FrappeReportBuilder.native.js.map +1 -1
  48. package/dist/cjs/FrappeReportView.native.js +3 -3
  49. package/dist/cjs/FrappeReportView.native.js.map +1 -1
  50. package/dist/cjs/FrappeTable.cjs +35 -38
  51. package/dist/cjs/FrappeTable.native.js +38 -39
  52. package/dist/cjs/FrappeTable.native.js.map +1 -1
  53. package/dist/cjs/FrappeTreeView.cjs +85 -50
  54. package/dist/cjs/FrappeTreeView.native.js +129 -50
  55. package/dist/cjs/FrappeTreeView.native.js.map +1 -1
  56. package/dist/cjs/SyncErrorNotice.native.js.map +1 -1
  57. package/dist/cjs/commentActions.cjs +1 -1
  58. package/dist/cjs/commentActions.native.js +1 -1
  59. package/dist/cjs/commentActions.native.js.map +1 -1
  60. package/dist/cjs/components/attachments.native.js.map +1 -1
  61. package/dist/cjs/components/tags.native.js.map +1 -1
  62. package/dist/cjs/components/timeline.cjs +1 -1
  63. package/dist/cjs/components/timeline.native.js +1 -1
  64. package/dist/cjs/components/timeline.native.js.map +1 -1
  65. package/dist/cjs/dependsOn.native.js.map +1 -1
  66. package/dist/cjs/desk/DeskFormPage.native.js.map +1 -1
  67. package/dist/cjs/desk/DeskFormSidebar.native.js.map +1 -1
  68. package/dist/cjs/desk/DeskListPage.native.js.map +1 -1
  69. package/dist/cjs/desk/DeskShell.cjs +2 -0
  70. package/dist/cjs/desk/DeskShell.native.js +2 -0
  71. package/dist/cjs/desk/DeskShell.native.js.map +1 -1
  72. package/dist/cjs/desk/DeskSidebar.native.js.map +1 -1
  73. package/dist/cjs/desk/awesomebar.cjs +1 -1
  74. package/dist/cjs/desk/awesomebar.native.js +1 -1
  75. package/dist/cjs/desk/awesomebar.native.js.map +1 -1
  76. package/dist/cjs/fieldOverrides.native.js.map +1 -1
  77. package/dist/cjs/fieldRegistry.native.js +31 -31
  78. package/dist/cjs/fieldRegistry.native.js.map +1 -1
  79. package/dist/cjs/fields/Barcode/index.native.js.map +1 -1
  80. package/dist/cjs/fields/Check/index.native.js.map +1 -1
  81. package/dist/cjs/fields/CodeEditor/index.native.js.map +1 -1
  82. package/dist/cjs/fields/Color/index.native.js.map +1 -1
  83. package/dist/cjs/fields/Data/index.native.js.map +1 -1
  84. package/dist/cjs/fields/Date/sheetKeyboard.native.js.map +1 -1
  85. package/dist/cjs/fields/Date/types.native.js.map +1 -1
  86. package/dist/cjs/fields/Date/wire.native.js.map +1 -1
  87. package/dist/cjs/fields/DateRange/index.cjs +30 -2
  88. package/dist/cjs/fields/DateRange/index.native.js +34 -2
  89. package/dist/cjs/fields/DateRange/index.native.js.map +1 -1
  90. package/dist/cjs/fields/Duration/index.native.js.map +1 -1
  91. package/dist/cjs/fields/DynamicLink.native.js.map +1 -1
  92. package/dist/cjs/fields/FileUpload.native.js.map +1 -1
  93. package/dist/cjs/fields/FileUploadField/index.native.js.map +1 -1
  94. package/dist/cjs/fields/Geolocation/index.native.js.map +1 -1
  95. package/dist/cjs/fields/HTML/index.native.js.map +1 -1
  96. package/dist/cjs/fields/Heading/index.native.js.map +1 -1
  97. package/dist/cjs/fields/Icon/index.native.js.map +1 -1
  98. package/dist/cjs/fields/Link.native.js.map +1 -1
  99. package/dist/cjs/fields/LinkTree.native.js.map +1 -1
  100. package/dist/cjs/fields/LongText/index.native.js.map +1 -1
  101. package/dist/cjs/fields/MentionInput/index.cjs +4 -1
  102. package/dist/cjs/fields/MentionInput/index.native.js +4 -1
  103. package/dist/cjs/fields/MentionInput/index.native.js.map +1 -1
  104. package/dist/cjs/fields/Numeric/index.native.js.map +1 -1
  105. package/dist/cjs/fields/OTPInput/index.native.js.map +1 -1
  106. package/dist/cjs/fields/Password/index.native.js.map +1 -1
  107. package/dist/cjs/fields/Phone/index.native.js.map +1 -1
  108. package/dist/cjs/fields/Progress/index.native.js.map +1 -1
  109. package/dist/cjs/fields/RadioGroup/index.native.js.map +1 -1
  110. package/dist/cjs/fields/Rating/index.native.js.map +1 -1
  111. package/dist/cjs/fields/ReadOnly/index.native.js.map +1 -1
  112. package/dist/cjs/fields/Select/index.native.js.map +1 -1
  113. package/dist/cjs/fields/Signature/index.native.js.map +1 -1
  114. package/dist/cjs/fields/Slider/index.native.js.map +1 -1
  115. package/dist/cjs/fields/SmallText/index.native.js.map +1 -1
  116. package/dist/cjs/fields/Switch/index.native.js.map +1 -1
  117. package/dist/cjs/fields/TableMultiSelect.native.js.map +1 -1
  118. package/dist/cjs/fields/TextEditor/types.native.js.map +1 -1
  119. package/dist/cjs/fields/TimePicker/index.native.js.map +1 -1
  120. package/dist/cjs/fields/ToggleGroup/index.native.js.map +1 -1
  121. package/dist/cjs/fields/shared/EditorPreviewPanes.native.js.map +1 -1
  122. package/dist/cjs/filterFields.native.js.map +1 -1
  123. package/dist/cjs/formEngine/createPrefill.native.js.map +1 -1
  124. package/dist/cjs/formEngine/dirtyTracking.native.js.map +1 -1
  125. package/dist/cjs/formEngine/doctypeMeta.native.js.map +1 -1
  126. package/dist/cjs/formEngine/fetchFrom.native.js.map +1 -1
  127. package/dist/cjs/formEngine/fieldPermissions.native.js.map +1 -1
  128. package/dist/cjs/formEngine/formActions.native.js.map +1 -1
  129. package/dist/cjs/formEngine/formLayout.native.js.map +1 -1
  130. package/dist/cjs/formEngine/index.native.js.map +1 -1
  131. package/dist/cjs/formEngine/useFormEngine.native.js.map +1 -1
  132. package/dist/cjs/frappeEventColor.native.js.map +1 -1
  133. package/dist/cjs/frappeStoryTarget.native.js.map +1 -1
  134. package/dist/cjs/frappeUsers.native.js.map +1 -1
  135. package/dist/cjs/index.cjs +4 -0
  136. package/dist/cjs/index.native.js +38 -34
  137. package/dist/cjs/index.native.js.map +1 -1
  138. package/dist/cjs/liveErrors.native.js.map +1 -1
  139. package/dist/cjs/resolveControl.native.js.map +1 -1
  140. package/dist/cjs/schemaForm/SchemaWizard.native.js.map +1 -1
  141. package/dist/cjs/schemaForm/applyFieldOrder.native.js.map +1 -1
  142. package/dist/cjs/schemaForm/index.cjs +10 -9
  143. package/dist/cjs/schemaForm/index.native.js +11 -10
  144. package/dist/cjs/schemaForm/index.native.js.map +1 -1
  145. package/dist/cjs/shared/devWarn.cjs +40 -0
  146. package/dist/cjs/shared/devWarn.native.js +45 -0
  147. package/dist/cjs/shared/devWarn.native.js.map +1 -0
  148. package/dist/cjs/shared/useKeyboardInset.native.js.map +1 -1
  149. package/dist/cjs/syncError.native.js.map +1 -1
  150. package/dist/cjs/useFrappeAggregate.cjs +15 -8
  151. package/dist/cjs/useFrappeAggregate.native.js +15 -9
  152. package/dist/cjs/useFrappeAggregate.native.js.map +1 -1
  153. package/dist/cjs/useFrappeFacets.cjs +10 -9
  154. package/dist/cjs/useFrappeFacets.native.js +10 -10
  155. package/dist/cjs/useFrappeFacets.native.js.map +1 -1
  156. package/dist/cjs/useFrappePagination.native.js.map +1 -1
  157. package/dist/cjs/useFrappeRows.cjs +113 -0
  158. package/dist/cjs/useFrappeRows.native.js +129 -0
  159. package/dist/cjs/useFrappeRows.native.js.map +1 -0
  160. package/dist/esm/ChartCard.native.js.map +1 -1
  161. package/dist/esm/FileBrowser/AttachLibrary.native.js.map +1 -1
  162. package/dist/esm/FileBrowser/folderTree.native.js.map +1 -1
  163. package/dist/esm/FileBrowser/index.native.js.map +1 -1
  164. package/dist/esm/FileBrowser/types.native.js.map +1 -1
  165. package/dist/esm/FileBrowser/viewPersistence.native.js.map +1 -1
  166. package/dist/esm/FormSidebar.mjs +7 -7
  167. package/dist/esm/FormSidebar.mjs.map +1 -1
  168. package/dist/esm/FormSidebar.native.js +7 -7
  169. package/dist/esm/FormSidebar.native.js.map +1 -1
  170. package/dist/esm/FrappeAssignment.native.js.map +1 -1
  171. package/dist/esm/FrappeCalendar.mjs +20 -17
  172. package/dist/esm/FrappeCalendar.mjs.map +1 -1
  173. package/dist/esm/FrappeCalendar.native.js +22 -21
  174. package/dist/esm/FrappeCalendar.native.js.map +1 -1
  175. package/dist/esm/FrappeChartCard.mjs +30 -4
  176. package/dist/esm/FrappeChartCard.mjs.map +1 -1
  177. package/dist/esm/FrappeChartCard.native.js +30 -4
  178. package/dist/esm/FrappeChartCard.native.js.map +1 -1
  179. package/dist/esm/FrappeConnectionIndicator.native.js.map +1 -1
  180. package/dist/esm/FrappeDashboard.native.js.map +1 -1
  181. package/dist/esm/FrappeForm.mjs +1 -1
  182. package/dist/esm/FrappeForm.mjs.map +1 -1
  183. package/dist/esm/FrappeForm.native.js +1 -1
  184. package/dist/esm/FrappeForm.native.js.map +1 -1
  185. package/dist/esm/FrappeGantt.mjs +27 -36
  186. package/dist/esm/FrappeGantt.mjs.map +1 -1
  187. package/dist/esm/FrappeGantt.native.js +29 -40
  188. package/dist/esm/FrappeGantt.native.js.map +1 -1
  189. package/dist/esm/FrappeImageView.mjs +5 -3
  190. package/dist/esm/FrappeImageView.mjs.map +1 -1
  191. package/dist/esm/FrappeImageView.native.js +9 -5
  192. package/dist/esm/FrappeImageView.native.js.map +1 -1
  193. package/dist/esm/FrappeKPICard.mjs +30 -4
  194. package/dist/esm/FrappeKPICard.mjs.map +1 -1
  195. package/dist/esm/FrappeKPICard.native.js +30 -4
  196. package/dist/esm/FrappeKPICard.native.js.map +1 -1
  197. package/dist/esm/FrappeKanban.mjs +16 -17
  198. package/dist/esm/FrappeKanban.mjs.map +1 -1
  199. package/dist/esm/FrappeKanban.native.js +18 -21
  200. package/dist/esm/FrappeKanban.native.js.map +1 -1
  201. package/dist/esm/FrappeLikedBy.mjs +1 -1
  202. package/dist/esm/FrappeLikedBy.mjs.map +1 -1
  203. package/dist/esm/FrappeLikedBy.native.js +1 -1
  204. package/dist/esm/FrappeLikedBy.native.js.map +1 -1
  205. package/dist/esm/FrappeList.mjs +2 -2
  206. package/dist/esm/FrappeList.mjs.map +1 -1
  207. package/dist/esm/FrappeList.native.js +2 -2
  208. package/dist/esm/FrappeList.native.js.map +1 -1
  209. package/dist/esm/FrappeListView.mjs +6 -6
  210. package/dist/esm/FrappeListView.mjs.map +1 -1
  211. package/dist/esm/FrappeListView.native.js +6 -6
  212. package/dist/esm/FrappeListView.native.js.map +1 -1
  213. package/dist/esm/FrappeProvider.mjs.map +1 -1
  214. package/dist/esm/FrappeProvider.native.js.map +1 -1
  215. package/dist/esm/FrappeReconnectIndicator.native.js.map +1 -1
  216. package/dist/esm/FrappeReportBuilder.mjs +2 -2
  217. package/dist/esm/FrappeReportBuilder.mjs.map +1 -1
  218. package/dist/esm/FrappeReportBuilder.native.js +2 -2
  219. package/dist/esm/FrappeReportBuilder.native.js.map +1 -1
  220. package/dist/esm/FrappeReportView.native.js.map +1 -1
  221. package/dist/esm/FrappeTable.mjs +36 -39
  222. package/dist/esm/FrappeTable.mjs.map +1 -1
  223. package/dist/esm/FrappeTable.native.js +39 -40
  224. package/dist/esm/FrappeTable.native.js.map +1 -1
  225. package/dist/esm/FrappeTreeView.mjs +89 -55
  226. package/dist/esm/FrappeTreeView.mjs.map +1 -1
  227. package/dist/esm/FrappeTreeView.native.js +133 -55
  228. package/dist/esm/FrappeTreeView.native.js.map +1 -1
  229. package/dist/esm/SyncErrorNotice.native.js.map +1 -1
  230. package/dist/esm/commentActions.mjs +1 -1
  231. package/dist/esm/commentActions.mjs.map +1 -1
  232. package/dist/esm/commentActions.native.js +1 -1
  233. package/dist/esm/commentActions.native.js.map +1 -1
  234. package/dist/esm/components/attachments.native.js.map +1 -1
  235. package/dist/esm/components/tags.native.js.map +1 -1
  236. package/dist/esm/components/timeline.mjs +1 -1
  237. package/dist/esm/components/timeline.mjs.map +1 -1
  238. package/dist/esm/components/timeline.native.js +1 -1
  239. package/dist/esm/components/timeline.native.js.map +1 -1
  240. package/dist/esm/dependsOn.native.js.map +1 -1
  241. package/dist/esm/desk/DeskFormPage.native.js.map +1 -1
  242. package/dist/esm/desk/DeskFormSidebar.native.js.map +1 -1
  243. package/dist/esm/desk/DeskListPage.native.js.map +1 -1
  244. package/dist/esm/desk/DeskShell.mjs +2 -0
  245. package/dist/esm/desk/DeskShell.mjs.map +1 -1
  246. package/dist/esm/desk/DeskShell.native.js +2 -0
  247. package/dist/esm/desk/DeskShell.native.js.map +1 -1
  248. package/dist/esm/desk/DeskSidebar.native.js.map +1 -1
  249. package/dist/esm/desk/awesomebar.mjs +1 -1
  250. package/dist/esm/desk/awesomebar.mjs.map +1 -1
  251. package/dist/esm/desk/awesomebar.native.js +1 -1
  252. package/dist/esm/desk/awesomebar.native.js.map +1 -1
  253. package/dist/esm/fieldOverrides.native.js.map +1 -1
  254. package/dist/esm/fieldRegistry.native.js.map +1 -1
  255. package/dist/esm/fields/Barcode/index.native.js.map +1 -1
  256. package/dist/esm/fields/Check/index.native.js.map +1 -1
  257. package/dist/esm/fields/CodeEditor/index.native.js.map +1 -1
  258. package/dist/esm/fields/Color/index.native.js.map +1 -1
  259. package/dist/esm/fields/Data/index.native.js.map +1 -1
  260. package/dist/esm/fields/Date/sheetKeyboard.native.js.map +1 -1
  261. package/dist/esm/fields/Date/types.native.js.map +1 -1
  262. package/dist/esm/fields/Date/wire.native.js.map +1 -1
  263. package/dist/esm/fields/DateRange/index.mjs +30 -2
  264. package/dist/esm/fields/DateRange/index.mjs.map +1 -1
  265. package/dist/esm/fields/DateRange/index.native.js +34 -2
  266. package/dist/esm/fields/DateRange/index.native.js.map +1 -1
  267. package/dist/esm/fields/Duration/index.native.js.map +1 -1
  268. package/dist/esm/fields/DynamicLink.native.js.map +1 -1
  269. package/dist/esm/fields/FileUpload.native.js.map +1 -1
  270. package/dist/esm/fields/FileUploadField/index.native.js.map +1 -1
  271. package/dist/esm/fields/Geolocation/index.native.js.map +1 -1
  272. package/dist/esm/fields/HTML/index.native.js.map +1 -1
  273. package/dist/esm/fields/Heading/index.native.js.map +1 -1
  274. package/dist/esm/fields/Icon/index.native.js.map +1 -1
  275. package/dist/esm/fields/Link.native.js.map +1 -1
  276. package/dist/esm/fields/LinkTree.native.js.map +1 -1
  277. package/dist/esm/fields/LongText/index.native.js.map +1 -1
  278. package/dist/esm/fields/MentionInput/index.mjs +4 -1
  279. package/dist/esm/fields/MentionInput/index.mjs.map +1 -1
  280. package/dist/esm/fields/MentionInput/index.native.js +4 -1
  281. package/dist/esm/fields/MentionInput/index.native.js.map +1 -1
  282. package/dist/esm/fields/Numeric/index.native.js.map +1 -1
  283. package/dist/esm/fields/OTPInput/index.native.js.map +1 -1
  284. package/dist/esm/fields/Password/index.native.js.map +1 -1
  285. package/dist/esm/fields/Phone/index.native.js.map +1 -1
  286. package/dist/esm/fields/Progress/index.native.js.map +1 -1
  287. package/dist/esm/fields/RadioGroup/index.native.js.map +1 -1
  288. package/dist/esm/fields/Rating/index.native.js.map +1 -1
  289. package/dist/esm/fields/ReadOnly/index.native.js.map +1 -1
  290. package/dist/esm/fields/Select/index.native.js.map +1 -1
  291. package/dist/esm/fields/Signature/index.native.js.map +1 -1
  292. package/dist/esm/fields/Slider/index.native.js.map +1 -1
  293. package/dist/esm/fields/SmallText/index.native.js.map +1 -1
  294. package/dist/esm/fields/Switch/index.native.js.map +1 -1
  295. package/dist/esm/fields/TableMultiSelect.native.js.map +1 -1
  296. package/dist/esm/fields/TextEditor/types.native.js.map +1 -1
  297. package/dist/esm/fields/TimePicker/index.native.js.map +1 -1
  298. package/dist/esm/fields/ToggleGroup/index.native.js.map +1 -1
  299. package/dist/esm/fields/shared/EditorPreviewPanes.native.js.map +1 -1
  300. package/dist/esm/filterFields.native.js.map +1 -1
  301. package/dist/esm/formEngine/createPrefill.native.js.map +1 -1
  302. package/dist/esm/formEngine/dirtyTracking.native.js.map +1 -1
  303. package/dist/esm/formEngine/doctypeMeta.native.js.map +1 -1
  304. package/dist/esm/formEngine/fetchFrom.native.js.map +1 -1
  305. package/dist/esm/formEngine/fieldPermissions.native.js.map +1 -1
  306. package/dist/esm/formEngine/formActions.native.js.map +1 -1
  307. package/dist/esm/formEngine/formLayout.native.js.map +1 -1
  308. package/dist/esm/formEngine/index.native.js.map +1 -1
  309. package/dist/esm/formEngine/useFormEngine.native.js.map +1 -1
  310. package/dist/esm/frappeEventColor.native.js.map +1 -1
  311. package/dist/esm/frappeStoryTarget.native.js.map +1 -1
  312. package/dist/esm/frappeUsers.native.js.map +1 -1
  313. package/dist/esm/index.mjs +2 -1
  314. package/dist/esm/index.mjs.map +1 -1
  315. package/dist/esm/index.native.js +2 -1
  316. package/dist/esm/index.native.js.map +1 -1
  317. package/dist/esm/liveErrors.native.js.map +1 -1
  318. package/dist/esm/resolveControl.native.js.map +1 -1
  319. package/dist/esm/schemaForm/SchemaWizard.native.js.map +1 -1
  320. package/dist/esm/schemaForm/applyFieldOrder.native.js.map +1 -1
  321. package/dist/esm/schemaForm/index.mjs +8 -7
  322. package/dist/esm/schemaForm/index.mjs.map +1 -1
  323. package/dist/esm/schemaForm/index.native.js +8 -7
  324. package/dist/esm/schemaForm/index.native.js.map +1 -1
  325. package/dist/esm/shared/devWarn.mjs +14 -0
  326. package/dist/esm/shared/devWarn.mjs.map +1 -0
  327. package/dist/esm/shared/devWarn.native.js +16 -0
  328. package/dist/esm/shared/devWarn.native.js.map +1 -0
  329. package/dist/esm/shared/useKeyboardInset.native.js.map +1 -1
  330. package/dist/esm/syncError.native.js.map +1 -1
  331. package/dist/esm/useFrappeAggregate.mjs +15 -8
  332. package/dist/esm/useFrappeAggregate.mjs.map +1 -1
  333. package/dist/esm/useFrappeAggregate.native.js +15 -9
  334. package/dist/esm/useFrappeAggregate.native.js.map +1 -1
  335. package/dist/esm/useFrappeFacets.mjs +10 -9
  336. package/dist/esm/useFrappeFacets.mjs.map +1 -1
  337. package/dist/esm/useFrappeFacets.native.js +10 -10
  338. package/dist/esm/useFrappeFacets.native.js.map +1 -1
  339. package/dist/esm/useFrappePagination.native.js.map +1 -1
  340. package/dist/esm/useFrappeRows.mjs +86 -0
  341. package/dist/esm/useFrappeRows.mjs.map +1 -0
  342. package/dist/esm/useFrappeRows.native.js +99 -0
  343. package/dist/esm/useFrappeRows.native.js.map +1 -0
  344. package/dist/jsx/FormSidebar.mjs +7 -7
  345. package/dist/jsx/FormSidebar.mjs.map +1 -1
  346. package/dist/jsx/FormSidebar.native.js +7 -7
  347. package/dist/jsx/FormSidebar.native.js.map +1 -1
  348. package/dist/jsx/FrappeCalendar.mjs +20 -17
  349. package/dist/jsx/FrappeCalendar.mjs.map +1 -1
  350. package/dist/jsx/FrappeCalendar.native.js +22 -21
  351. package/dist/jsx/FrappeCalendar.native.js.map +1 -1
  352. package/dist/jsx/FrappeChartCard.mjs +30 -4
  353. package/dist/jsx/FrappeChartCard.mjs.map +1 -1
  354. package/dist/jsx/FrappeChartCard.native.js +29 -3
  355. package/dist/jsx/FrappeChartCard.native.js.map +1 -1
  356. package/dist/jsx/FrappeForm.mjs +1 -1
  357. package/dist/jsx/FrappeForm.mjs.map +1 -1
  358. package/dist/jsx/FrappeForm.native.js +1 -1
  359. package/dist/jsx/FrappeForm.native.js.map +1 -1
  360. package/dist/jsx/FrappeGantt.mjs +27 -36
  361. package/dist/jsx/FrappeGantt.mjs.map +1 -1
  362. package/dist/jsx/FrappeGantt.native.js +27 -38
  363. package/dist/jsx/FrappeGantt.native.js.map +1 -1
  364. package/dist/jsx/FrappeImageView.mjs +5 -3
  365. package/dist/jsx/FrappeImageView.mjs.map +1 -1
  366. package/dist/jsx/FrappeImageView.native.js +8 -4
  367. package/dist/jsx/FrappeImageView.native.js.map +1 -1
  368. package/dist/jsx/FrappeKPICard.mjs +30 -4
  369. package/dist/jsx/FrappeKPICard.mjs.map +1 -1
  370. package/dist/jsx/FrappeKPICard.native.js +29 -3
  371. package/dist/jsx/FrappeKPICard.native.js.map +1 -1
  372. package/dist/jsx/FrappeKanban.mjs +16 -17
  373. package/dist/jsx/FrappeKanban.mjs.map +1 -1
  374. package/dist/jsx/FrappeKanban.native.js +18 -21
  375. package/dist/jsx/FrappeKanban.native.js.map +1 -1
  376. package/dist/jsx/FrappeLikedBy.mjs +1 -1
  377. package/dist/jsx/FrappeLikedBy.mjs.map +1 -1
  378. package/dist/jsx/FrappeLikedBy.native.js +1 -1
  379. package/dist/jsx/FrappeLikedBy.native.js.map +1 -1
  380. package/dist/jsx/FrappeList.mjs +2 -2
  381. package/dist/jsx/FrappeList.mjs.map +1 -1
  382. package/dist/jsx/FrappeList.native.js +2 -2
  383. package/dist/jsx/FrappeList.native.js.map +1 -1
  384. package/dist/jsx/FrappeListView.mjs +6 -6
  385. package/dist/jsx/FrappeListView.mjs.map +1 -1
  386. package/dist/jsx/FrappeListView.native.js +6 -6
  387. package/dist/jsx/FrappeListView.native.js.map +1 -1
  388. package/dist/jsx/FrappeProvider.mjs.map +1 -1
  389. package/dist/jsx/FrappeProvider.native.js.map +1 -1
  390. package/dist/jsx/FrappeReportBuilder.mjs +2 -2
  391. package/dist/jsx/FrappeReportBuilder.mjs.map +1 -1
  392. package/dist/jsx/FrappeReportBuilder.native.js +2 -2
  393. package/dist/jsx/FrappeReportBuilder.native.js.map +1 -1
  394. package/dist/jsx/FrappeTable.mjs +36 -39
  395. package/dist/jsx/FrappeTable.mjs.map +1 -1
  396. package/dist/jsx/FrappeTable.native.js +38 -39
  397. package/dist/jsx/FrappeTable.native.js.map +1 -1
  398. package/dist/jsx/FrappeTreeView.mjs +89 -55
  399. package/dist/jsx/FrappeTreeView.mjs.map +1 -1
  400. package/dist/jsx/FrappeTreeView.native.js +129 -50
  401. package/dist/jsx/FrappeTreeView.native.js.map +1 -1
  402. package/dist/jsx/commentActions.mjs +1 -1
  403. package/dist/jsx/commentActions.mjs.map +1 -1
  404. package/dist/jsx/commentActions.native.js +1 -1
  405. package/dist/jsx/commentActions.native.js.map +1 -1
  406. package/dist/jsx/components/timeline.mjs +1 -1
  407. package/dist/jsx/components/timeline.mjs.map +1 -1
  408. package/dist/jsx/components/timeline.native.js +1 -1
  409. package/dist/jsx/desk/DeskShell.mjs +2 -0
  410. package/dist/jsx/desk/DeskShell.mjs.map +1 -1
  411. package/dist/jsx/desk/DeskShell.native.js +2 -0
  412. package/dist/jsx/desk/DeskShell.native.js.map +1 -1
  413. package/dist/jsx/desk/awesomebar.mjs +1 -1
  414. package/dist/jsx/desk/awesomebar.mjs.map +1 -1
  415. package/dist/jsx/desk/awesomebar.native.js +1 -1
  416. package/dist/jsx/desk/awesomebar.native.js.map +1 -1
  417. package/dist/jsx/fields/DateRange/index.mjs +30 -2
  418. package/dist/jsx/fields/DateRange/index.mjs.map +1 -1
  419. package/dist/jsx/fields/DateRange/index.native.js +34 -2
  420. package/dist/jsx/fields/DateRange/index.native.js.map +1 -1
  421. package/dist/jsx/fields/MentionInput/index.mjs +4 -1
  422. package/dist/jsx/fields/MentionInput/index.mjs.map +1 -1
  423. package/dist/jsx/fields/MentionInput/index.native.js +4 -1
  424. package/dist/jsx/fields/MentionInput/index.native.js.map +1 -1
  425. package/dist/jsx/index.js +2 -1
  426. package/dist/jsx/index.js.map +1 -1
  427. package/dist/jsx/index.mjs +2 -1
  428. package/dist/jsx/index.mjs.map +1 -1
  429. package/dist/jsx/index.native.js +4 -0
  430. package/dist/jsx/index.native.js.map +1 -1
  431. package/dist/jsx/schemaForm/index.mjs +8 -7
  432. package/dist/jsx/schemaForm/index.mjs.map +1 -1
  433. package/dist/jsx/schemaForm/index.native.js +10 -9
  434. package/dist/jsx/schemaForm/index.native.js.map +1 -1
  435. package/dist/jsx/shared/devWarn.mjs +14 -0
  436. package/dist/jsx/shared/devWarn.mjs.map +1 -0
  437. package/dist/jsx/shared/devWarn.native.js +45 -0
  438. package/dist/jsx/shared/devWarn.native.js.map +1 -0
  439. package/dist/jsx/useFrappeAggregate.mjs +15 -8
  440. package/dist/jsx/useFrappeAggregate.mjs.map +1 -1
  441. package/dist/jsx/useFrappeAggregate.native.js +15 -9
  442. package/dist/jsx/useFrappeAggregate.native.js.map +1 -1
  443. package/dist/jsx/useFrappeFacets.mjs +10 -9
  444. package/dist/jsx/useFrappeFacets.mjs.map +1 -1
  445. package/dist/jsx/useFrappeFacets.native.js +10 -10
  446. package/dist/jsx/useFrappeFacets.native.js.map +1 -1
  447. package/dist/jsx/useFrappeRows.mjs +86 -0
  448. package/dist/jsx/useFrappeRows.mjs.map +1 -0
  449. package/dist/jsx/useFrappeRows.native.js +129 -0
  450. package/dist/jsx/useFrappeRows.native.js.map +1 -0
  451. package/package.json +17 -16
  452. package/src/FileBrowser/FileBrowser.spec.tsx +11 -1
  453. package/src/FormSidebar.tsx +7 -7
  454. package/src/FrappeCalendar.tsx +25 -22
  455. package/src/FrappeChartCard.spec.tsx +179 -0
  456. package/src/FrappeChartCard.tsx +55 -6
  457. package/src/FrappeForm.tsx +7 -3
  458. package/src/FrappeGantt.tsx +29 -39
  459. package/src/FrappeImageView.tsx +5 -3
  460. package/src/FrappeKPICard.spec.tsx +153 -0
  461. package/src/FrappeKPICard.tsx +52 -6
  462. package/src/FrappeKanban.tsx +24 -17
  463. package/src/FrappeLikedBy.tsx +1 -1
  464. package/src/FrappeList.tsx +3 -2
  465. package/src/FrappeListView.tsx +6 -6
  466. package/src/FrappeProvider.fixturesOnly.spec.tsx +129 -0
  467. package/src/FrappeProvider.tsx +16 -6
  468. package/src/FrappeReportBuilder.tsx +4 -2
  469. package/src/FrappeTable.autoHeight.spec.tsx +142 -0
  470. package/src/FrappeTable.rowAccumulator.spec.tsx +110 -0
  471. package/src/FrappeTable.tsx +75 -48
  472. package/src/FrappeTreeView.stories.tsx +59 -0
  473. package/src/FrappeTreeView.tsx +166 -56
  474. package/src/commentActions.ts +1 -1
  475. package/src/components/timeline.tsx +1 -1
  476. package/src/desk/DeskShell.tsx +2 -0
  477. package/src/desk/awesomebar.tsx +5 -2
  478. package/src/fields/CodeEditor/CodeEditor.spec.tsx +10 -9
  479. package/src/fields/Date/Date.spec.tsx +8 -1
  480. package/src/fields/Date/nativePresentation.spec.tsx +8 -1
  481. package/src/fields/Date/typeParity.spec.tsx +27 -10
  482. package/src/fields/DateRange/DateRange.spec.tsx +87 -15
  483. package/src/fields/DateRange/index.tsx +47 -3
  484. package/src/fields/Duration/Duration.spec.tsx +73 -0
  485. package/src/fields/MentionInput/MentionInput.spec.tsx +110 -0
  486. package/src/fields/MentionInput/index.tsx +4 -1
  487. package/src/fields/Password/index.tsx +1 -1
  488. package/src/fields/Progress/Progress.spec.tsx +9 -0
  489. package/src/fields/RadioGroup/RadioGroup.spec.tsx +93 -0
  490. package/src/fields/Signature/Signature.spec.tsx +105 -0
  491. package/src/fields/Slider/Slider.spec.tsx +73 -0
  492. package/src/fields/Switch/Switch.spec.tsx +65 -0
  493. package/src/fields/TextEditor/TextEditor.spec.tsx +2 -3
  494. package/src/fields/TextEditor/TextEditor.stories.tsx +31 -1
  495. package/src/fields/ToggleGroup/ToggleGroup.spec.tsx +110 -0
  496. package/src/frappeViews.designLaw.spec.ts +11 -7
  497. package/src/index.ts +13 -0
  498. package/src/schemaForm/index.tsx +6 -7
  499. package/src/shared/devWarn.ts +44 -0
  500. package/src/useFrappeAggregate.ts +17 -11
  501. package/src/useFrappeFacets.ts +17 -10
  502. package/src/useFrappeRows.spec.tsx +176 -0
  503. package/src/useFrappeRows.ts +293 -0
  504. package/types/FrappeCalendar.d.ts.map +1 -1
  505. package/types/FrappeChartCard.d.ts +17 -1
  506. package/types/FrappeChartCard.d.ts.map +1 -1
  507. package/types/FrappeForm.d.ts +6 -2
  508. package/types/FrappeForm.d.ts.map +1 -1
  509. package/types/FrappeGantt.d.ts.map +1 -1
  510. package/types/FrappeImageView.d.ts.map +1 -1
  511. package/types/FrappeKPICard.d.ts +14 -1
  512. package/types/FrappeKPICard.d.ts.map +1 -1
  513. package/types/FrappeKanban.d.ts.map +1 -1
  514. package/types/FrappeList.d.ts.map +1 -1
  515. package/types/FrappeProvider.d.ts +16 -6
  516. package/types/FrappeProvider.d.ts.map +1 -1
  517. package/types/FrappeReportBuilder.d.ts.map +1 -1
  518. package/types/FrappeTable.d.ts +20 -1
  519. package/types/FrappeTable.d.ts.map +1 -1
  520. package/types/FrappeTreeView.d.ts +38 -1
  521. package/types/FrappeTreeView.d.ts.map +1 -1
  522. package/types/desk/DeskShell.d.ts.map +1 -1
  523. package/types/desk/awesomebar.d.ts.map +1 -1
  524. package/types/fields/DateRange/index.d.ts.map +1 -1
  525. package/types/fields/MentionInput/index.d.ts.map +1 -1
  526. package/types/fields/Password/index.d.ts +1 -1
  527. package/types/fields/Password/index.d.ts.map +1 -1
  528. package/types/index.d.ts +1 -0
  529. package/types/index.d.ts.map +1 -1
  530. package/types/schemaForm/index.d.ts.map +1 -1
  531. package/types/shared/devWarn.d.ts +23 -0
  532. package/types/shared/devWarn.d.ts.map +1 -0
  533. package/types/useFrappeAggregate.d.ts +2 -1
  534. package/types/useFrappeAggregate.d.ts.map +1 -1
  535. package/types/useFrappeFacets.d.ts +2 -1
  536. package/types/useFrappeFacets.d.ts.map +1 -1
  537. package/types/useFrappeRows.d.ts +186 -0
  538. package/types/useFrappeRows.d.ts.map +1 -0
@@ -1,14 +1,14 @@
1
- import { useDocTypeMeta, useFrappeCollection, useLiveQuery } from "@multiplatform.one/frappe";
2
- import { AsyncBoundary, TreeView, type TreeNode } from "@multiplatform.one/components";
1
+ import { useDocTypeMeta } from "@multiplatform.one/frappe";
2
+ import { AsyncBoundary, EmptyState, TreeView, type TreeNode } from "@multiplatform.one/components";
3
3
  import { TreeStructureIcon } from "@phosphor-icons/react";
4
- import React, { useCallback, useEffect, useMemo, useState } from "react";
4
+ import React, { useCallback, useMemo, useState } from "react";
5
5
  import { useTranslation } from "react-i18next";
6
6
  import { Text, YStack, type YStackProps } from "tamagui";
7
- import { useResolvedKnobs } from "@multiplatform.one/theme";
7
+ import { useGlyphColor, useResolvedKnobs } from "@multiplatform.one/theme";
8
8
  import { formCommonColors } from "@multiplatform.one/forms";
9
9
  import { useFrappeConfig } from "./FrappeProvider";
10
10
  import { FrappeReconnectIndicator } from "./FrappeReconnectIndicator";
11
- import { toLiveLoadError } from "./liveErrors";
11
+ import { useFrappeRows } from "./useFrappeRows";
12
12
 
13
13
  export interface FrappeTreeViewProps<TDoc extends { name: string; doctype: string }> extends Omit<
14
14
  YStackProps,
@@ -16,11 +16,32 @@ export interface FrappeTreeViewProps<TDoc extends { name: string; doctype: strin
16
16
  > {
17
17
  doctype: string;
18
18
  parentField?: string;
19
+ /**
20
+ * Separator that splits {@link FrappeTreeViewProps.pathField} into levels,
21
+ * e.g. ":" for an account named `Assets:Personal:Bank:Checking`. Setting it
22
+ * switches the tree to path mode: the branches between root and leaf are
23
+ * synthesised from the segments, `parentField` is neither read nor fetched,
24
+ * and the `is_tree` gate is skipped. A doctype whose hierarchy lives in the
25
+ * row's own key has no parent field and the server will never report
26
+ * `is_tree`.
27
+ */
28
+ pathSeparator?: string;
29
+ /**
30
+ * Row field holding the path. Path mode only; defaults to `name`. Path mode
31
+ * fetches `name`, this field, `valueField` and whatever `fields` adds, so a
32
+ * caller who needs more on the `onNodeClick` document asks for it there.
33
+ */
34
+ pathField?: string;
19
35
  titleField?: string;
20
36
  valueField?: string;
21
37
  fields?: readonly (keyof TDoc & string)[];
22
38
  filters?: Partial<TDoc> | Array<[keyof TDoc & string, string, any]>;
23
39
  onNodeClick?: (doc: Partial<TDoc>) => void;
40
+ /**
41
+ * Path-mode selection, fired for synthesised branches as well as documents.
42
+ * `doc` is present only when a document actually sits at that path.
43
+ */
44
+ onPathSelect?: (path: string, doc?: Partial<TDoc>) => void;
24
45
  /** Reserved for future DnD reparenting; not wired yet. */
25
46
  enableDragDrop?: boolean;
26
47
  /** Expand every branch on first paint (passed through to TreeView). */
@@ -88,20 +109,94 @@ export function buildTreeNodes<TDoc extends { name: string }>(
88
109
  return sortDocs(roots).map(buildNode);
89
110
  }
90
111
 
112
+ /** One level of the path forest, before it becomes TreeNodes. */
113
+ interface PathBucket<TDoc> {
114
+ path: string;
115
+ segment: string;
116
+ doc?: TDoc;
117
+ children: Map<string, PathBucket<TDoc>>;
118
+ }
119
+
120
+ /**
121
+ * Build a TreeNode forest from paths held on the rows themselves, e.g.
122
+ * `Assets:Personal:Bank:Checking` split on ":".
123
+ *
124
+ * The branches between root and leaf are not rows, so they are synthesised:
125
+ * a synthesised node carries no `data` and its `id` is the path prefix it
126
+ * stands for. A row whose path value is empty falls back to a single segment
127
+ * of its own name, so nothing is silently dropped.
128
+ */
129
+ export function buildPathTreeNodes<TDoc extends { name: string }>(
130
+ docs: TDoc[],
131
+ pathField: string,
132
+ separator: string,
133
+ ): TreeNode<Record<string, unknown>>[] {
134
+ const roots = new Map<string, PathBucket<TDoc>>();
135
+
136
+ const splitPath = (doc: TDoc): string[] => {
137
+ const raw = (doc as Record<string, unknown>)[pathField];
138
+ const value = raw == null ? "" : String(raw);
139
+ // An empty separator would split the value into single characters.
140
+ const segments = separator ? value.split(separator) : [value];
141
+ const cleaned = segments.map((segment) => segment.trim()).filter((segment) => segment !== "");
142
+ return cleaned.length > 0 ? cleaned : [doc.name];
143
+ };
144
+
145
+ for (const doc of docs) {
146
+ let level = roots;
147
+ let prefix = "";
148
+ let bucket: PathBucket<TDoc> | undefined;
149
+ for (const segment of splitPath(doc)) {
150
+ prefix = prefix ? `${prefix}${separator}${segment}` : segment;
151
+ bucket = level.get(segment);
152
+ if (!bucket) {
153
+ bucket = { path: prefix, segment, children: new Map() };
154
+ level.set(segment, bucket);
155
+ }
156
+ level = bucket.children;
157
+ }
158
+ // Two rows on one path: the first keeps the node rather than the last
159
+ // row the live query happened to deliver.
160
+ if (bucket && !bucket.doc) bucket.doc = doc;
161
+ }
162
+
163
+ const toNodes = (level: Map<string, PathBucket<TDoc>>): TreeNode<Record<string, unknown>>[] =>
164
+ Array.from(level.values())
165
+ .sort((a, b) => a.segment.localeCompare(b.segment))
166
+ .map((bucket) => {
167
+ const children = toNodes(bucket.children);
168
+ return {
169
+ id: bucket.path,
170
+ label: bucket.segment,
171
+ data: bucket.doc as unknown as Record<string, unknown> | undefined,
172
+ children: children.length > 0 ? children : undefined,
173
+ };
174
+ });
175
+
176
+ return toNodes(roots);
177
+ }
178
+
91
179
  /**
92
180
  * Thin Frappe wrapper around the generic TreeView component.
93
181
  *
94
182
  * Fetches the full DocType list via `useFrappeCollection` / `useLiveQuery`
95
183
  * (realtime-backed), then builds a `TreeNode` forest from the parent field.
184
+ *
185
+ * Pass `pathSeparator` instead when the hierarchy lives in the row's own key
186
+ * (`Assets:Personal:Bank:Checking`). The branches are synthesised client-side,
187
+ * so no parent field and no `is_tree` are needed.
96
188
  */
97
189
  export function FrappeTreeView<TDoc extends { name: string; doctype: string }>({
98
190
  doctype,
99
191
  parentField: parentFieldProp,
192
+ pathSeparator,
193
+ pathField,
100
194
  titleField: titleFieldProp,
101
195
  valueField,
102
196
  fields,
103
197
  filters,
104
198
  onNodeClick,
199
+ onPathSelect,
105
200
  enableDragDrop: _enableDragDrop = false,
106
201
  expandByDefault = false,
107
202
  display = "default",
@@ -116,6 +211,7 @@ export function FrappeTreeView<TDoc extends { name: string; doctype: string }>({
116
211
 
117
212
  const config = useFrappeConfig();
118
213
  const { knobProps } = useResolvedKnobs();
214
+ const emptyIconColor = useGlyphColor(formCommonColors.muted);
119
215
  const { t } = useTranslation();
120
216
  const [selectedId, setSelectedId] = useState<string | undefined>();
121
217
 
@@ -123,8 +219,10 @@ export function FrappeTreeView<TDoc extends { name: string; doctype: string }>({
123
219
  const finalAuth = auth ?? config?.auth;
124
220
  const finalSyncOptions = syncOptions ?? config?.syncOptions;
125
221
 
126
- if (!finalBaseURL) {
127
- throw new Error("FrappeTreeView requires baseURL prop or FrappeProvider with baseURL");
222
+ if (!finalBaseURL && !config?.fixtures) {
223
+ throw new Error(
224
+ "FrappeTreeView requires baseURL prop or FrappeProvider with baseURL or fixtures",
225
+ );
128
226
  }
129
227
 
130
228
  const appConfig = useMemo(
@@ -152,6 +250,8 @@ export function FrappeTreeView<TDoc extends { name: string; doctype: string }>({
152
250
 
153
251
  const { meta, isLoading: isMetaLoading, error: metaError } = useDocTypeMeta(appConfig, doctype);
154
252
 
253
+ const isPathMode = !!pathSeparator;
254
+ const effectivePathField = pathField ?? "name";
155
255
  const effectiveTitleField = titleFieldProp ?? meta?.title_field ?? "name";
156
256
  const effectiveParentField =
157
257
  parentFieldProp ?? `parent_${doctype.toLowerCase().replace(/ /g, "_")}`;
@@ -160,67 +260,75 @@ export function FrappeTreeView<TDoc extends { name: string; doctype: string }>({
160
260
  // lets callers continue (Guest peek / offline). Successful meta always
161
261
  // wins for the is_tree gate — including rejecting flat DocTypes that
162
262
  // happened to pass parentField.
163
- const isKnownNotTree = !!meta && !meta.is_tree;
164
- const canProceed = !!meta?.is_tree || (!!metaError && !meta && !!parentFieldProp);
263
+ //
264
+ // Path mode is the exception: the hierarchy comes from the row's own key,
265
+ // so there is nothing for is_tree to be right about.
266
+ const isKnownNotTree = !isPathMode && !!meta && !meta.is_tree;
267
+ const canProceed = isPathMode || !!meta?.is_tree || (!!metaError && !meta && !!parentFieldProp);
165
268
 
166
269
  const effectiveFields = useMemo(() => {
167
270
  const fieldSet = new Set<string>(fields as string[] | undefined);
168
271
  fieldSet.add("name");
169
- fieldSet.add(effectiveTitleField);
170
- fieldSet.add(effectiveParentField);
272
+ if (isPathMode) {
273
+ // The parent field does not exist on a path-shaped doctype; asking for
274
+ // it would fail the read on a live bench.
275
+ fieldSet.add(effectivePathField);
276
+ } else {
277
+ fieldSet.add(effectiveTitleField);
278
+ fieldSet.add(effectiveParentField);
279
+ }
171
280
  if (valueField) fieldSet.add(valueField);
172
281
  return Array.from(fieldSet) as (keyof TDoc & string)[];
173
- }, [fields, effectiveTitleField, effectiveParentField, valueField]);
174
-
175
- // Honest error surface: without onSyncError a 403/network failure renders
176
- // as an empty tree.
177
- const [syncError, setSyncError] = useState<Error | null>(null);
178
- const handleSyncError = useCallback(
179
- (err: unknown) => {
180
- setSyncError(
181
- toLiveLoadError(err, {
182
- permissionMessage: t("You do not have permission to view {{doctype}}", { doctype }),
183
- genericMessage: t("Failed to load {{doctype}} tree", { doctype }),
184
- }),
185
- );
186
- },
187
- [doctype, t],
188
- );
282
+ }, [
283
+ fields,
284
+ isPathMode,
285
+ effectivePathField,
286
+ effectiveTitleField,
287
+ effectiveParentField,
288
+ valueField,
289
+ ]);
189
290
 
190
- const collection = useFrappeCollection<TDoc>(
191
- canProceed && !isKnownNotTree ? appConfig : undefined,
192
- doctype,
193
- { fields: effectiveFields, filters, onSyncError: handleSyncError },
291
+ // The shared doctype read (MPO-251): collection + live query + the honest
292
+ // error surface a bare collection swallows — without it a 403 or a network
293
+ // failure renders as an empty tree. `limit: null` keeps the tree on the
294
+ // bench's own page length, as it was before the hook existed.
295
+ const rowsMessages = useMemo(
296
+ () => ({
297
+ permission: t("You do not have permission to view {{doctype}}", { doctype }),
298
+ generic: t("Failed to load {{doctype}} tree", { doctype }),
299
+ }),
300
+ [doctype, t],
194
301
  );
195
-
196
- // A new collection (doctype/filter change) starts with a clean slate.
197
- useEffect(() => {
198
- setSyncError(null);
199
- }, [collection]);
200
-
201
302
  const {
202
- data: rawData,
203
- isLoading: isDataLoading,
204
- isError,
205
- } = useLiveQuery((q) => (collection ? q.from({ _list: collection }) : null), [collection]);
206
-
207
- const docs = useMemo(() => (rawData as TDoc[] | undefined) ?? [], [rawData]);
303
+ rows: docs,
304
+ isQueryLoading: isDataLoading,
305
+ error: queryError,
306
+ } = useFrappeRows<TDoc>(appConfig, doctype, {
307
+ fields: effectiveFields,
308
+ filters,
309
+ limit: null,
310
+ enabled: canProceed && !isKnownNotTree,
311
+ messages: rowsMessages,
312
+ });
208
313
 
209
314
  const treeNodes = useMemo(
210
- () => buildTreeNodes(docs, effectiveParentField, effectiveTitleField),
211
- [docs, effectiveParentField, effectiveTitleField],
315
+ () =>
316
+ pathSeparator
317
+ ? buildPathTreeNodes(docs, effectivePathField, pathSeparator)
318
+ : buildTreeNodes(docs, effectiveParentField, effectiveTitleField),
319
+ [docs, pathSeparator, effectivePathField, effectiveParentField, effectiveTitleField],
212
320
  );
213
321
 
214
- const queryError =
215
- syncError ?? (isError ? new Error(t("Failed to load {{doctype}} tree", { doctype })) : null);
216
-
217
322
  const handleNodeSelect = useCallback(
218
323
  (node: TreeNode<Record<string, unknown>>) => {
219
324
  setSelectedId(node.id);
325
+ if (isPathMode) onPathSelect?.(node.id, node.data as Partial<TDoc> | undefined);
326
+ // A synthesised branch is not a document, so onNodeClick stays silent
327
+ // rather than handing a caller a name that would 404 on open.
220
328
  if (!node.data) return;
221
329
  onNodeClick?.(node.data as Partial<TDoc>);
222
330
  },
223
- [onNodeClick],
331
+ [isPathMode, onNodeClick, onPathSelect],
224
332
  );
225
333
 
226
334
  if (isMetaLoading) {
@@ -228,7 +336,7 @@ export function FrappeTreeView<TDoc extends { name: string; doctype: string }>({
228
336
  return <AsyncBoundary layout="list" loading {...stackProps} />;
229
337
  }
230
338
 
231
- if (metaError && !meta && !parentFieldProp) {
339
+ if (metaError && !meta && !parentFieldProp && !isPathMode) {
232
340
  if (error) return <>{error(metaError)}</>;
233
341
  return (
234
342
  <AsyncBoundary
@@ -243,12 +351,14 @@ export function FrappeTreeView<TDoc extends { name: string; doctype: string }>({
243
351
  if (isKnownNotTree) {
244
352
  const iconSize = Number(knobProps.controlIcon?.width) || 16;
245
353
  return (
246
- <YStack {...knobProps.panelPadding} alignItems="center" {...knobProps.gap} {...stackProps}>
247
- <TreeStructureIcon size={iconSize * 2} color={formCommonColors.muted} />
248
- <Text color={formCommonColors.muted} {...knobProps.body}>
249
- {t("This DocType does not support tree view")}
250
- </Text>
251
- </YStack>
354
+ <EmptyState
355
+ title={t("This DocType does not support tree view")}
356
+ description={t(
357
+ "Pass pathSeparator and pathField to build the hierarchy from a path-shaped value on each row. parentField alone does not, because a flat DocType has no parent field.",
358
+ )}
359
+ icon={<TreeStructureIcon size={iconSize * 2} color={emptyIconColor} />}
360
+ {...stackProps}
361
+ />
252
362
  );
253
363
  }
254
364
 
@@ -67,7 +67,7 @@ export function useFrappeCommentActions(
67
67
  ): FrappeCommentActions {
68
68
  return useMemo(() => {
69
69
  const app =
70
- config && !config.fixtures
70
+ config?.baseURL && !config.fixtures
71
71
  ? new FrappeApp(config.baseURL, (config.auth ?? {}) as Record<string, unknown>)
72
72
  : undefined;
73
73
 
@@ -208,7 +208,7 @@ export function Timeline({
208
208
 
209
209
  const resolveSessionUser = useCallback(async (): Promise<string> => {
210
210
  if (sessionUserRef.current) return sessionUserRef.current;
211
- if (config && !config.fixtures) {
211
+ if (config?.baseURL && !config.fixtures) {
212
212
  const app = new FrappeApp(config.baseURL, (config.auth ?? {}) as Record<string, unknown>);
213
213
  sessionUserRef.current = await app.auth().getLoggedInUser();
214
214
  } else {
@@ -209,6 +209,7 @@ export function DeskShell({
209
209
  {showSidebar && !isNarrow && (
210
210
  <YStack
211
211
  role="navigation"
212
+ aria-label={t("Desk navigation")}
212
213
  id="desk-sidebar"
213
214
  flexShrink={0}
214
215
  data-testid="desk-sidebar-rail"
@@ -234,6 +235,7 @@ export function DeskShell({
234
235
  />
235
236
  <YStack
236
237
  role="navigation"
238
+ aria-label={t("Desk navigation")}
237
239
  id="desk-sidebar"
238
240
  position="absolute"
239
241
  top={0}
@@ -101,7 +101,10 @@ async function addRecentSearch(query: string): Promise<void> {
101
101
  // Helpers
102
102
  // ---------------------------------------------------------------------------
103
103
 
104
- function createHttpClientFromConfig(config: FrappeConnectionConfig): HttpClient {
104
+ function createHttpClientFromConfig(config: {
105
+ baseURL: string;
106
+ auth?: FrappeConnectionConfig["auth"];
107
+ }): HttpClient {
105
108
  return new HttpClient(
106
109
  config.baseURL,
107
110
  config.auth as Parameters<typeof HttpClient.prototype.updateAuth>[0],
@@ -168,7 +171,7 @@ export function Awesomebar({ onNavigate, basePath = "/desk", ...stackProps }: Aw
168
171
  // HttpClient ref for document search
169
172
  const httpRef = useRef<HttpClient | undefined>(undefined);
170
173
  const configKeyRef = useRef("");
171
- if (config) {
174
+ if (config?.baseURL) {
172
175
  const key = `${config.baseURL}:${config.auth?.token ?? ""}`;
173
176
  if (key !== configKeyRef.current) {
174
177
  httpRef.current = createHttpClientFromConfig({
@@ -29,12 +29,10 @@ function readCodeEditorSource() {
29
29
  return readFileSync(join(codeEditorDir(), "index.tsx"), "utf8");
30
30
  }
31
31
 
32
- function readCodeEditorStories() {
33
- return readFileSync(join(codeEditorDir(), "CodeEditor.stories.tsx"), "utf8");
34
- }
35
-
36
32
  afterEach(cleanup);
37
33
 
34
+ vi.mock("@multiplatform.one/storybook", () => ({ action: () => vi.fn() }));
35
+
38
36
  describe("frappeCodeLanguage (stock ControlCode language_map)", () => {
39
37
  it("maps stock Frappe options case-insensitively", () => {
40
38
  expect(frappeCodeLanguage("Python")).toBe("python");
@@ -102,11 +100,14 @@ describe("CodeEditorField (standalone)", () => {
102
100
  expect(result.getTextArea()).toBeNull();
103
101
  });
104
102
 
105
- it("ships CSF3 story objects so native gallery keeps args (KS blank-pane)", () => {
106
- const stories = readCodeEditorStories();
107
- expect(stories).toMatch(/export const Main = \{/);
108
- expect(stories).not.toMatch(/Main\.args\s*=/);
109
- expect(stories).toContain("value: PYTHON_FIXTURE");
103
+ it("ships CSF3 story objects so native gallery keeps args (KS blank-pane)", async () => {
104
+ const { Main, Json, ReadOnly } = await import("./CodeEditor.stories");
105
+ for (const story of [Main, Json, ReadOnly]) {
106
+ expect(typeof story).toBe("object");
107
+ expect(story.render).toBeTypeOf("function");
108
+ expect(story.args.value?.trim().length).toBeGreaterThan(0);
109
+ }
110
+ expect(ReadOnly.args.readOnly).toBe(true);
110
111
  });
111
112
 
112
113
  it("forwards knob containerRadius onto the source textarea (F14)", () => {
@@ -10,7 +10,7 @@
10
10
  * a seeded value is not a user edit).
11
11
  */
12
12
 
13
- import { describe, it, expect, vi } from "vitest";
13
+ import { describe, it, expect, vi, beforeAll } from "vitest";
14
14
 
15
15
  // The first field-module import in a cold fork transforms the whole fields
16
16
  // graph (same budget as tests/fieldRenderers.spec.tsx).
@@ -79,6 +79,13 @@ function getDayButton(root: ParentNode, day: number): HTMLButtonElement | undefi
79
79
  });
80
80
  }
81
81
 
82
+ // Warm the graph here, not inside the first `it`: the transform is setup cost
83
+ // (110-155s quiet, past 240s under load), and charging it to an assertion made
84
+ // whichever case ran first time out.
85
+ beforeAll(async () => {
86
+ await loadDateField();
87
+ }, 900_000);
88
+
82
89
  describe("Date wrapper — late-arriving value display", () => {
83
90
  it("a value arriving after mount displays, without onChange", async () => {
84
91
  const DateField = await loadDateField();
@@ -18,7 +18,7 @@
18
18
  * than rendered) and the platform flags.
19
19
  */
20
20
 
21
- import { describe, it, expect, vi, beforeEach } from "vitest";
21
+ import { describe, it, expect, vi, beforeAll, beforeEach } from "vitest";
22
22
 
23
23
  // Same cold-fork budget as the sibling Date.spec.tsx: the first field-module
24
24
  // import transforms the whole fields graph.
@@ -132,6 +132,13 @@ async function press(root: ParentNode, text: string) {
132
132
  const lastPick = () => mockState.picks[mockState.picks.length - 1];
133
133
  const waitForPick = (predicate: () => void) => waitFor(predicate, { timeout: 30_000 });
134
134
 
135
+ // Warm the graph here, not inside the first `it`: the transform is setup cost
136
+ // (110-155s quiet, past 240s under load), and charging it to an assertion made
137
+ // whichever case ran first time out.
138
+ beforeAll(async () => {
139
+ await loadNativeDateField();
140
+ }, 900_000);
141
+
135
142
  beforeEach(() => {
136
143
  // The iOS sheet is a portal, so a previous case's chrome would otherwise
137
144
  // still be in the document when the next one asserts on it.
@@ -17,7 +17,7 @@
17
17
  * rather than rendered) and the platform flags. The web half imports neither.
18
18
  */
19
19
 
20
- import { describe, it, expect, vi, beforeEach } from "vitest";
20
+ import { describe, it, expect, vi, beforeAll, beforeEach } from "vitest";
21
21
 
22
22
  // Same cold-fork budget as the sibling Date specs: the first field-module
23
23
  // import transforms the whole fields graph.
@@ -168,6 +168,21 @@ async function pressText(root: ParentNode, text: string) {
168
168
  });
169
169
  }
170
170
 
171
+ async function selectPeriod(period: "AM" | "PM") {
172
+ const wheel = document.querySelector('[role="slider"][aria-label="AM/PM"]');
173
+ expect(wheel).toBeTruthy();
174
+ await act(async () => {
175
+ fireEvent.keyDown(wheel!, { key: period === "AM" ? "Home" : "End" });
176
+ });
177
+ }
178
+
179
+ // Warm the graph here, not inside the first `it`: the transform is setup cost
180
+ // (110-155s quiet, past 240s under load), and charging it to an assertion made
181
+ // whichever case ran first time out.
182
+ beforeAll(async () => {
183
+ await Promise.all([loadWebDateField(), loadNativeDateField()]);
184
+ }, 900_000);
185
+
171
186
  beforeEach(() => {
172
187
  // Both halves portal their surfaces, so a previous case's chrome would
173
188
  // otherwise still be in the document when the next one queries it.
@@ -194,7 +209,7 @@ describe("web Date field — type=date keeps the calendar", () => {
194
209
  await openPanel(triggerInput(result.container)!);
195
210
  expect(panelText()).toContain("Su");
196
211
  // A date-only control offers no clock.
197
- expect(panelText()).not.toMatch(/\bHour\b/);
212
+ expect(document.querySelector('[role="slider"][aria-label="Hour"]')).toBeNull();
198
213
 
199
214
  await waitFor(() => expect(dayCell(15)).toBeTruthy(), { timeout: 30_000 });
200
215
  await act(async () => {
@@ -226,8 +241,8 @@ describe("web Date field — type=time renders a time control", () => {
226
241
  );
227
242
  await openPanel(triggerInput(result.container)!);
228
243
  const text = panelText();
229
- expect(text).toContain("Hour");
230
- expect(text).toContain("Min");
244
+ expect(document.querySelector('[role="slider"][aria-label="Hour"]')).toBeTruthy();
245
+ expect(document.querySelector('[role="slider"][aria-label="Min"]')).toBeTruthy();
231
246
  expect(text).not.toContain("Su");
232
247
  });
233
248
 
@@ -239,11 +254,11 @@ describe("web Date field — type=time renders a time control", () => {
239
254
  );
240
255
  await openPanel(triggerInput(result.container)!);
241
256
  // 9:00 AM → PM is a deterministic edit with no wheel animation in it.
242
- await pressText(document.body, "PM");
257
+ await selectPeriod("PM");
243
258
 
244
259
  // The control speaks `HH:mm`; the field re-serializes through the shared
245
260
  // wire body, so what persists carries seconds like every other writer.
246
- expect(onChange).toHaveBeenCalledWith("21:00:00");
261
+ await waitFor(() => expect(onChange).toHaveBeenCalledWith("21:00:00"));
247
262
  });
248
263
 
249
264
  it("adopts a seconds-less HH:mm value too (what Frappe hands a fresh field)", async () => {
@@ -292,7 +307,9 @@ describe("web Date field — type=datetime renders date AND time", () => {
292
307
  await openPanel(triggerInput(result.container)!);
293
308
  expect(panelText()).toContain("Su");
294
309
  await pressText(document.body, "Time");
295
- await waitFor(() => expect(panelText()).toContain("Hour"), { timeout: 30_000 });
310
+ await waitFor(() =>
311
+ expect(document.querySelector('[role="slider"][aria-label="Hour"]')).toBeTruthy(),
312
+ );
296
313
  });
297
314
 
298
315
  it("a day change keeps the existing time — and the picker, not the serializer, keeps it", async () => {
@@ -330,8 +347,8 @@ describe("web Date field — type=datetime renders date AND time", () => {
330
347
  await pressText(document.body, "Time");
331
348
  // 2:30 PM → AM. Carrying `previousValue` here would have pinned the old
332
349
  // 14:30 back over the edit the user just made.
333
- await pressText(document.body, "AM");
334
- expect(onChange).toHaveBeenLastCalledWith("2026-03-05 02:30:00");
350
+ await selectPeriod("AM");
351
+ await waitFor(() => expect(onChange).toHaveBeenLastCalledWith("2026-03-05 02:30:00"));
335
352
  });
336
353
  });
337
354
 
@@ -412,7 +429,7 @@ describe("web and native persist byte-identical wire strings", () => {
412
429
 
413
430
  it("time — moving 9:00 AM to 9:00 PM writes the same string on both halves", async () => {
414
431
  const web = await webPick("time", "09:00:00", async () => {
415
- await pressText(document.body, "PM");
432
+ await selectPeriod("PM");
416
433
  });
417
434
  cleanup();
418
435
  mockState.picks.length = 0;