@multiplatform.one/frappe-ui 7.7.6 → 7.8.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 (491) 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.native.js.map +1 -1
  8. package/dist/cjs/FrappeAssignment.native.js.map +1 -1
  9. package/dist/cjs/FrappeCalendar.cjs +20 -17
  10. package/dist/cjs/FrappeCalendar.native.js +22 -21
  11. package/dist/cjs/FrappeCalendar.native.js.map +1 -1
  12. package/dist/cjs/FrappeChartCard.native.js.map +1 -1
  13. package/dist/cjs/FrappeConnectionIndicator.native.js.map +1 -1
  14. package/dist/cjs/FrappeDashboard.native.js.map +1 -1
  15. package/dist/cjs/FrappeForm.cjs +1 -1
  16. package/dist/cjs/FrappeForm.native.js +2 -2
  17. package/dist/cjs/FrappeForm.native.js.map +1 -1
  18. package/dist/cjs/FrappeGantt.cjs +25 -34
  19. package/dist/cjs/FrappeGantt.native.js +27 -38
  20. package/dist/cjs/FrappeGantt.native.js.map +1 -1
  21. package/dist/cjs/FrappeImageView.cjs +4 -2
  22. package/dist/cjs/FrappeImageView.native.js +8 -4
  23. package/dist/cjs/FrappeImageView.native.js.map +1 -1
  24. package/dist/cjs/FrappeKPICard.cjs +26 -1
  25. package/dist/cjs/FrappeKPICard.native.js +26 -1
  26. package/dist/cjs/FrappeKPICard.native.js.map +1 -1
  27. package/dist/cjs/FrappeKanban.cjs +16 -17
  28. package/dist/cjs/FrappeKanban.native.js +18 -21
  29. package/dist/cjs/FrappeKanban.native.js.map +1 -1
  30. package/dist/cjs/FrappeLikedBy.cjs +1 -1
  31. package/dist/cjs/FrappeLikedBy.native.js +1 -1
  32. package/dist/cjs/FrappeLikedBy.native.js.map +1 -1
  33. package/dist/cjs/FrappeList.cjs +2 -2
  34. package/dist/cjs/FrappeList.native.js +2 -2
  35. package/dist/cjs/FrappeList.native.js.map +1 -1
  36. package/dist/cjs/FrappeListView.native.js.map +1 -1
  37. package/dist/cjs/FrappeProvider.native.js.map +1 -1
  38. package/dist/cjs/FrappeReconnectIndicator.native.js.map +1 -1
  39. package/dist/cjs/FrappeReportBuilder.cjs +2 -2
  40. package/dist/cjs/FrappeReportBuilder.native.js +2 -2
  41. package/dist/cjs/FrappeReportBuilder.native.js.map +1 -1
  42. package/dist/cjs/FrappeReportView.native.js +3 -3
  43. package/dist/cjs/FrappeReportView.native.js.map +1 -1
  44. package/dist/cjs/FrappeTable.cjs +35 -38
  45. package/dist/cjs/FrappeTable.native.js +38 -39
  46. package/dist/cjs/FrappeTable.native.js.map +1 -1
  47. package/dist/cjs/FrappeTreeView.cjs +85 -50
  48. package/dist/cjs/FrappeTreeView.native.js +129 -50
  49. package/dist/cjs/FrappeTreeView.native.js.map +1 -1
  50. package/dist/cjs/SyncErrorNotice.native.js.map +1 -1
  51. package/dist/cjs/commentActions.cjs +1 -1
  52. package/dist/cjs/commentActions.native.js +1 -1
  53. package/dist/cjs/commentActions.native.js.map +1 -1
  54. package/dist/cjs/components/attachments.native.js.map +1 -1
  55. package/dist/cjs/components/tags.native.js.map +1 -1
  56. package/dist/cjs/components/timeline.cjs +1 -1
  57. package/dist/cjs/components/timeline.native.js +1 -1
  58. package/dist/cjs/components/timeline.native.js.map +1 -1
  59. package/dist/cjs/dependsOn.native.js.map +1 -1
  60. package/dist/cjs/desk/DeskFormPage.native.js.map +1 -1
  61. package/dist/cjs/desk/DeskFormSidebar.native.js.map +1 -1
  62. package/dist/cjs/desk/DeskListPage.native.js.map +1 -1
  63. package/dist/cjs/desk/DeskShell.cjs +2 -0
  64. package/dist/cjs/desk/DeskShell.native.js +2 -0
  65. package/dist/cjs/desk/DeskShell.native.js.map +1 -1
  66. package/dist/cjs/desk/DeskSidebar.native.js.map +1 -1
  67. package/dist/cjs/desk/awesomebar.cjs +1 -1
  68. package/dist/cjs/desk/awesomebar.native.js +1 -1
  69. package/dist/cjs/desk/awesomebar.native.js.map +1 -1
  70. package/dist/cjs/fieldOverrides.native.js.map +1 -1
  71. package/dist/cjs/fieldRegistry.native.js +31 -31
  72. package/dist/cjs/fieldRegistry.native.js.map +1 -1
  73. package/dist/cjs/fields/Barcode/index.native.js.map +1 -1
  74. package/dist/cjs/fields/Check/index.native.js.map +1 -1
  75. package/dist/cjs/fields/CodeEditor/index.native.js.map +1 -1
  76. package/dist/cjs/fields/Color/index.native.js.map +1 -1
  77. package/dist/cjs/fields/Data/index.native.js.map +1 -1
  78. package/dist/cjs/fields/Date/sheetKeyboard.native.js.map +1 -1
  79. package/dist/cjs/fields/Date/types.native.js.map +1 -1
  80. package/dist/cjs/fields/Date/wire.native.js.map +1 -1
  81. package/dist/cjs/fields/DateRange/index.native.js.map +1 -1
  82. package/dist/cjs/fields/Duration/index.native.js.map +1 -1
  83. package/dist/cjs/fields/DynamicLink.native.js.map +1 -1
  84. package/dist/cjs/fields/FileUpload.native.js.map +1 -1
  85. package/dist/cjs/fields/FileUploadField/index.native.js.map +1 -1
  86. package/dist/cjs/fields/Geolocation/index.native.js.map +1 -1
  87. package/dist/cjs/fields/HTML/index.native.js.map +1 -1
  88. package/dist/cjs/fields/Heading/index.native.js.map +1 -1
  89. package/dist/cjs/fields/Icon/index.native.js.map +1 -1
  90. package/dist/cjs/fields/Link.native.js.map +1 -1
  91. package/dist/cjs/fields/LinkTree.native.js.map +1 -1
  92. package/dist/cjs/fields/LongText/index.native.js.map +1 -1
  93. package/dist/cjs/fields/MentionInput/index.cjs +4 -1
  94. package/dist/cjs/fields/MentionInput/index.native.js +4 -1
  95. package/dist/cjs/fields/MentionInput/index.native.js.map +1 -1
  96. package/dist/cjs/fields/Numeric/index.native.js.map +1 -1
  97. package/dist/cjs/fields/OTPInput/index.native.js.map +1 -1
  98. package/dist/cjs/fields/Password/index.native.js.map +1 -1
  99. package/dist/cjs/fields/Phone/index.native.js.map +1 -1
  100. package/dist/cjs/fields/Progress/index.native.js.map +1 -1
  101. package/dist/cjs/fields/RadioGroup/index.native.js.map +1 -1
  102. package/dist/cjs/fields/Rating/index.native.js.map +1 -1
  103. package/dist/cjs/fields/ReadOnly/index.native.js.map +1 -1
  104. package/dist/cjs/fields/Select/index.native.js.map +1 -1
  105. package/dist/cjs/fields/Signature/index.native.js.map +1 -1
  106. package/dist/cjs/fields/Slider/index.native.js.map +1 -1
  107. package/dist/cjs/fields/SmallText/index.native.js.map +1 -1
  108. package/dist/cjs/fields/Switch/index.native.js.map +1 -1
  109. package/dist/cjs/fields/TableMultiSelect.native.js.map +1 -1
  110. package/dist/cjs/fields/TextEditor/types.native.js.map +1 -1
  111. package/dist/cjs/fields/TimePicker/index.native.js.map +1 -1
  112. package/dist/cjs/fields/ToggleGroup/index.native.js.map +1 -1
  113. package/dist/cjs/fields/shared/EditorPreviewPanes.native.js.map +1 -1
  114. package/dist/cjs/filterFields.native.js.map +1 -1
  115. package/dist/cjs/formEngine/createPrefill.native.js.map +1 -1
  116. package/dist/cjs/formEngine/dirtyTracking.native.js.map +1 -1
  117. package/dist/cjs/formEngine/doctypeMeta.native.js.map +1 -1
  118. package/dist/cjs/formEngine/fetchFrom.native.js.map +1 -1
  119. package/dist/cjs/formEngine/fieldPermissions.native.js.map +1 -1
  120. package/dist/cjs/formEngine/formActions.native.js.map +1 -1
  121. package/dist/cjs/formEngine/formLayout.native.js.map +1 -1
  122. package/dist/cjs/formEngine/index.native.js.map +1 -1
  123. package/dist/cjs/formEngine/useFormEngine.native.js.map +1 -1
  124. package/dist/cjs/frappeEventColor.native.js.map +1 -1
  125. package/dist/cjs/frappeStoryTarget.native.js.map +1 -1
  126. package/dist/cjs/frappeUsers.native.js.map +1 -1
  127. package/dist/cjs/index.cjs +4 -0
  128. package/dist/cjs/index.native.js +38 -34
  129. package/dist/cjs/index.native.js.map +1 -1
  130. package/dist/cjs/liveErrors.native.js.map +1 -1
  131. package/dist/cjs/resolveControl.native.js.map +1 -1
  132. package/dist/cjs/schemaForm/SchemaWizard.native.js.map +1 -1
  133. package/dist/cjs/schemaForm/applyFieldOrder.native.js.map +1 -1
  134. package/dist/cjs/schemaForm/index.cjs +10 -9
  135. package/dist/cjs/schemaForm/index.native.js +11 -10
  136. package/dist/cjs/schemaForm/index.native.js.map +1 -1
  137. package/dist/cjs/shared/devWarn.cjs +40 -0
  138. package/dist/cjs/shared/devWarn.native.js +45 -0
  139. package/dist/cjs/shared/devWarn.native.js.map +1 -0
  140. package/dist/cjs/shared/useKeyboardInset.native.js.map +1 -1
  141. package/dist/cjs/syncError.native.js.map +1 -1
  142. package/dist/cjs/useFrappeAggregate.cjs +15 -8
  143. package/dist/cjs/useFrappeAggregate.native.js +15 -9
  144. package/dist/cjs/useFrappeAggregate.native.js.map +1 -1
  145. package/dist/cjs/useFrappeFacets.cjs +10 -9
  146. package/dist/cjs/useFrappeFacets.native.js +10 -10
  147. package/dist/cjs/useFrappeFacets.native.js.map +1 -1
  148. package/dist/cjs/useFrappePagination.native.js.map +1 -1
  149. package/dist/cjs/useFrappeRows.cjs +113 -0
  150. package/dist/cjs/useFrappeRows.native.js +129 -0
  151. package/dist/cjs/useFrappeRows.native.js.map +1 -0
  152. package/dist/esm/ChartCard.native.js.map +1 -1
  153. package/dist/esm/FileBrowser/AttachLibrary.native.js.map +1 -1
  154. package/dist/esm/FileBrowser/folderTree.native.js.map +1 -1
  155. package/dist/esm/FileBrowser/index.native.js.map +1 -1
  156. package/dist/esm/FileBrowser/types.native.js.map +1 -1
  157. package/dist/esm/FileBrowser/viewPersistence.native.js.map +1 -1
  158. package/dist/esm/FormSidebar.native.js.map +1 -1
  159. package/dist/esm/FrappeAssignment.native.js.map +1 -1
  160. package/dist/esm/FrappeCalendar.mjs +20 -17
  161. package/dist/esm/FrappeCalendar.mjs.map +1 -1
  162. package/dist/esm/FrappeCalendar.native.js +22 -21
  163. package/dist/esm/FrappeCalendar.native.js.map +1 -1
  164. package/dist/esm/FrappeChartCard.native.js.map +1 -1
  165. package/dist/esm/FrappeConnectionIndicator.native.js.map +1 -1
  166. package/dist/esm/FrappeDashboard.native.js.map +1 -1
  167. package/dist/esm/FrappeForm.mjs +1 -1
  168. package/dist/esm/FrappeForm.mjs.map +1 -1
  169. package/dist/esm/FrappeForm.native.js +1 -1
  170. package/dist/esm/FrappeForm.native.js.map +1 -1
  171. package/dist/esm/FrappeGantt.mjs +27 -36
  172. package/dist/esm/FrappeGantt.mjs.map +1 -1
  173. package/dist/esm/FrappeGantt.native.js +29 -40
  174. package/dist/esm/FrappeGantt.native.js.map +1 -1
  175. package/dist/esm/FrappeImageView.mjs +5 -3
  176. package/dist/esm/FrappeImageView.mjs.map +1 -1
  177. package/dist/esm/FrappeImageView.native.js +9 -5
  178. package/dist/esm/FrappeImageView.native.js.map +1 -1
  179. package/dist/esm/FrappeKPICard.mjs +27 -2
  180. package/dist/esm/FrappeKPICard.mjs.map +1 -1
  181. package/dist/esm/FrappeKPICard.native.js +27 -2
  182. package/dist/esm/FrappeKPICard.native.js.map +1 -1
  183. package/dist/esm/FrappeKanban.mjs +16 -17
  184. package/dist/esm/FrappeKanban.mjs.map +1 -1
  185. package/dist/esm/FrappeKanban.native.js +18 -21
  186. package/dist/esm/FrappeKanban.native.js.map +1 -1
  187. package/dist/esm/FrappeLikedBy.mjs +1 -1
  188. package/dist/esm/FrappeLikedBy.mjs.map +1 -1
  189. package/dist/esm/FrappeLikedBy.native.js +1 -1
  190. package/dist/esm/FrappeLikedBy.native.js.map +1 -1
  191. package/dist/esm/FrappeList.mjs +2 -2
  192. package/dist/esm/FrappeList.mjs.map +1 -1
  193. package/dist/esm/FrappeList.native.js +2 -2
  194. package/dist/esm/FrappeList.native.js.map +1 -1
  195. package/dist/esm/FrappeListView.native.js.map +1 -1
  196. package/dist/esm/FrappeProvider.mjs.map +1 -1
  197. package/dist/esm/FrappeProvider.native.js.map +1 -1
  198. package/dist/esm/FrappeReconnectIndicator.native.js.map +1 -1
  199. package/dist/esm/FrappeReportBuilder.mjs +2 -2
  200. package/dist/esm/FrappeReportBuilder.mjs.map +1 -1
  201. package/dist/esm/FrappeReportBuilder.native.js +2 -2
  202. package/dist/esm/FrappeReportBuilder.native.js.map +1 -1
  203. package/dist/esm/FrappeReportView.native.js.map +1 -1
  204. package/dist/esm/FrappeTable.mjs +36 -39
  205. package/dist/esm/FrappeTable.mjs.map +1 -1
  206. package/dist/esm/FrappeTable.native.js +39 -40
  207. package/dist/esm/FrappeTable.native.js.map +1 -1
  208. package/dist/esm/FrappeTreeView.mjs +89 -55
  209. package/dist/esm/FrappeTreeView.mjs.map +1 -1
  210. package/dist/esm/FrappeTreeView.native.js +133 -55
  211. package/dist/esm/FrappeTreeView.native.js.map +1 -1
  212. package/dist/esm/SyncErrorNotice.native.js.map +1 -1
  213. package/dist/esm/commentActions.mjs +1 -1
  214. package/dist/esm/commentActions.mjs.map +1 -1
  215. package/dist/esm/commentActions.native.js +1 -1
  216. package/dist/esm/commentActions.native.js.map +1 -1
  217. package/dist/esm/components/attachments.native.js.map +1 -1
  218. package/dist/esm/components/tags.native.js.map +1 -1
  219. package/dist/esm/components/timeline.mjs +1 -1
  220. package/dist/esm/components/timeline.mjs.map +1 -1
  221. package/dist/esm/components/timeline.native.js +1 -1
  222. package/dist/esm/components/timeline.native.js.map +1 -1
  223. package/dist/esm/dependsOn.native.js.map +1 -1
  224. package/dist/esm/desk/DeskFormPage.native.js.map +1 -1
  225. package/dist/esm/desk/DeskFormSidebar.native.js.map +1 -1
  226. package/dist/esm/desk/DeskListPage.native.js.map +1 -1
  227. package/dist/esm/desk/DeskShell.mjs +2 -0
  228. package/dist/esm/desk/DeskShell.mjs.map +1 -1
  229. package/dist/esm/desk/DeskShell.native.js +2 -0
  230. package/dist/esm/desk/DeskShell.native.js.map +1 -1
  231. package/dist/esm/desk/DeskSidebar.native.js.map +1 -1
  232. package/dist/esm/desk/awesomebar.mjs +1 -1
  233. package/dist/esm/desk/awesomebar.mjs.map +1 -1
  234. package/dist/esm/desk/awesomebar.native.js +1 -1
  235. package/dist/esm/desk/awesomebar.native.js.map +1 -1
  236. package/dist/esm/fieldOverrides.native.js.map +1 -1
  237. package/dist/esm/fieldRegistry.native.js.map +1 -1
  238. package/dist/esm/fields/Barcode/index.native.js.map +1 -1
  239. package/dist/esm/fields/Check/index.native.js.map +1 -1
  240. package/dist/esm/fields/CodeEditor/index.native.js.map +1 -1
  241. package/dist/esm/fields/Color/index.native.js.map +1 -1
  242. package/dist/esm/fields/Data/index.native.js.map +1 -1
  243. package/dist/esm/fields/Date/sheetKeyboard.native.js.map +1 -1
  244. package/dist/esm/fields/Date/types.native.js.map +1 -1
  245. package/dist/esm/fields/Date/wire.native.js.map +1 -1
  246. package/dist/esm/fields/DateRange/index.native.js.map +1 -1
  247. package/dist/esm/fields/Duration/index.native.js.map +1 -1
  248. package/dist/esm/fields/DynamicLink.native.js.map +1 -1
  249. package/dist/esm/fields/FileUpload.native.js.map +1 -1
  250. package/dist/esm/fields/FileUploadField/index.native.js.map +1 -1
  251. package/dist/esm/fields/Geolocation/index.native.js.map +1 -1
  252. package/dist/esm/fields/HTML/index.native.js.map +1 -1
  253. package/dist/esm/fields/Heading/index.native.js.map +1 -1
  254. package/dist/esm/fields/Icon/index.native.js.map +1 -1
  255. package/dist/esm/fields/Link.native.js.map +1 -1
  256. package/dist/esm/fields/LinkTree.native.js.map +1 -1
  257. package/dist/esm/fields/LongText/index.native.js.map +1 -1
  258. package/dist/esm/fields/MentionInput/index.mjs +4 -1
  259. package/dist/esm/fields/MentionInput/index.mjs.map +1 -1
  260. package/dist/esm/fields/MentionInput/index.native.js +4 -1
  261. package/dist/esm/fields/MentionInput/index.native.js.map +1 -1
  262. package/dist/esm/fields/Numeric/index.native.js.map +1 -1
  263. package/dist/esm/fields/OTPInput/index.native.js.map +1 -1
  264. package/dist/esm/fields/Password/index.native.js.map +1 -1
  265. package/dist/esm/fields/Phone/index.native.js.map +1 -1
  266. package/dist/esm/fields/Progress/index.native.js.map +1 -1
  267. package/dist/esm/fields/RadioGroup/index.native.js.map +1 -1
  268. package/dist/esm/fields/Rating/index.native.js.map +1 -1
  269. package/dist/esm/fields/ReadOnly/index.native.js.map +1 -1
  270. package/dist/esm/fields/Select/index.native.js.map +1 -1
  271. package/dist/esm/fields/Signature/index.native.js.map +1 -1
  272. package/dist/esm/fields/Slider/index.native.js.map +1 -1
  273. package/dist/esm/fields/SmallText/index.native.js.map +1 -1
  274. package/dist/esm/fields/Switch/index.native.js.map +1 -1
  275. package/dist/esm/fields/TableMultiSelect.native.js.map +1 -1
  276. package/dist/esm/fields/TextEditor/types.native.js.map +1 -1
  277. package/dist/esm/fields/TimePicker/index.native.js.map +1 -1
  278. package/dist/esm/fields/ToggleGroup/index.native.js.map +1 -1
  279. package/dist/esm/fields/shared/EditorPreviewPanes.native.js.map +1 -1
  280. package/dist/esm/filterFields.native.js.map +1 -1
  281. package/dist/esm/formEngine/createPrefill.native.js.map +1 -1
  282. package/dist/esm/formEngine/dirtyTracking.native.js.map +1 -1
  283. package/dist/esm/formEngine/doctypeMeta.native.js.map +1 -1
  284. package/dist/esm/formEngine/fetchFrom.native.js.map +1 -1
  285. package/dist/esm/formEngine/fieldPermissions.native.js.map +1 -1
  286. package/dist/esm/formEngine/formActions.native.js.map +1 -1
  287. package/dist/esm/formEngine/formLayout.native.js.map +1 -1
  288. package/dist/esm/formEngine/index.native.js.map +1 -1
  289. package/dist/esm/formEngine/useFormEngine.native.js.map +1 -1
  290. package/dist/esm/frappeEventColor.native.js.map +1 -1
  291. package/dist/esm/frappeStoryTarget.native.js.map +1 -1
  292. package/dist/esm/frappeUsers.native.js.map +1 -1
  293. package/dist/esm/index.mjs +2 -1
  294. package/dist/esm/index.mjs.map +1 -1
  295. package/dist/esm/index.native.js +2 -1
  296. package/dist/esm/index.native.js.map +1 -1
  297. package/dist/esm/liveErrors.native.js.map +1 -1
  298. package/dist/esm/resolveControl.native.js.map +1 -1
  299. package/dist/esm/schemaForm/SchemaWizard.native.js.map +1 -1
  300. package/dist/esm/schemaForm/applyFieldOrder.native.js.map +1 -1
  301. package/dist/esm/schemaForm/index.mjs +8 -7
  302. package/dist/esm/schemaForm/index.mjs.map +1 -1
  303. package/dist/esm/schemaForm/index.native.js +8 -7
  304. package/dist/esm/schemaForm/index.native.js.map +1 -1
  305. package/dist/esm/shared/devWarn.mjs +14 -0
  306. package/dist/esm/shared/devWarn.mjs.map +1 -0
  307. package/dist/esm/shared/devWarn.native.js +16 -0
  308. package/dist/esm/shared/devWarn.native.js.map +1 -0
  309. package/dist/esm/shared/useKeyboardInset.native.js.map +1 -1
  310. package/dist/esm/syncError.native.js.map +1 -1
  311. package/dist/esm/useFrappeAggregate.mjs +15 -8
  312. package/dist/esm/useFrappeAggregate.mjs.map +1 -1
  313. package/dist/esm/useFrappeAggregate.native.js +15 -9
  314. package/dist/esm/useFrappeAggregate.native.js.map +1 -1
  315. package/dist/esm/useFrappeFacets.mjs +10 -9
  316. package/dist/esm/useFrappeFacets.mjs.map +1 -1
  317. package/dist/esm/useFrappeFacets.native.js +10 -10
  318. package/dist/esm/useFrappeFacets.native.js.map +1 -1
  319. package/dist/esm/useFrappePagination.native.js.map +1 -1
  320. package/dist/esm/useFrappeRows.mjs +86 -0
  321. package/dist/esm/useFrappeRows.mjs.map +1 -0
  322. package/dist/esm/useFrappeRows.native.js +99 -0
  323. package/dist/esm/useFrappeRows.native.js.map +1 -0
  324. package/dist/jsx/FrappeCalendar.mjs +20 -17
  325. package/dist/jsx/FrappeCalendar.mjs.map +1 -1
  326. package/dist/jsx/FrappeCalendar.native.js +22 -21
  327. package/dist/jsx/FrappeCalendar.native.js.map +1 -1
  328. package/dist/jsx/FrappeForm.mjs +1 -1
  329. package/dist/jsx/FrappeForm.mjs.map +1 -1
  330. package/dist/jsx/FrappeForm.native.js +1 -1
  331. package/dist/jsx/FrappeForm.native.js.map +1 -1
  332. package/dist/jsx/FrappeGantt.mjs +27 -36
  333. package/dist/jsx/FrappeGantt.mjs.map +1 -1
  334. package/dist/jsx/FrappeGantt.native.js +27 -38
  335. package/dist/jsx/FrappeGantt.native.js.map +1 -1
  336. package/dist/jsx/FrappeImageView.mjs +5 -3
  337. package/dist/jsx/FrappeImageView.mjs.map +1 -1
  338. package/dist/jsx/FrappeImageView.native.js +8 -4
  339. package/dist/jsx/FrappeImageView.native.js.map +1 -1
  340. package/dist/jsx/FrappeKPICard.mjs +27 -2
  341. package/dist/jsx/FrappeKPICard.mjs.map +1 -1
  342. package/dist/jsx/FrappeKPICard.native.js +26 -1
  343. package/dist/jsx/FrappeKPICard.native.js.map +1 -1
  344. package/dist/jsx/FrappeKanban.mjs +16 -17
  345. package/dist/jsx/FrappeKanban.mjs.map +1 -1
  346. package/dist/jsx/FrappeKanban.native.js +18 -21
  347. package/dist/jsx/FrappeKanban.native.js.map +1 -1
  348. package/dist/jsx/FrappeLikedBy.mjs +1 -1
  349. package/dist/jsx/FrappeLikedBy.mjs.map +1 -1
  350. package/dist/jsx/FrappeLikedBy.native.js +1 -1
  351. package/dist/jsx/FrappeLikedBy.native.js.map +1 -1
  352. package/dist/jsx/FrappeList.mjs +2 -2
  353. package/dist/jsx/FrappeList.mjs.map +1 -1
  354. package/dist/jsx/FrappeList.native.js +2 -2
  355. package/dist/jsx/FrappeList.native.js.map +1 -1
  356. package/dist/jsx/FrappeProvider.mjs.map +1 -1
  357. package/dist/jsx/FrappeProvider.native.js.map +1 -1
  358. package/dist/jsx/FrappeReportBuilder.mjs +2 -2
  359. package/dist/jsx/FrappeReportBuilder.mjs.map +1 -1
  360. package/dist/jsx/FrappeReportBuilder.native.js +2 -2
  361. package/dist/jsx/FrappeReportBuilder.native.js.map +1 -1
  362. package/dist/jsx/FrappeTable.mjs +36 -39
  363. package/dist/jsx/FrappeTable.mjs.map +1 -1
  364. package/dist/jsx/FrappeTable.native.js +38 -39
  365. package/dist/jsx/FrappeTable.native.js.map +1 -1
  366. package/dist/jsx/FrappeTreeView.mjs +89 -55
  367. package/dist/jsx/FrappeTreeView.mjs.map +1 -1
  368. package/dist/jsx/FrappeTreeView.native.js +129 -50
  369. package/dist/jsx/FrappeTreeView.native.js.map +1 -1
  370. package/dist/jsx/commentActions.mjs +1 -1
  371. package/dist/jsx/commentActions.mjs.map +1 -1
  372. package/dist/jsx/commentActions.native.js +1 -1
  373. package/dist/jsx/commentActions.native.js.map +1 -1
  374. package/dist/jsx/components/timeline.mjs +1 -1
  375. package/dist/jsx/components/timeline.mjs.map +1 -1
  376. package/dist/jsx/components/timeline.native.js +1 -1
  377. package/dist/jsx/desk/DeskShell.mjs +2 -0
  378. package/dist/jsx/desk/DeskShell.mjs.map +1 -1
  379. package/dist/jsx/desk/DeskShell.native.js +2 -0
  380. package/dist/jsx/desk/DeskShell.native.js.map +1 -1
  381. package/dist/jsx/desk/awesomebar.mjs +1 -1
  382. package/dist/jsx/desk/awesomebar.mjs.map +1 -1
  383. package/dist/jsx/desk/awesomebar.native.js +1 -1
  384. package/dist/jsx/desk/awesomebar.native.js.map +1 -1
  385. package/dist/jsx/fields/MentionInput/index.mjs +4 -1
  386. package/dist/jsx/fields/MentionInput/index.mjs.map +1 -1
  387. package/dist/jsx/fields/MentionInput/index.native.js +4 -1
  388. package/dist/jsx/fields/MentionInput/index.native.js.map +1 -1
  389. package/dist/jsx/index.js +2 -1
  390. package/dist/jsx/index.js.map +1 -1
  391. package/dist/jsx/index.mjs +2 -1
  392. package/dist/jsx/index.mjs.map +1 -1
  393. package/dist/jsx/index.native.js +4 -0
  394. package/dist/jsx/index.native.js.map +1 -1
  395. package/dist/jsx/schemaForm/index.mjs +8 -7
  396. package/dist/jsx/schemaForm/index.mjs.map +1 -1
  397. package/dist/jsx/schemaForm/index.native.js +10 -9
  398. package/dist/jsx/schemaForm/index.native.js.map +1 -1
  399. package/dist/jsx/shared/devWarn.mjs +14 -0
  400. package/dist/jsx/shared/devWarn.mjs.map +1 -0
  401. package/dist/jsx/shared/devWarn.native.js +45 -0
  402. package/dist/jsx/shared/devWarn.native.js.map +1 -0
  403. package/dist/jsx/useFrappeAggregate.mjs +15 -8
  404. package/dist/jsx/useFrappeAggregate.mjs.map +1 -1
  405. package/dist/jsx/useFrappeAggregate.native.js +15 -9
  406. package/dist/jsx/useFrappeAggregate.native.js.map +1 -1
  407. package/dist/jsx/useFrappeFacets.mjs +10 -9
  408. package/dist/jsx/useFrappeFacets.mjs.map +1 -1
  409. package/dist/jsx/useFrappeFacets.native.js +10 -10
  410. package/dist/jsx/useFrappeFacets.native.js.map +1 -1
  411. package/dist/jsx/useFrappeRows.mjs +86 -0
  412. package/dist/jsx/useFrappeRows.mjs.map +1 -0
  413. package/dist/jsx/useFrappeRows.native.js +129 -0
  414. package/dist/jsx/useFrappeRows.native.js.map +1 -0
  415. package/package.json +17 -16
  416. package/src/FileBrowser/FileBrowser.spec.tsx +11 -1
  417. package/src/FrappeCalendar.tsx +25 -22
  418. package/src/FrappeForm.tsx +7 -3
  419. package/src/FrappeGantt.tsx +29 -39
  420. package/src/FrappeImageView.tsx +5 -3
  421. package/src/FrappeKPICard.spec.tsx +128 -0
  422. package/src/FrappeKPICard.tsx +44 -4
  423. package/src/FrappeKanban.tsx +24 -17
  424. package/src/FrappeLikedBy.tsx +1 -1
  425. package/src/FrappeList.tsx +3 -2
  426. package/src/FrappeProvider.fixturesOnly.spec.tsx +129 -0
  427. package/src/FrappeProvider.tsx +16 -6
  428. package/src/FrappeReportBuilder.tsx +4 -2
  429. package/src/FrappeTable.autoHeight.spec.tsx +142 -0
  430. package/src/FrappeTable.rowAccumulator.spec.tsx +110 -0
  431. package/src/FrappeTable.tsx +75 -48
  432. package/src/FrappeTreeView.stories.tsx +59 -0
  433. package/src/FrappeTreeView.tsx +166 -56
  434. package/src/commentActions.ts +1 -1
  435. package/src/components/timeline.tsx +1 -1
  436. package/src/desk/DeskShell.tsx +2 -0
  437. package/src/desk/awesomebar.tsx +5 -2
  438. package/src/fields/CodeEditor/CodeEditor.spec.tsx +10 -9
  439. package/src/fields/Date/typeParity.spec.tsx +19 -9
  440. package/src/fields/Duration/Duration.spec.tsx +73 -0
  441. package/src/fields/MentionInput/MentionInput.spec.tsx +110 -0
  442. package/src/fields/MentionInput/index.tsx +4 -1
  443. package/src/fields/Password/index.tsx +1 -1
  444. package/src/fields/Progress/Progress.spec.tsx +9 -0
  445. package/src/fields/RadioGroup/RadioGroup.spec.tsx +93 -0
  446. package/src/fields/Signature/Signature.spec.tsx +105 -0
  447. package/src/fields/Slider/Slider.spec.tsx +73 -0
  448. package/src/fields/Switch/Switch.spec.tsx +65 -0
  449. package/src/fields/TextEditor/TextEditor.spec.tsx +2 -3
  450. package/src/fields/TextEditor/TextEditor.stories.tsx +31 -1
  451. package/src/fields/ToggleGroup/ToggleGroup.spec.tsx +110 -0
  452. package/src/frappeViews.designLaw.spec.ts +11 -7
  453. package/src/index.ts +13 -0
  454. package/src/schemaForm/index.tsx +6 -7
  455. package/src/shared/devWarn.ts +42 -0
  456. package/src/useFrappeAggregate.ts +17 -11
  457. package/src/useFrappeFacets.ts +17 -10
  458. package/src/useFrappeRows.spec.tsx +176 -0
  459. package/src/useFrappeRows.ts +293 -0
  460. package/types/FrappeCalendar.d.ts.map +1 -1
  461. package/types/FrappeForm.d.ts +6 -2
  462. package/types/FrappeForm.d.ts.map +1 -1
  463. package/types/FrappeGantt.d.ts.map +1 -1
  464. package/types/FrappeImageView.d.ts.map +1 -1
  465. package/types/FrappeKPICard.d.ts +9 -1
  466. package/types/FrappeKPICard.d.ts.map +1 -1
  467. package/types/FrappeKanban.d.ts.map +1 -1
  468. package/types/FrappeList.d.ts.map +1 -1
  469. package/types/FrappeProvider.d.ts +16 -6
  470. package/types/FrappeProvider.d.ts.map +1 -1
  471. package/types/FrappeReportBuilder.d.ts.map +1 -1
  472. package/types/FrappeTable.d.ts +20 -1
  473. package/types/FrappeTable.d.ts.map +1 -1
  474. package/types/FrappeTreeView.d.ts +38 -1
  475. package/types/FrappeTreeView.d.ts.map +1 -1
  476. package/types/desk/DeskShell.d.ts.map +1 -1
  477. package/types/desk/awesomebar.d.ts.map +1 -1
  478. package/types/fields/MentionInput/index.d.ts.map +1 -1
  479. package/types/fields/Password/index.d.ts +1 -1
  480. package/types/fields/Password/index.d.ts.map +1 -1
  481. package/types/index.d.ts +1 -0
  482. package/types/index.d.ts.map +1 -1
  483. package/types/schemaForm/index.d.ts.map +1 -1
  484. package/types/shared/devWarn.d.ts +23 -0
  485. package/types/shared/devWarn.d.ts.map +1 -0
  486. package/types/useFrappeAggregate.d.ts +2 -1
  487. package/types/useFrappeAggregate.d.ts.map +1 -1
  488. package/types/useFrappeFacets.d.ts +2 -1
  489. package/types/useFrappeFacets.d.ts.map +1 -1
  490. package/types/useFrappeRows.d.ts +186 -0
  491. package/types/useFrappeRows.d.ts.map +1 -0
@@ -55,14 +55,15 @@ describe("Frappe view adapters — design-law 100%", () => {
55
55
  expect(source).toMatch(/from "@multiplatform.one\/components"/);
56
56
  });
57
57
 
58
- it("FrappeGantt action banners use form ramps and do not steal Desk assembly", () => {
58
+ it("FrappeGantt action errors use Alert and keep the adapter boundary", () => {
59
59
  const source = read("FrappeGantt.tsx");
60
- expect(source).toContain("formCommonColors");
60
+ expect(source).toMatch(/import \{[^}]*Alert[^}]*\} from "@multiplatform.one\/components"/);
61
+ expect(source).toMatch(/<Alert\b[^>]*intent="error"/);
61
62
  expect(source).toContain("containerRadius");
63
+ expect(source).not.toContain("knobProps.borderRadius");
62
64
  expect(source).not.toMatch(/fontSize=\{knobProps\.sizeToken\}/);
63
- expect(source).not.toContain('color="$red11"');
64
- expect(source).toContain("BACKOFFICE_VIEWS");
65
- expect(source).toContain("MPO-14");
65
+ expect(source).not.toMatch(/\$red\d+/);
66
+ expect(source).not.toMatch(/from ["'](?:@multiplatform\.one\/backoffice|\.\/desk\/)/);
66
67
  });
67
68
 
68
69
  it("FrappeReportView uses the house Button and label fragments (LC-54)", () => {
@@ -81,12 +82,15 @@ describe("Frappe view adapters — design-law 100%", () => {
81
82
  expect(source).toContain("formCommonColors");
82
83
  expect(source).not.toMatch(/fontWeight="600"|fontWeight="500"/);
83
84
  expect(source).toContain('fontWeight="400"');
84
- expect(source).toContain("outlined");
85
+ expect(source).not.toMatch(/<Button\b[^>]*\b(?:controlFill|backgroundColor|borderColor)=/);
85
86
  });
86
87
 
87
88
  it("FrappeTreeView empty chrome is EmptyState and labels use the label fragment", () => {
88
89
  const source = read("FrappeTreeView.tsx");
89
- expect(source).toContain("EmptyState");
90
+ expect(source).toMatch(/import \{[^}]*EmptyState[^}]*\} from "@multiplatform.one\/components"/);
91
+ expect(source).toContain("<EmptyState");
92
+ expect(source).toContain("useGlyphColor(formCommonColors.muted)");
93
+ expect(source).not.toMatch(/<TreeStructureIcon\b[^>]*color=\{formCommonColors\./);
90
94
  expect(source).not.toMatch(/size=\{48\}/);
91
95
  expect(source).toContain("knobProps.label");
92
96
  expect(source).not.toMatch(/fontSize=\{display === "compressed" \? 12 : 14\}/);
package/src/index.ts CHANGED
@@ -120,6 +120,19 @@ export {
120
120
  type FrappeChartDataSource,
121
121
  } from "./FrappeChartCard";
122
122
 
123
+ // The composed doctype read (MPO-251) — the supported way to get rows out of
124
+ // a doctype when the panel shape has no shipped component. FrappeTable and
125
+ // the other live views read through it, so there is one implementation.
126
+ export {
127
+ useFrappeRows,
128
+ useFrappeConnection,
129
+ DEFAULT_FRAPPE_ROWS_LIMIT,
130
+ type FrappeRowsConnection,
131
+ type FrappeRowsMessages,
132
+ type UseFrappeRowsOptions,
133
+ type UseFrappeRowsResult,
134
+ } from "./useFrappeRows";
135
+
123
136
  export {
124
137
  useFrappeAggregate,
125
138
  type FrappeAggregateConnection,
@@ -17,9 +17,10 @@ import {
17
17
  type RequiredMarkStrategy,
18
18
  } from "@multiplatform.one/forms";
19
19
  import { useResolvedKnobs } from "@multiplatform.one/theme";
20
+ import { Card } from "@multiplatform.one/components";
20
21
  import React, { useMemo } from "react";
21
22
  import { useTranslation } from "react-i18next";
22
- import { Card, Text, XStack, YStack } from "tamagui";
23
+ import { Text, XStack, YStack } from "tamagui";
23
24
 
24
25
  import { compileDependsOn } from "../dependsOn";
25
26
  import { Heading, type HeadingLevel } from "../fields/Heading";
@@ -353,13 +354,12 @@ function SchemaFormSectionCard({ section, headingLevel, renderField }: SchemaFor
353
354
 
354
355
  return (
355
356
  <Card
356
- borderWidth={hideBorder ? 0 : 1}
357
- borderColor="$borderColor"
358
- size={knobProps.sizeToken}
359
- backgroundColor={hideBorder ? "transparent" : undefined}
357
+ data-mpo-schema-form-card=""
358
+ data-mpo-schema-form-borderless={hideBorder ? "" : undefined}
359
+ {...(hideBorder ? { borderWidth: 0, backgroundColor: "transparent" } : {})}
360
360
  >
361
361
  {(section.label || section.description) && (
362
- <Card.Header {...knobProps.panelPadding}>
362
+ <Card.Header>
363
363
  {section.label ? (
364
364
  <Heading
365
365
  label={section.label}
@@ -380,7 +380,6 @@ function SchemaFormSectionCard({ section, headingLevel, renderField }: SchemaFor
380
380
  {/* Kept mounted while collapsed (display none) so field state and the
381
381
  collapse target survive toggles — matches desk's CSS hide. */}
382
382
  <Card.Footer
383
- {...knobProps.panelPadding}
384
383
  display={effectiveCollapsed ? "none" : undefined}
385
384
  aria-hidden={effectiveCollapsed || undefined}
386
385
  >
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Package-local DEV guardrails for frappe-ui, warned under a `[frappe-ui]`
3
+ * prefix.
4
+ *
5
+ * The canonical catalog is `devWarn` in `@multiplatform.one/theme`, whose
6
+ * `DevWarnCode` union is closed over design-guardrail codes. Live-data
7
+ * misconfiguration is a frappe-ui concern rather than a design-law one, so
8
+ * it warns from here, the same way AsyncBoundary keeps its own.
9
+ *
10
+ * No-ops when `NODE_ENV === "production"`, and each key warns once per
11
+ * process so a re-render never repeats a line.
12
+ */
13
+
14
+ export type FrappeDevWarnCode = "kpi-datasource-without-baseurl";
15
+
16
+ export type FrappeDevWarnDetail = {
17
+ component?: string;
18
+ id?: string;
19
+ doctype?: string;
20
+ suggest?: string;
21
+ };
22
+
23
+ const seen = new Set<string>();
24
+
25
+ export function frappeDevWarn(code: FrappeDevWarnCode, detail: FrappeDevWarnDetail = {}): void {
26
+ if (process.env.NODE_ENV === "production") return;
27
+ const key = [code, detail.component ?? "", detail.id ?? "", detail.doctype ?? ""].join(":");
28
+ if (seen.has(key)) return;
29
+ seen.add(key);
30
+ const bits = [
31
+ detail.component ? `component=${detail.component}` : undefined,
32
+ detail.id ? `id=${detail.id}` : undefined,
33
+ detail.doctype ? `doctype=${detail.doctype}` : undefined,
34
+ detail.suggest ? `suggest=${detail.suggest}` : undefined,
35
+ ].filter(Boolean);
36
+ console.warn(`[frappe-ui] ${code}${bits.length ? ` (${bits.join(", ")})` : ""}`);
37
+ }
38
+
39
+ /** @internal test helper */
40
+ export function __resetFrappeDevWarnSeen(): void {
41
+ seen.clear();
42
+ }
@@ -41,7 +41,8 @@ export type FrappeAggregateOperation = "count" | "sum" | "avg" | "min" | "max";
41
41
 
42
42
  /** Connection shape shared with the other frappe-ui widgets. */
43
43
  export interface FrappeAggregateConnection {
44
- baseURL: string;
44
+ /** Required unless `fixtures` is set (see FrappeConfig.baseURL). */
45
+ baseURL?: string;
45
46
  /** False keeps HTTP reads without realtime subscriptions. */
46
47
  realtime?: boolean;
47
48
  socketPort?: number;
@@ -97,18 +98,18 @@ const DEFAULT_DEBOUNCE_MS = 300;
97
98
  // One REST client per connection — widgets sharing a bench share it.
98
99
  const dbCache = new Map<string, DbModule>();
99
100
 
100
- function getDb(connection: FrappeAggregateConnection): DbModule {
101
- const key = `${connection.baseURL}:${connection.auth?.token ?? ""}:${connection.auth?.type ?? ""}`;
101
+ function getDb(baseURL: string, auth: FrappeAggregateConnection["auth"]): DbModule {
102
+ const key = `${baseURL}:${auth?.token ?? ""}:${auth?.type ?? ""}`;
102
103
  let db = dbCache.get(key);
103
104
  if (!db) {
104
- const authConfig: AuthConfig | undefined = connection.auth
105
+ const authConfig: AuthConfig | undefined = auth
105
106
  ? {
106
- useToken: connection.auth.useToken,
107
- token: connection.auth.token,
108
- type: connection.auth.type as AuthConfig["type"],
107
+ useToken: auth.useToken,
108
+ token: auth.token,
109
+ type: auth.type as AuthConfig["type"],
109
110
  }
110
111
  : undefined;
111
- db = new DbModule(new HttpClient(connection.baseURL, authConfig));
112
+ db = new DbModule(new HttpClient(baseURL, authConfig));
112
113
  dbCache.set(key, db);
113
114
  }
114
115
  return db;
@@ -271,9 +272,14 @@ export function useFrappeAggregate(
271
272
  if (!conn || !currentSpec.doctype) return;
272
273
  const seq = ++fetchSeq.current;
273
274
  try {
274
- const result = conn.fixtures
275
- ? await fetchFixtureAggregate(conn.fixtures, currentSpec)
276
- : await fetchLiveAggregate(getDb(conn), currentSpec);
275
+ let result: AggregateData;
276
+ if (conn.fixtures) {
277
+ result = await fetchFixtureAggregate(conn.fixtures, currentSpec);
278
+ } else if (conn.baseURL) {
279
+ result = await fetchLiveAggregate(getDb(conn.baseURL, conn.auth), currentSpec);
280
+ } else {
281
+ throw new Error("useFrappeAggregate requires a connection with baseURL or fixtures");
282
+ }
277
283
  if (seq !== fetchSeq.current) return; // stale response — a newer fetch won
278
284
  setData(result);
279
285
  setError(undefined);
@@ -78,7 +78,8 @@ export interface FrappeFacetState {
78
78
 
79
79
  /** Connection shape shared with the other frappe-ui widgets. */
80
80
  export interface FrappeFacetsConnection {
81
- baseURL: string;
81
+ /** Required unless `fixtures` is set (see FrappeConfig.baseURL). */
82
+ baseURL?: string;
82
83
  auth?: { useToken?: boolean; token?: string | (() => string | Promise<string>); type?: string };
83
84
  fixtures?: FixtureProvider;
84
85
  }
@@ -169,18 +170,18 @@ export function scrubUserFacetRows(
169
170
  // One RPC client per connection — facets sharing a bench share it.
170
171
  const callCache = new Map<string, CallModule>();
171
172
 
172
- function getCall(connection: FrappeFacetsConnection): CallModule {
173
- const key = `${connection.baseURL}:${connection.auth?.token ?? ""}:${connection.auth?.type ?? ""}`;
173
+ function getCall(baseURL: string, auth: FrappeFacetsConnection["auth"]): CallModule {
174
+ const key = `${baseURL}:${auth?.token ?? ""}:${auth?.type ?? ""}`;
174
175
  let call = callCache.get(key);
175
176
  if (!call) {
176
- const authConfig: AuthConfig | undefined = connection.auth
177
+ const authConfig: AuthConfig | undefined = auth
177
178
  ? {
178
- useToken: connection.auth.useToken,
179
- token: connection.auth.token,
180
- type: connection.auth.type as AuthConfig["type"],
179
+ useToken: auth.useToken,
180
+ token: auth.token,
181
+ type: auth.type as AuthConfig["type"],
181
182
  }
182
183
  : undefined;
183
- call = new CallModule(new HttpClient(connection.baseURL, authConfig));
184
+ call = new CallModule(new HttpClient(baseURL, authConfig));
184
185
  callCache.set(key, call);
185
186
  }
186
187
  return call;
@@ -439,7 +440,9 @@ export function useFrappeFacets(
439
440
  useEffect(() => {
440
441
  if (!enabled) return;
441
442
  const conn = connectionRef.current;
442
- if (!conn) return;
443
+ // Neither a corpus nor a bench can answer, so stay idle instead of
444
+ // entering a loading state nothing will ever resolve.
445
+ if (!conn || (!conn.fixtures && !conn.baseURL)) return;
443
446
  const seq = ++fetchSeq.current;
444
447
  const activeFilters = JSON.parse(filtersKey) as FrappeFacetFilters;
445
448
 
@@ -525,7 +528,11 @@ export function useFrappeFacets(
525
528
  return;
526
529
  }
527
530
 
528
- const call = getCall(conn);
531
+ // Narrowing only: the guard at the top of the effect already returned
532
+ // when neither a corpus nor a baseURL is configured.
533
+ if (!conn.baseURL) return;
534
+
535
+ const call = getCall(conn.baseURL, conn.auth);
529
536
  fetchGroupByCount(call, doctype, filtersExcludingField(activeFilters, "_assign"), "assigned_to")
530
537
  .then((rows) => done("assigned", rows))
531
538
  .catch((error) => fail("assigned", error));
@@ -0,0 +1,176 @@
1
+ /**
2
+ * useFrappeRows — the composed doctype read (MPO-251).
3
+ *
4
+ * What this locks:
5
+ * 1. rows / isLoading / error come back from one hook, so a panel with no
6
+ * shipped component does not re-derive the read.
7
+ * 2. A 403 or an unreachable server surfaces as an ERROR, not as an empty
8
+ * result — the trap the copies each had to remember.
9
+ * 3. `limit` is defaulted by the hook (DEFAULT_FRAPPE_ROWS_LIMIT), with
10
+ * `limit: null` as the explicit bench-default opt-out FrappeTable takes.
11
+ * 4. Collection sharing is keyed on the options JSON: the same field list
12
+ * shares one collection, a different one does not.
13
+ *
14
+ * Fixture-hermetic: documents ride InMemoryFixtureProvider, so nothing
15
+ * dials a baseURL.
16
+ */
17
+
18
+ import { InMemoryFixtureProvider, useFrappeCollection } from "@multiplatform.one/frappe";
19
+ import { renderWithProviders } from "@multiplatform.one/test-utils";
20
+ import { cleanup, waitFor } from "@testing-library/react";
21
+ import { afterEach, describe, expect, it, vi } from "vitest";
22
+ import { FrappeProvider } from "./FrappeProvider";
23
+ import { DEFAULT_FRAPPE_ROWS_LIMIT, useFrappeConnection, useFrappeRows } from "./useFrappeRows";
24
+
25
+ afterEach(() => {
26
+ cleanup();
27
+ vi.restoreAllMocks();
28
+ });
29
+
30
+ interface Account {
31
+ name: string;
32
+ doctype: string;
33
+ account: string;
34
+ balance: string;
35
+ }
36
+
37
+ const accounts: Account[] = [
38
+ { name: "ACC-001", doctype: "Account", account: "Assets:Cash", balance: "10.00" },
39
+ { name: "ACC-002", doctype: "Account", account: "Assets:Bank", balance: "9.00" },
40
+ ];
41
+
42
+ const accountFields = ["name", "account", "balance"] as const;
43
+
44
+ function Harness({
45
+ onResult,
46
+ ...options
47
+ }: {
48
+ onResult: (result: ReturnType<typeof useFrappeRows<Account>>) => void;
49
+ } & Parameters<typeof useFrappeRows<Account>>[2]) {
50
+ const connection = useFrappeConnection();
51
+ const result = useFrappeRows<Account>(connection, "Account", options);
52
+ onResult(result);
53
+ return null;
54
+ }
55
+
56
+ function renderHarness(
57
+ options: Parameters<typeof useFrappeRows<Account>>[2] = {},
58
+ fixtures = new InMemoryFixtureProvider({ Account: accounts }),
59
+ ) {
60
+ const results: Array<ReturnType<typeof useFrappeRows<Account>>> = [];
61
+ const utils = renderWithProviders(
62
+ <FrappeProvider baseURL="https://userows.spec.test" fixtures={fixtures}>
63
+ <Harness onResult={(r) => results.push(r)} {...options} />
64
+ </FrappeProvider>,
65
+ );
66
+ return { results, last: () => results[results.length - 1]!, ...utils };
67
+ }
68
+
69
+ describe("useFrappeRows", () => {
70
+ it("reads a doctype into rows", async () => {
71
+ const { last } = renderHarness({ fields: accountFields });
72
+ await waitFor(() => expect(last().rows).toHaveLength(2));
73
+ expect(last().rows.map((r) => r.name)).toEqual(["ACC-001", "ACC-002"]);
74
+ expect(last().isLoading).toBe(false);
75
+ expect(last().error).toBeNull();
76
+ });
77
+
78
+ it("parks on enabled: false — no rows, not loading", () => {
79
+ const { last } = renderHarness({ fields: accountFields, enabled: false });
80
+ expect(last().rows).toEqual([]);
81
+ expect(last().isLoading).toBe(false);
82
+ expect(last().collection).toBeUndefined();
83
+ });
84
+
85
+ it("surfaces a permission rejection as an error rather than an empty result", async () => {
86
+ const fixtures = new InMemoryFixtureProvider({ Account: accounts });
87
+ vi.spyOn(fixtures, "getList").mockRejectedValue(
88
+ Object.assign(new Error("PermissionError"), { status: 403 }),
89
+ );
90
+ const { last } = renderHarness(
91
+ {
92
+ fields: accountFields,
93
+ messages: { permission: "No permission for Account", generic: "Error loading Account" },
94
+ },
95
+ fixtures,
96
+ );
97
+ await waitFor(() => expect(last().error).toBeInstanceOf(Error));
98
+ expect(last().error?.message).toContain("No permission for Account");
99
+ expect(last().rows).toEqual([]);
100
+ });
101
+
102
+ it("surfaces an unreachable server as an error rather than an empty result", async () => {
103
+ const fixtures = new InMemoryFixtureProvider({ Account: accounts });
104
+ vi.spyOn(fixtures, "getList").mockRejectedValue(new Error("Failed to fetch"));
105
+ const { last } = renderHarness(
106
+ {
107
+ fields: accountFields,
108
+ messages: { permission: "No permission for Account", generic: "Error loading Account" },
109
+ },
110
+ fixtures,
111
+ );
112
+ await waitFor(() => expect(last().error).toBeInstanceOf(Error));
113
+ expect(last().error?.message).toContain("Error loading Account");
114
+ });
115
+
116
+ it("defaults the limit rather than leaving it to the caller", () => {
117
+ // Two readers of the same doctype: one taking the default limit, one
118
+ // passing null (the bench-default opt-out). The options JSON is the
119
+ // collection cache key and `limit` is part of it, so a differing limit
120
+ // must produce a DIFFERENT collection.
121
+ const fixtures = new InMemoryFixtureProvider({ Account: accounts });
122
+ const seen: Array<unknown> = [];
123
+ function TwoReaders() {
124
+ const connection = useFrappeConnection();
125
+ const defaulted = useFrappeRows<Account>(connection, "Account", { fields: accountFields });
126
+ const benchDefault = useFrappeRows<Account>(connection, "Account", {
127
+ fields: accountFields,
128
+ limit: null,
129
+ });
130
+ const explicit = useFrappeRows<Account>(connection, "Account", {
131
+ fields: accountFields,
132
+ limit: DEFAULT_FRAPPE_ROWS_LIMIT,
133
+ });
134
+ seen.push([defaulted.collection, benchDefault.collection, explicit.collection]);
135
+ return null;
136
+ }
137
+ renderWithProviders(
138
+ <FrappeProvider baseURL="https://userows.spec.test" fixtures={fixtures}>
139
+ <TwoReaders />
140
+ </FrappeProvider>,
141
+ );
142
+ const [defaulted, benchDefault, explicit] = seen[seen.length - 1] as unknown[];
143
+ expect(defaulted).toBeDefined();
144
+ expect(defaulted, "omitting limit is the same query as passing the default").toBe(explicit);
145
+ expect(benchDefault, "limit: null is a different query — no limit at all").not.toBe(defaulted);
146
+ });
147
+
148
+ it("shares one collection with an identical field list and splits on a different one", () => {
149
+ const fixtures = new InMemoryFixtureProvider({ Account: accounts });
150
+ const seen: Array<unknown[]> = [];
151
+ function ThreeReaders() {
152
+ const connection = useFrappeConnection();
153
+ const a = useFrappeRows<Account>(connection, "Account", { fields: accountFields });
154
+ const b = useFrappeRows<Account>(connection, "Account", {
155
+ fields: ["name", "account", "balance"],
156
+ });
157
+ const c = useFrappeRows<Account>(connection, "Account", { fields: ["name", "account"] });
158
+ seen.push([a.collection, b.collection, c.collection]);
159
+ return null;
160
+ }
161
+ renderWithProviders(
162
+ <FrappeProvider baseURL="https://userows.spec.test" fixtures={fixtures}>
163
+ <ThreeReaders />
164
+ </FrappeProvider>,
165
+ );
166
+ const [a, b, c] = seen[seen.length - 1]!;
167
+ expect(a, "same field list shares one collection").toBe(b);
168
+ expect(c, "a field list short by one entry does NOT share").not.toBe(a);
169
+ });
170
+
171
+ it("is the same primitive FrappeTable's read was built on", () => {
172
+ // Guardrail against the hook drifting away from useFrappeCollection —
173
+ // the point of MPO-251 is ONE implementation, not a second one.
174
+ expect(typeof useFrappeCollection).toBe("function");
175
+ });
176
+ });