@multiplatform.one/frappe-ui 7.11.0 → 7.16.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 (366) hide show
  1. package/README.md +2 -2
  2. package/dist/cjs/FrappeCalendar.cjs +1 -0
  3. package/dist/cjs/FrappeCalendar.native.js +1 -0
  4. package/dist/cjs/FrappeCalendar.native.js.map +1 -1
  5. package/dist/cjs/FrappeDashboard.cjs +8 -10
  6. package/dist/cjs/FrappeDashboard.native.js +8 -14
  7. package/dist/cjs/FrappeDashboard.native.js.map +1 -1
  8. package/dist/cjs/FrappeForm.cjs +465 -175
  9. package/dist/cjs/FrappeForm.native.js +611 -207
  10. package/dist/cjs/FrappeForm.native.js.map +1 -1
  11. package/dist/cjs/FrappeFormConnections.cjs +125 -0
  12. package/dist/cjs/FrappeFormConnections.native.js +149 -0
  13. package/dist/cjs/FrappeFormConnections.native.js.map +1 -0
  14. package/dist/cjs/FrappeImageView.cjs +7 -9
  15. package/dist/cjs/FrappeImageView.native.js +7 -13
  16. package/dist/cjs/FrappeImageView.native.js.map +1 -1
  17. package/dist/cjs/FrappeList.cjs +29 -4
  18. package/dist/cjs/FrappeList.native.js +37 -5
  19. package/dist/cjs/FrappeList.native.js.map +1 -1
  20. package/dist/cjs/FrappeListView.cjs +102 -29
  21. package/dist/cjs/FrappeListView.native.js +109 -29
  22. package/dist/cjs/FrappeListView.native.js.map +1 -1
  23. package/dist/cjs/FrappeProvider.cjs +7 -2
  24. package/dist/cjs/FrappeProvider.native.js +7 -2
  25. package/dist/cjs/FrappeProvider.native.js.map +1 -1
  26. package/dist/cjs/FrappeReportBuilder.cjs +10 -11
  27. package/dist/cjs/FrappeReportBuilder.native.js +10 -16
  28. package/dist/cjs/FrappeReportBuilder.native.js.map +1 -1
  29. package/dist/cjs/FrappeRowsReader.cjs +49 -0
  30. package/dist/cjs/FrappeRowsReader.native.js +53 -0
  31. package/dist/cjs/FrappeRowsReader.native.js.map +1 -0
  32. package/dist/cjs/FrappeTable.cjs +18 -6
  33. package/dist/cjs/FrappeTable.native.js +24 -6
  34. package/dist/cjs/FrappeTable.native.js.map +1 -1
  35. package/dist/cjs/fieldRegistry.cjs +36 -11
  36. package/dist/cjs/fieldRegistry.native.js +59 -11
  37. package/dist/cjs/fieldRegistry.native.js.map +1 -1
  38. package/dist/cjs/fields/Date/index.native.js +5 -2
  39. package/dist/cjs/fields/Date/index.native.js.map +1 -1
  40. package/dist/cjs/fields/Date/sheetKeyboard.cjs +2 -2
  41. package/dist/cjs/fields/Date/sheetKeyboard.native.js +2 -2
  42. package/dist/cjs/fields/Date/sheetKeyboard.native.js.map +1 -1
  43. package/dist/cjs/fields/DateRange/index.cjs +2 -1
  44. package/dist/cjs/fields/DateRange/index.native.js +4 -1
  45. package/dist/cjs/fields/DateRange/index.native.js.map +1 -1
  46. package/dist/cjs/fields/Password/index.cjs +1 -1
  47. package/dist/cjs/fields/Password/index.native.js +1 -1
  48. package/dist/cjs/formEngine/index.cjs +4 -2
  49. package/dist/cjs/formEngine/index.native.js +3 -1
  50. package/dist/cjs/formEngine/index.native.js.map +1 -1
  51. package/dist/cjs/formEngine/useSessionRoles.cjs +77 -0
  52. package/dist/cjs/formEngine/useSessionRoles.native.js +84 -0
  53. package/dist/cjs/formEngine/useSessionRoles.native.js.map +1 -0
  54. package/dist/cjs/frappeConnections.cjs +41 -0
  55. package/dist/cjs/frappeConnections.native.js +50 -0
  56. package/dist/cjs/frappeConnections.native.js.map +1 -0
  57. package/dist/cjs/frappeNavigation.cjs +107 -0
  58. package/dist/cjs/frappeNavigation.native.js +112 -0
  59. package/dist/cjs/frappeNavigation.native.js.map +1 -0
  60. package/dist/cjs/index.cjs +18 -1
  61. package/dist/cjs/index.native.js +18 -1
  62. package/dist/cjs/index.native.js.map +1 -1
  63. package/dist/cjs/schemaForm/index.cjs +4 -1
  64. package/dist/cjs/schemaForm/index.native.js +4 -1
  65. package/dist/cjs/schemaForm/index.native.js.map +1 -1
  66. package/dist/cjs/useConnectionFilters.cjs +146 -0
  67. package/dist/cjs/useConnectionFilters.native.js +213 -0
  68. package/dist/cjs/useConnectionFilters.native.js.map +1 -0
  69. package/dist/cjs/useFrappePagination.cjs +37 -18
  70. package/dist/cjs/useFrappePagination.native.js +59 -23
  71. package/dist/cjs/useFrappePagination.native.js.map +1 -1
  72. package/dist/cjs/useFrappeRows.native.js.map +1 -1
  73. package/dist/esm/FrappeCalendar.mjs +1 -0
  74. package/dist/esm/FrappeCalendar.mjs.map +1 -1
  75. package/dist/esm/FrappeCalendar.native.js +1 -0
  76. package/dist/esm/FrappeCalendar.native.js.map +1 -1
  77. package/dist/esm/FrappeDashboard.mjs +9 -11
  78. package/dist/esm/FrappeDashboard.mjs.map +1 -1
  79. package/dist/esm/FrappeDashboard.native.js +9 -15
  80. package/dist/esm/FrappeDashboard.native.js.map +1 -1
  81. package/dist/esm/FrappeForm.mjs +471 -181
  82. package/dist/esm/FrappeForm.mjs.map +1 -1
  83. package/dist/esm/FrappeForm.native.js +599 -195
  84. package/dist/esm/FrappeForm.native.js.map +1 -1
  85. package/dist/esm/FrappeFormConnections.mjs +99 -0
  86. package/dist/esm/FrappeFormConnections.mjs.map +1 -0
  87. package/dist/esm/FrappeFormConnections.native.js +120 -0
  88. package/dist/esm/FrappeFormConnections.native.js.map +1 -0
  89. package/dist/esm/FrappeImageView.mjs +8 -10
  90. package/dist/esm/FrappeImageView.mjs.map +1 -1
  91. package/dist/esm/FrappeImageView.native.js +8 -14
  92. package/dist/esm/FrappeImageView.native.js.map +1 -1
  93. package/dist/esm/FrappeList.mjs +31 -6
  94. package/dist/esm/FrappeList.mjs.map +1 -1
  95. package/dist/esm/FrappeList.native.js +39 -7
  96. package/dist/esm/FrappeList.native.js.map +1 -1
  97. package/dist/esm/FrappeListView.mjs +103 -30
  98. package/dist/esm/FrappeListView.mjs.map +1 -1
  99. package/dist/esm/FrappeListView.native.js +110 -30
  100. package/dist/esm/FrappeListView.native.js.map +1 -1
  101. package/dist/esm/FrappeProvider.mjs +7 -2
  102. package/dist/esm/FrappeProvider.mjs.map +1 -1
  103. package/dist/esm/FrappeProvider.native.js +7 -2
  104. package/dist/esm/FrappeProvider.native.js.map +1 -1
  105. package/dist/esm/FrappeReportBuilder.mjs +11 -12
  106. package/dist/esm/FrappeReportBuilder.mjs.map +1 -1
  107. package/dist/esm/FrappeReportBuilder.native.js +11 -17
  108. package/dist/esm/FrappeReportBuilder.native.js.map +1 -1
  109. package/dist/esm/FrappeRowsReader.mjs +24 -0
  110. package/dist/esm/FrappeRowsReader.mjs.map +1 -0
  111. package/dist/esm/FrappeRowsReader.native.js +25 -0
  112. package/dist/esm/FrappeRowsReader.native.js.map +1 -0
  113. package/dist/esm/FrappeTable.mjs +18 -6
  114. package/dist/esm/FrappeTable.mjs.map +1 -1
  115. package/dist/esm/FrappeTable.native.js +24 -6
  116. package/dist/esm/FrappeTable.native.js.map +1 -1
  117. package/dist/esm/fieldRegistry.mjs +35 -12
  118. package/dist/esm/fieldRegistry.mjs.map +1 -1
  119. package/dist/esm/fieldRegistry.native.js +58 -12
  120. package/dist/esm/fieldRegistry.native.js.map +1 -1
  121. package/dist/esm/fields/Date/index.native.js +6 -3
  122. package/dist/esm/fields/Date/index.native.js.map +1 -1
  123. package/dist/esm/fields/Date/sheetKeyboard.mjs +2 -2
  124. package/dist/esm/fields/Date/sheetKeyboard.mjs.map +1 -1
  125. package/dist/esm/fields/Date/sheetKeyboard.native.js +2 -2
  126. package/dist/esm/fields/Date/sheetKeyboard.native.js.map +1 -1
  127. package/dist/esm/fields/DateRange/index.mjs +2 -1
  128. package/dist/esm/fields/DateRange/index.mjs.map +1 -1
  129. package/dist/esm/fields/DateRange/index.native.js +4 -1
  130. package/dist/esm/fields/DateRange/index.native.js.map +1 -1
  131. package/dist/esm/fields/Password/index.mjs +1 -1
  132. package/dist/esm/fields/Password/index.mjs.map +1 -1
  133. package/dist/esm/fields/Password/index.native.js +1 -1
  134. package/dist/esm/fields/Password/index.native.js.map +1 -1
  135. package/dist/esm/formEngine/index.mjs +2 -1
  136. package/dist/esm/formEngine/index.mjs.map +1 -1
  137. package/dist/esm/formEngine/index.native.js +2 -1
  138. package/dist/esm/formEngine/index.native.js.map +1 -1
  139. package/dist/esm/formEngine/useSessionRoles.mjs +52 -0
  140. package/dist/esm/formEngine/useSessionRoles.mjs.map +1 -0
  141. package/dist/esm/formEngine/useSessionRoles.native.js +56 -0
  142. package/dist/esm/formEngine/useSessionRoles.native.js.map +1 -0
  143. package/dist/esm/frappeConnections.mjs +15 -0
  144. package/dist/esm/frappeConnections.mjs.map +1 -0
  145. package/dist/esm/frappeConnections.native.js +21 -0
  146. package/dist/esm/frappeConnections.native.js.map +1 -0
  147. package/dist/esm/frappeNavigation.mjs +78 -0
  148. package/dist/esm/frappeNavigation.mjs.map +1 -0
  149. package/dist/esm/frappeNavigation.native.js +80 -0
  150. package/dist/esm/frappeNavigation.native.js.map +1 -0
  151. package/dist/esm/index.mjs +7 -3
  152. package/dist/esm/index.mjs.map +1 -1
  153. package/dist/esm/index.native.js +7 -3
  154. package/dist/esm/index.native.js.map +1 -1
  155. package/dist/esm/schemaForm/index.mjs +4 -1
  156. package/dist/esm/schemaForm/index.mjs.map +1 -1
  157. package/dist/esm/schemaForm/index.native.js +4 -1
  158. package/dist/esm/schemaForm/index.native.js.map +1 -1
  159. package/dist/esm/useConnectionFilters.mjs +121 -0
  160. package/dist/esm/useConnectionFilters.mjs.map +1 -0
  161. package/dist/esm/useConnectionFilters.native.js +185 -0
  162. package/dist/esm/useConnectionFilters.native.js.map +1 -0
  163. package/dist/esm/useFrappePagination.mjs +38 -19
  164. package/dist/esm/useFrappePagination.mjs.map +1 -1
  165. package/dist/esm/useFrappePagination.native.js +60 -24
  166. package/dist/esm/useFrappePagination.native.js.map +1 -1
  167. package/dist/esm/useFrappeRows.mjs.map +1 -1
  168. package/dist/esm/useFrappeRows.native.js.map +1 -1
  169. package/dist/jsx/FrappeCalendar.mjs +1 -0
  170. package/dist/jsx/FrappeCalendar.mjs.map +1 -1
  171. package/dist/jsx/FrappeCalendar.native.js +1 -0
  172. package/dist/jsx/FrappeCalendar.native.js.map +1 -1
  173. package/dist/jsx/FrappeDashboard.mjs +9 -11
  174. package/dist/jsx/FrappeDashboard.mjs.map +1 -1
  175. package/dist/jsx/FrappeDashboard.native.js +8 -14
  176. package/dist/jsx/FrappeDashboard.native.js.map +1 -1
  177. package/dist/jsx/FrappeForm.mjs +471 -181
  178. package/dist/jsx/FrappeForm.mjs.map +1 -1
  179. package/dist/jsx/FrappeForm.native.js +611 -207
  180. package/dist/jsx/FrappeForm.native.js.map +1 -1
  181. package/dist/jsx/FrappeFormConnections.mjs +99 -0
  182. package/dist/jsx/FrappeFormConnections.mjs.map +1 -0
  183. package/dist/jsx/FrappeFormConnections.native.js +149 -0
  184. package/dist/jsx/FrappeFormConnections.native.js.map +1 -0
  185. package/dist/jsx/FrappeImageView.mjs +8 -10
  186. package/dist/jsx/FrappeImageView.mjs.map +1 -1
  187. package/dist/jsx/FrappeImageView.native.js +7 -13
  188. package/dist/jsx/FrappeImageView.native.js.map +1 -1
  189. package/dist/jsx/FrappeList.mjs +31 -6
  190. package/dist/jsx/FrappeList.mjs.map +1 -1
  191. package/dist/jsx/FrappeList.native.js +37 -5
  192. package/dist/jsx/FrappeList.native.js.map +1 -1
  193. package/dist/jsx/FrappeListView.mjs +103 -30
  194. package/dist/jsx/FrappeListView.mjs.map +1 -1
  195. package/dist/jsx/FrappeListView.native.js +109 -29
  196. package/dist/jsx/FrappeListView.native.js.map +1 -1
  197. package/dist/jsx/FrappeProvider.mjs +7 -2
  198. package/dist/jsx/FrappeProvider.mjs.map +1 -1
  199. package/dist/jsx/FrappeProvider.native.js +7 -2
  200. package/dist/jsx/FrappeProvider.native.js.map +1 -1
  201. package/dist/jsx/FrappeReportBuilder.mjs +11 -12
  202. package/dist/jsx/FrappeReportBuilder.mjs.map +1 -1
  203. package/dist/jsx/FrappeReportBuilder.native.js +10 -16
  204. package/dist/jsx/FrappeReportBuilder.native.js.map +1 -1
  205. package/dist/jsx/FrappeRowsReader.mjs +24 -0
  206. package/dist/jsx/FrappeRowsReader.mjs.map +1 -0
  207. package/dist/jsx/FrappeRowsReader.native.js +53 -0
  208. package/dist/jsx/FrappeRowsReader.native.js.map +1 -0
  209. package/dist/jsx/FrappeTable.mjs +18 -6
  210. package/dist/jsx/FrappeTable.mjs.map +1 -1
  211. package/dist/jsx/FrappeTable.native.js +24 -6
  212. package/dist/jsx/FrappeTable.native.js.map +1 -1
  213. package/dist/jsx/fieldRegistry.mjs +35 -12
  214. package/dist/jsx/fieldRegistry.mjs.map +1 -1
  215. package/dist/jsx/fieldRegistry.native.js +59 -11
  216. package/dist/jsx/fieldRegistry.native.js.map +1 -1
  217. package/dist/jsx/fields/Date/index.native.js +5 -2
  218. package/dist/jsx/fields/Date/index.native.js.map +1 -1
  219. package/dist/jsx/fields/Date/sheetKeyboard.mjs +2 -2
  220. package/dist/jsx/fields/Date/sheetKeyboard.mjs.map +1 -1
  221. package/dist/jsx/fields/Date/sheetKeyboard.native.js +2 -2
  222. package/dist/jsx/fields/Date/sheetKeyboard.native.js.map +1 -1
  223. package/dist/jsx/fields/DateRange/index.mjs +2 -1
  224. package/dist/jsx/fields/DateRange/index.mjs.map +1 -1
  225. package/dist/jsx/fields/DateRange/index.native.js +4 -1
  226. package/dist/jsx/fields/DateRange/index.native.js.map +1 -1
  227. package/dist/jsx/fields/Password/index.mjs +1 -1
  228. package/dist/jsx/fields/Password/index.mjs.map +1 -1
  229. package/dist/jsx/fields/Password/index.native.js +1 -1
  230. package/dist/jsx/fields/Password/index.native.js.map +1 -1
  231. package/dist/jsx/formEngine/index.mjs +2 -1
  232. package/dist/jsx/formEngine/index.mjs.map +1 -1
  233. package/dist/jsx/formEngine/index.native.js +3 -1
  234. package/dist/jsx/formEngine/index.native.js.map +1 -1
  235. package/dist/jsx/formEngine/useSessionRoles.mjs +52 -0
  236. package/dist/jsx/formEngine/useSessionRoles.mjs.map +1 -0
  237. package/dist/jsx/formEngine/useSessionRoles.native.js +84 -0
  238. package/dist/jsx/formEngine/useSessionRoles.native.js.map +1 -0
  239. package/dist/jsx/frappeConnections.mjs +15 -0
  240. package/dist/jsx/frappeConnections.mjs.map +1 -0
  241. package/dist/jsx/frappeConnections.native.js +50 -0
  242. package/dist/jsx/frappeConnections.native.js.map +1 -0
  243. package/dist/jsx/frappeNavigation.mjs +78 -0
  244. package/dist/jsx/frappeNavigation.mjs.map +1 -0
  245. package/dist/jsx/frappeNavigation.native.js +112 -0
  246. package/dist/jsx/frappeNavigation.native.js.map +1 -0
  247. package/dist/jsx/index.js +7 -3
  248. package/dist/jsx/index.js.map +1 -1
  249. package/dist/jsx/index.mjs +7 -3
  250. package/dist/jsx/index.mjs.map +1 -1
  251. package/dist/jsx/index.native.js +18 -1
  252. package/dist/jsx/index.native.js.map +1 -1
  253. package/dist/jsx/schemaForm/index.mjs +4 -1
  254. package/dist/jsx/schemaForm/index.mjs.map +1 -1
  255. package/dist/jsx/schemaForm/index.native.js +4 -1
  256. package/dist/jsx/schemaForm/index.native.js.map +1 -1
  257. package/dist/jsx/useConnectionFilters.mjs +121 -0
  258. package/dist/jsx/useConnectionFilters.mjs.map +1 -0
  259. package/dist/jsx/useConnectionFilters.native.js +213 -0
  260. package/dist/jsx/useConnectionFilters.native.js.map +1 -0
  261. package/dist/jsx/useFrappePagination.mjs +38 -19
  262. package/dist/jsx/useFrappePagination.mjs.map +1 -1
  263. package/dist/jsx/useFrappePagination.native.js +59 -23
  264. package/dist/jsx/useFrappePagination.native.js.map +1 -1
  265. package/dist/jsx/useFrappeRows.mjs.map +1 -1
  266. package/dist/jsx/useFrappeRows.native.js.map +1 -1
  267. package/package.json +24 -20
  268. package/src/FileBrowser/AttachLibrary.stories.tsx +23 -0
  269. package/src/FrappeCalendar.radius.spec.tsx +55 -0
  270. package/src/FrappeCalendar.tsx +1 -0
  271. package/src/FrappeDashboard.tsx +11 -16
  272. package/src/FrappeForm.connections.spec.tsx +280 -0
  273. package/src/FrappeForm.connections.stories.tsx +93 -0
  274. package/src/FrappeForm.deskSemantics.spec.tsx +284 -0
  275. package/src/FrappeForm.tsx +560 -145
  276. package/src/FrappeFormConnections.tsx +148 -0
  277. package/src/FrappeGuestMeta.spec.tsx +143 -0
  278. package/src/FrappeImageView.tsx +8 -12
  279. package/src/FrappeList.tsx +71 -15
  280. package/src/FrappeListView.cards.spec.tsx +175 -0
  281. package/src/FrappeListView.cards.stories.tsx +131 -0
  282. package/src/FrappeListView.connections.spec.tsx +192 -0
  283. package/src/FrappeListView.connections.stories.tsx +99 -0
  284. package/src/FrappeListView.seed.spec.tsx +228 -0
  285. package/src/FrappeListView.tsx +177 -31
  286. package/src/FrappeProvider.tsx +13 -1
  287. package/src/FrappeReportBuilder.tsx +11 -19
  288. package/src/FrappeRowsReader.tsx +38 -0
  289. package/src/FrappeTable.optionalProps.spec.tsx +249 -0
  290. package/src/FrappeTable.spec.tsx +32 -42
  291. package/src/FrappeTable.stories.spec.tsx +55 -0
  292. package/src/FrappeTable.stories.tsx +28 -37
  293. package/src/FrappeTable.tsx +108 -45
  294. package/src/childTableDependsOn.spec.tsx +85 -0
  295. package/src/desk/DeskFormSidebar.spec.tsx +20 -0
  296. package/src/desk/DeskFormSidebar.stories.tsx +42 -0
  297. package/src/fieldRegistry.spec.tsx +27 -64
  298. package/src/fieldRegistry.ts +71 -14
  299. package/src/fields/Date/index.native.tsx +4 -2
  300. package/src/fields/Date/sheetKeyboard.spec.ts +14 -5
  301. package/src/fields/Date/sheetKeyboard.ts +12 -4
  302. package/src/fields/DateRange/DateRange.spec.tsx +67 -0
  303. package/src/fields/DateRange/index.tsx +5 -1
  304. package/src/fields/LinkTree.spec.tsx +8 -0
  305. package/src/fields/LinkTree.stories.tsx +28 -5
  306. package/src/fields/Password/index.tsx +1 -1
  307. package/src/fields/Select/Select.hydration.spec.tsx +177 -0
  308. package/src/formEngine/doctypeMeta.ts +15 -114
  309. package/src/formEngine/index.ts +2 -0
  310. package/src/formEngine/seam.spec.ts +23 -4
  311. package/src/formEngine/useSessionRoles.ts +73 -0
  312. package/src/frappeConnections.ts +50 -0
  313. package/src/frappeNavigation.tsx +112 -0
  314. package/src/frappeRoutes.spec.tsx +335 -0
  315. package/src/index.ts +28 -1
  316. package/src/schemaForm/index.tsx +1 -0
  317. package/src/useConnectionFilters.tsx +157 -0
  318. package/src/useFrappePagination.ts +70 -26
  319. package/src/useFrappeRows.sharedPath.spec.tsx +206 -0
  320. package/src/useFrappeRows.ts +5 -4
  321. package/types/FrappeCalendar.d.ts.map +1 -1
  322. package/types/FrappeDashboard.d.ts +3 -4
  323. package/types/FrappeDashboard.d.ts.map +1 -1
  324. package/types/FrappeForm.d.ts +57 -5
  325. package/types/FrappeForm.d.ts.map +1 -1
  326. package/types/FrappeFormConnections.d.ts +18 -0
  327. package/types/FrappeFormConnections.d.ts.map +1 -0
  328. package/types/FrappeImageView.d.ts +2 -3
  329. package/types/FrappeImageView.d.ts.map +1 -1
  330. package/types/FrappeList.d.ts +20 -2
  331. package/types/FrappeList.d.ts.map +1 -1
  332. package/types/FrappeListView.d.ts +53 -3
  333. package/types/FrappeListView.d.ts.map +1 -1
  334. package/types/FrappeProvider.d.ts +8 -1
  335. package/types/FrappeProvider.d.ts.map +1 -1
  336. package/types/FrappeReportBuilder.d.ts.map +1 -1
  337. package/types/FrappeRowsReader.d.ts +26 -0
  338. package/types/FrappeRowsReader.d.ts.map +1 -0
  339. package/types/FrappeTable.d.ts +39 -8
  340. package/types/FrappeTable.d.ts.map +1 -1
  341. package/types/fieldRegistry.d.ts +17 -3
  342. package/types/fieldRegistry.d.ts.map +1 -1
  343. package/types/fields/Date/index.native.d.ts.map +1 -1
  344. package/types/fields/Date/sheetKeyboard.d.ts +4 -3
  345. package/types/fields/Date/sheetKeyboard.d.ts.map +1 -1
  346. package/types/fields/DateRange/index.d.ts.map +1 -1
  347. package/types/formEngine/doctypeMeta.d.ts +10 -114
  348. package/types/formEngine/doctypeMeta.d.ts.map +1 -1
  349. package/types/formEngine/index.d.ts +1 -0
  350. package/types/formEngine/index.d.ts.map +1 -1
  351. package/types/formEngine/useSessionRoles.d.ts +19 -0
  352. package/types/formEngine/useSessionRoles.d.ts.map +1 -0
  353. package/types/frappeConnections.d.ts +33 -0
  354. package/types/frappeConnections.d.ts.map +1 -0
  355. package/types/frappeNavigation.d.ts +49 -0
  356. package/types/frappeNavigation.d.ts.map +1 -0
  357. package/types/index.d.ts +7 -3
  358. package/types/index.d.ts.map +1 -1
  359. package/types/schemaForm/index.d.ts.map +1 -1
  360. package/types/useConnectionFilters.d.ts +34 -0
  361. package/types/useConnectionFilters.d.ts.map +1 -0
  362. package/types/useFrappePagination.d.ts +18 -5
  363. package/types/useFrappePagination.d.ts.map +1 -1
  364. package/types/useFrappeRows.d.ts +5 -4
  365. package/types/useFrappeRows.d.ts.map +1 -1
  366. package/src/FileBrowser/AttachLibrary.spec.tsx +0 -74
@@ -1,58 +1,67 @@
1
- import { useFrappeCollection, useFrappeDoctypeEvents, useLiveQuery, useDocTypeMeta } from "@multiplatform.one/frappe";
2
- import { AsyncSkeleton } from "@multiplatform.one/components";
1
+ import { getFrappeSyncModule, useFrappeCollection, useFrappeDoctypeEvents, useLiveQuery, useDocTypeMeta } from "@multiplatform.one/frappe";
2
+ import { AsyncBoundary, AsyncSkeleton, DetailPageLayout, PageHeader, Tabs } from "@multiplatform.one/components";
3
3
  import { SchemaForm } from "./schemaForm/index.mjs";
4
4
  import { FormSidebar } from "./FormSidebar.mjs";
5
5
  import { eq } from "@tanstack/db";
6
- import { FloppyDiskIcon, TrashIcon, XIcon } from "@phosphor-icons/react";
7
- import { useEffect, useMemo, useRef, useState } from "react";
6
+ import { ArrowLeftIcon, FloppyDiskIcon, PencilSimpleIcon, TrashIcon, XIcon } from "@phosphor-icons/react";
7
+ import { useCallback, useEffect, useMemo, useRef, useState } from "react";
8
8
  import { useTranslation } from "react-i18next";
9
- import { Button, formCommonColors } from "@multiplatform.one/forms";
9
+ import { Button, Input, formCommonColors } from "@multiplatform.one/forms";
10
10
  import { Text, XStack, YStack } from "tamagui";
11
11
  import { useResolvedKnobs } from "@multiplatform.one/theme";
12
12
  import { useFrappeConfig } from "./FrappeProvider.mjs";
13
13
  import { FrappeReconnectIndicator } from "./FrappeReconnectIndicator.mjs";
14
14
  import { Timeline } from "./components/timeline.mjs";
15
15
  import { dialog } from "@multiplatform.one/desktop";
16
- import { jsx, jsxs } from "react/jsx-runtime";
17
- const LAYOUT_FIELDTYPES = /* @__PURE__ */new Set(["Section Break", "Column Break", "Tab Break"]);
16
+ import { applyFetchedValues, buildFetchMap } from "./formEngine/fetchFrom.mjs";
17
+ import { buildPermLevelMatrix } from "./formEngine/fieldPermissions.mjs";
18
+ import { createHttpClient, validateLink } from "./formEngine/formActions.mjs";
19
+ import { buildFormTabs, isPromptNamed } from "./formEngine/formLayout.mjs";
20
+ import { useSessionRoles } from "./formEngine/useSessionRoles.mjs";
21
+ import { connectionFields, connectionsFromMeta } from "./frappeConnections.mjs";
22
+ import { FrappeFormConnections } from "./FrappeFormConnections.mjs";
23
+ import { FrappeRowsReader } from "./FrappeRowsReader.mjs";
24
+ import { frappeRouteHref, frappeRouteTarget, useFrappeRouter } from "./frappeNavigation.mjs";
25
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
26
+ import { createElement } from "react";
18
27
  function isEmptyFieldValue(value) {
19
28
  if (value === void 0 || value === null) return true;
20
29
  if (typeof value === "string" && value.trim() === "") return true;
21
30
  if (Array.isArray(value) && value.length === 0) return true;
22
31
  return false;
23
32
  }
24
- function mapFieldToGenericSchema(field) {
25
- return {
26
- type: field.fieldtype,
27
- name: field.fieldname,
28
- label: field.label,
29
- options: field.options,
30
- required: !!field.reqd,
31
- hidden: !!field.hidden,
32
- readOnly: !!field.read_only,
33
- precision: field.precision,
34
- depends_on: field.depends_on,
35
- // Pass through additional Frappe-specific metadata
36
- fieldtype: field.fieldtype,
37
- fieldname: field.fieldname,
38
- in_list_view: field.in_list_view,
39
- in_standard_filter: field.in_standard_filter
40
- };
33
+ function sectionsToLayoutFields(sections) {
34
+ const fields = [];
35
+ sections.forEach((section, sectionIndex) => {
36
+ fields.push({
37
+ fieldname: `__section_${sectionIndex}`,
38
+ fieldtype: section.tab ? "Tab Break" : "Section Break",
39
+ label: section.label,
40
+ collapsible: section.collapsible ? 1 : 0
41
+ });
42
+ section.columns.forEach((column, columnIndex) => {
43
+ if (columnIndex > 0) {
44
+ fields.push({
45
+ fieldname: `__column_${sectionIndex}_${columnIndex}`,
46
+ fieldtype: "Column Break"
47
+ });
48
+ }
49
+ fields.push(...column.fields);
50
+ });
51
+ });
52
+ return fields;
41
53
  }
42
- function mapMetaToFormSchema(meta, sectionOverrides) {
43
- const sections = sectionOverrides ?? meta.sections;
44
- const genericSections = sections.map(section => ({
45
- label: section.label,
46
- collapsible: section.collapsible,
47
- columns: section.columns.map(col => ({
48
- fields: col.fields.map(mapFieldToGenericSchema)
49
- }))
54
+ const documentBookkeeping = /* @__PURE__ */new Set(["name", "owner", "creation", "modified", "modified_by", "docstatus", "idx", "doctype", "_user_tags", "_comments", "_assign", "_liked_by", "_seen"]);
55
+ function fieldsFromDocument(doc) {
56
+ return Object.entries(doc).filter(([key, value]) => !key.startsWith("$") && !documentBookkeeping.has(key) && (value === null || typeof value === "string" || typeof value === "number")).map(([key, value]) => ({
57
+ name: key,
58
+ label: key.replace(/_/g, " ").replace(/(^|\s)\S/g, c => c.toUpperCase()),
59
+ type: typeof value === "number" ? Number.isInteger(value) ? "Int" : "Float" : "Data",
60
+ readOnly: true
50
61
  }));
51
- const allFields = meta.fields.map(mapFieldToGenericSchema);
52
- return {
53
- sections: genericSections,
54
- fields: allFields
55
- };
62
+ }
63
+ function hasRestrictedPermLevel(meta) {
64
+ return !!meta?.fields.some(field => Number(field.permlevel ?? 0) > 0);
56
65
  }
57
66
  function resolveFileUrl(value, baseURL) {
58
67
  if (!value || typeof value !== "string") return void 0;
@@ -118,7 +127,72 @@ function mapDocToSidebarMetadata(doc, t) {
118
127
  }
119
128
  return metadata;
120
129
  }
121
- function FrappeForm({
130
+ function FrappeForm(props) {
131
+ const {
132
+ route,
133
+ ...formProps
134
+ } = props;
135
+ if (route === void 0) return /* @__PURE__ */jsx(FrappeFormBody, {
136
+ ...formProps
137
+ });
138
+ return /* @__PURE__ */jsx(FrappeFormRoute, {
139
+ ...formProps,
140
+ route
141
+ });
142
+ }
143
+ function FrappeFormRoute({
144
+ route,
145
+ name: nameProp,
146
+ onSave,
147
+ onCancel,
148
+ onDelete,
149
+ onEdit,
150
+ ...props
151
+ }) {
152
+ const router = useFrappeRouter();
153
+ const fromPath = router ? frappeRouteTarget(route, router.pathname) : void 0;
154
+ const target = nameProp ? {
155
+ mode: fromPath?.mode === "view" ? "view" : "edit",
156
+ name: nameProp
157
+ } : fromPath?.mode === "view" || fromPath?.mode === "edit" ? fromPath : {
158
+ mode: "create"
159
+ };
160
+ const go = next => router?.navigate(frappeRouteHref(route, next));
161
+ const name = target.mode === "view" || target.mode === "edit" ? target.name : void 0;
162
+ return /* @__PURE__ */createElement(FrappeFormBody, {
163
+ ...props,
164
+ key: `${target.mode}:${name ?? ""}`,
165
+ name,
166
+ routePage: {
167
+ onBack: () => go({
168
+ mode: "list"
169
+ })
170
+ },
171
+ onEdit: target.mode === "view" ? onEdit ?? (() => go({
172
+ mode: "edit",
173
+ name: target.name
174
+ })) : void 0,
175
+ onSave: onSave ?? (doc => {
176
+ const saved = doc.name ?? name;
177
+ go(saved ? {
178
+ mode: "view",
179
+ name: saved
180
+ } : {
181
+ mode: "list"
182
+ });
183
+ }),
184
+ onCancel: onCancel ?? (() => go(name ? {
185
+ mode: "view",
186
+ name
187
+ } : {
188
+ mode: "list"
189
+ })),
190
+ onDelete: onDelete ?? (() => go({
191
+ mode: "list"
192
+ }))
193
+ });
194
+ }
195
+ function FrappeFormBody({
122
196
  baseURL,
123
197
  auth,
124
198
  syncOptions,
@@ -131,14 +205,23 @@ function FrappeForm({
131
205
  readOnlyFields,
132
206
  sections,
133
207
  order,
208
+ roles,
134
209
  onSave,
135
210
  onCancel,
136
211
  onDelete,
212
+ onEdit,
137
213
  showToolbar = true,
138
214
  showSidebar = true,
139
215
  showTimeline = true,
140
216
  disabled = false,
141
- sectionHeadingLevel
217
+ sectionHeadingLevel,
218
+ connections,
219
+ showConnections = true,
220
+ initialDoc,
221
+ loadingFallback,
222
+ notFoundFallback,
223
+ errorFallback,
224
+ routePage
142
225
  }) {
143
226
  const config = useFrappeConfig();
144
227
  const {
@@ -147,12 +230,17 @@ function FrappeForm({
147
230
  const {
148
231
  t
149
232
  } = useTranslation();
150
- const [localDoc, setLocalDoc] = useState({});
151
- const [baselineDoc, setBaselineDoc] = useState(void 0);
233
+ const seedDoc = name && initialDoc && initialDoc.name === name ? initialDoc : void 0;
234
+ const seedRef = useRef(seedDoc);
235
+ seedRef.current = seedDoc;
236
+ const [localDoc, setLocalDoc] = useState(() => seedDoc ?? {});
237
+ const [baselineDoc, setBaselineDoc] = useState(() => seedDoc);
238
+ const [docError, setDocError] = useState(null);
152
239
  const [conflictFields, setConflictFields] = useState([]);
153
240
  const [wasDeleted, setWasDeleted] = useState(false);
154
241
  const [isSubmitting, setIsSubmitting] = useState(false);
155
242
  const [errors, setErrors] = useState({});
243
+ const [activeTab, setActiveTab] = useState(void 0);
156
244
  const everLoadedRef = useRef(false);
157
245
  const localDocRef = useRef(localDoc);
158
246
  localDocRef.current = localDoc;
@@ -179,16 +267,59 @@ function FrappeForm({
179
267
  isLoading: isMetaLoading,
180
268
  error: metaError
181
269
  } = useDocTypeMeta(frappeConfig, doctype);
182
- const formSchema = useMemo(() => {
270
+ const sessionRoles = useSessionRoles(!roles && hasRestrictedPermLevel(meta) ? frappeConfig : void 0);
271
+ const effectiveRoles = roles ?? sessionRoles;
272
+ const permLevels = useMemo(() => buildPermLevelMatrix(meta?.permissions, effectiveRoles), [meta?.permissions, effectiveRoles]);
273
+ const isCreate = !name;
274
+ const docstatus = Number(baselineDoc?.docstatus ?? 0);
275
+ const layoutFields = useMemo(() => {
183
276
  if (!meta) return void 0;
184
- return mapMetaToFormSchema(meta, sections);
277
+ return sections ? sectionsToLayoutFields(sections) : meta.fields;
185
278
  }, [meta, sections]);
186
- const hideFieldSet = useMemo(() => new Set(hideFields ?? []), [hideFields]);
279
+ const formTabs = useMemo(() => {
280
+ if (!layoutFields) return void 0;
281
+ return buildFormTabs({
282
+ fields: layoutFields,
283
+ doc: {
284
+ ...localDoc,
285
+ __islocal: isCreate ? 1 : 0
286
+ },
287
+ docstatus,
288
+ formReadOnly: !!meta?.read_only,
289
+ isCreate,
290
+ detailsLabel: t("Details"),
291
+ permLevels,
292
+ hiddenFields: hideFields
293
+ });
294
+ }, [layoutFields, localDoc, docstatus, meta?.read_only, isCreate, permLevels, hideFields, t]);
295
+ const readsWithoutMeta = !children && !meta && Boolean(metaError) && Boolean(name);
296
+ const recordTabs = useMemo(() => {
297
+ if (!readsWithoutMeta || !baselineDoc) return void 0;
298
+ const recordFields = fieldsFromDocument(baselineDoc);
299
+ return [{
300
+ key: "__details",
301
+ label: t("Details"),
302
+ schema: {
303
+ sections: [{
304
+ columns: [{
305
+ fields: recordFields
306
+ }]
307
+ }],
308
+ fields: recordFields
309
+ }
310
+ }];
311
+ }, [readsWithoutMeta, baselineDoc, t]);
312
+ const promptNamed = isCreate && !!meta && isPromptNamed(meta.autoname, meta.naming_rule);
313
+ const fetchMap = useMemo(() => meta ? buildFetchMap(meta.fields) : void 0, [meta]);
314
+ const handleDocSyncError = useCallback(err => {
315
+ setDocError(err instanceof Error ? err : new Error(String(err)));
316
+ }, []);
187
317
  const docCollection = useFrappeCollection(name ? frappeConfig : void 0, doctype, {
188
318
  fields,
189
319
  filters: name ? {
190
320
  name
191
- } : void 0
321
+ } : void 0,
322
+ onSyncError: handleDocSyncError
192
323
  });
193
324
  const {
194
325
  data: rawDocData,
@@ -249,8 +380,41 @@ function FrappeForm({
249
380
  everLoadedRef.current = false;
250
381
  setWasDeleted(false);
251
382
  setConflictFields([]);
252
- setBaselineDoc(void 0);
383
+ setDocError(null);
384
+ const seed = seedRef.current;
385
+ setBaselineDoc(seed);
386
+ if (seed) setLocalDoc(seed);
253
387
  }, [doctype, name]);
388
+ const effectiveConnections = useMemo(() => connections ?? connectionsFromMeta(meta), [connections, meta]);
389
+ const readsConnections = Boolean(children) && Boolean(name) && effectiveConnections.length > 0;
390
+ const [connectionSnapshots, setConnectionSnapshots] = useState({});
391
+ useEffect(() => {
392
+ setConnectionSnapshots({});
393
+ }, [doctype, name]);
394
+ const connectionReads = useMemo(() => readsConnections && name ? effectiveConnections.map(link => ({
395
+ link,
396
+ options: {
397
+ fields: connectionFields(link),
398
+ filters: [[link.fieldname, "=", name]],
399
+ limit: link.limit ?? 0
400
+ },
401
+ onChange: snapshot => setConnectionSnapshots(prev => ({
402
+ ...prev,
403
+ [link.doctype]: snapshot
404
+ }))
405
+ })) : [], [readsConnections, effectiveConnections, name]);
406
+ const connectionRows = useMemo(() => {
407
+ const rows = {};
408
+ for (const {
409
+ link
410
+ } of connectionReads) {
411
+ rows[link.doctype] = connectionSnapshots[link.doctype]?.rows ?? [];
412
+ }
413
+ return rows;
414
+ }, [connectionReads, connectionSnapshots]);
415
+ const connectionsLoading = connectionReads.some(({
416
+ link
417
+ }) => connectionSnapshots[link.doctype]?.isLoading ?? true);
254
418
  useFrappeDoctypeEvents(name ? frappeConfig : void 0, doctype, event => {
255
419
  if (event.type !== "doc_deleted") return;
256
420
  const payload = event.payload;
@@ -303,6 +467,32 @@ function FrappeForm({
303
467
  return dirty;
304
468
  }, [localDoc, baselineDoc]);
305
469
  const hasUnsavedChanges = dirtyFieldNames.length > 0;
470
+ const runFetchFrom = (field, value) => {
471
+ const rules = fetchMap?.get(field);
472
+ if (!rules || rules.length === 0) return;
473
+ const applyPatch = fetched2 => {
474
+ setLocalDoc(prev => {
475
+ const current = prev;
476
+ if (current[field] !== value) return prev;
477
+ const patch = applyFetchedValues(rules, fetched2, current);
478
+ return Object.keys(patch).length > 0 ? {
479
+ ...current,
480
+ ...patch
481
+ } : prev;
482
+ });
483
+ };
484
+ if (isEmptyFieldValue(value)) {
485
+ applyPatch({});
486
+ return;
487
+ }
488
+ const linkField = meta?.fields.find(metaField => metaField.fieldname === field);
489
+ const targetDoctype = typeof linkField?.options === "string" ? linkField.options : "";
490
+ if (!targetDoctype) return;
491
+ const sources = Array.from(new Set(rules.map(rule => rule.source)));
492
+ const fixtures = frappeConfig.fixtures;
493
+ const fetched = fixtures ? fixtures.getDoc(targetDoctype, String(value), sources).then(doc => doc ?? {}) : validateLink(createHttpClient(frappeConfig), targetDoctype, String(value), sources);
494
+ fetched.then(applyPatch).catch(() => void 0);
495
+ };
306
496
  const setValue = (field, value) => {
307
497
  setLocalDoc(prev => ({
308
498
  ...prev,
@@ -315,19 +505,23 @@ function FrappeForm({
315
505
  delete newErrors[String(field)];
316
506
  return newErrors;
317
507
  });
508
+ runFetchFrom(String(field), value);
318
509
  };
319
510
  const validateRequiredFields = () => {
320
- if (!meta) return {};
511
+ if (!formTabs) return {};
321
512
  const validationErrors = {};
322
513
  const doc = localDoc;
323
- for (const field of meta.fields) {
324
- if (!field.reqd) continue;
325
- if (field.hidden || LAYOUT_FIELDTYPES.has(field.fieldtype)) continue;
326
- if (hideFieldSet.has(field.fieldname)) continue;
327
- if (isEmptyFieldValue(doc[field.fieldname])) {
328
- validationErrors[field.fieldname] = t("{{label}} is required", {
329
- label: field.label || field.fieldname
330
- });
514
+ if (promptNamed && isEmptyFieldValue(doc.name)) {
515
+ validationErrors.name = t("Name is required");
516
+ }
517
+ for (const tab of formTabs) {
518
+ for (const field of tab.schema.fields) {
519
+ if (!field.required) continue;
520
+ if (isEmptyFieldValue(doc[field.name])) {
521
+ validationErrors[field.name] = t("{{label}} is required", {
522
+ label: field.label || field.name
523
+ });
524
+ }
331
525
  }
332
526
  }
333
527
  return validationErrors;
@@ -357,13 +551,20 @@ function FrappeForm({
357
551
  setConflictFields([]);
358
552
  } else {
359
553
  if (!collection) return;
554
+ const temporaryName = localDoc.name ?? `new-${Date.now()}`;
360
555
  const docToInsert = {
361
556
  ...localDoc,
362
557
  doctype,
363
- name: localDoc.name ?? `new-${Date.now()}`
558
+ name: temporaryName
364
559
  };
365
560
  const tx = collection.insert(docToInsert);
366
561
  await tx.isPersisted.promise;
562
+ const createdName = getFrappeSyncModule(frappeConfig)?.createdName(temporaryName) ?? temporaryName;
563
+ onSave?.({
564
+ ...localDoc,
565
+ name: createdName
566
+ });
567
+ return;
367
568
  }
368
569
  onSave?.(localDoc);
369
570
  } catch (err) {
@@ -426,17 +627,45 @@ function FrappeForm({
426
627
  setIsSubmitting(false);
427
628
  }
428
629
  };
630
+ const titleField = meta?.title_field;
631
+ const titleValue = titleField ? localDoc[titleField] : void 0;
632
+ const pageTitle = isCreate ? t("New {{doctype}}", {
633
+ doctype
634
+ }) : String(titleValue || name);
635
+ const frame = (content, aside) => routePage ?
636
+ // flexBasis auto: see DeskFormPage (react-native-web's min-height:0
637
+ // reset would cap the scroll page at viewport height).
638
+ /* @__PURE__ */
639
+ jsx(DetailPageLayout, {
640
+ flexBasis: "auto",
641
+ toolbarLeading: /* @__PURE__ */jsx(Button, {
642
+ size: "$3",
643
+ chromeless: true,
644
+ icon: ArrowLeftIcon,
645
+ onPress: routePage.onBack,
646
+ "aria-label": t("Back to {{doctype}} list", {
647
+ doctype
648
+ }),
649
+ children: doctype
650
+ }),
651
+ header: /* @__PURE__ */jsx(PageHeader, {
652
+ title: pageTitle,
653
+ divider: false
654
+ }),
655
+ aside,
656
+ children: content
657
+ }) : content;
429
658
  if (!children && isMetaLoading && !meta) {
430
- return /* @__PURE__ */jsx(YStack, {
659
+ return frame(/* @__PURE__ */jsx(YStack, {
431
660
  ...knobProps.panelPadding,
432
661
  testID: "frappe-form-skeleton",
433
662
  children: /* @__PURE__ */jsx(AsyncSkeleton, {
434
663
  layout: "generic"
435
664
  })
436
- });
665
+ }));
437
666
  }
438
- if (!children && metaError && !meta) {
439
- return /* @__PURE__ */jsxs(YStack, {
667
+ if (!children && metaError && !meta && !name) {
668
+ return frame(/* @__PURE__ */jsxs(YStack, {
440
669
  ...knobProps.panelPadding,
441
670
  alignItems: "center",
442
671
  ...knobProps.gap,
@@ -451,19 +680,33 @@ function FrappeForm({
451
680
  ...knobProps.body,
452
681
  children: metaError.message
453
682
  })]
454
- });
683
+ }));
455
684
  }
456
- if (name && liveDoc?.isLoading && !wasDeleted) {
457
- return /* @__PURE__ */jsx(YStack, {
685
+ const isDocReading = Boolean(name) && (!docCollection || Boolean(liveDoc?.isLoading));
686
+ const showsSeed = Boolean(seedDoc) && isDocReading;
687
+ if (name && docError && !liveDoc?.data && !wasDeleted) {
688
+ if (errorFallback !== void 0) return frame(errorFallback);
689
+ return frame(/* @__PURE__ */jsx(AsyncBoundary, {
690
+ ...knobProps.panelPadding,
691
+ error: docError,
692
+ errorTitle: t("Failed to load {{doctype}}", {
693
+ doctype
694
+ })
695
+ }));
696
+ }
697
+ if (name && isDocReading && !showsSeed && !wasDeleted) {
698
+ if (loadingFallback !== void 0) return frame(loadingFallback);
699
+ return frame(/* @__PURE__ */jsx(YStack, {
458
700
  ...knobProps.panelPadding,
459
701
  testID: "frappe-form-skeleton",
460
702
  children: /* @__PURE__ */jsx(AsyncSkeleton, {
461
703
  layout: "generic"
462
704
  })
463
- });
705
+ }));
464
706
  }
465
- if (name && !liveDoc?.isLoading && !liveDoc?.data && !wasDeleted) {
466
- return /* @__PURE__ */jsxs(YStack, {
707
+ if (name && !isDocReading && !liveDoc?.data && !wasDeleted) {
708
+ if (notFoundFallback !== void 0) return frame(notFoundFallback);
709
+ return frame(/* @__PURE__ */jsxs(YStack, {
467
710
  ...knobProps.panelPadding,
468
711
  alignItems: "center",
469
712
  ...knobProps.gap,
@@ -480,132 +723,179 @@ function FrappeForm({
480
723
  name
481
724
  })
482
725
  })]
483
- });
726
+ }));
484
727
  }
485
728
  const effectiveDisabled = disabled || wasDeleted;
729
+ const readOnlyView = Boolean(onEdit) || readsWithoutMeta;
730
+ const fieldsDisabled = effectiveDisabled || readOnlyView;
731
+ const shownTabs = formTabs ?? recordTabs;
486
732
  const imageFieldName = meta?.image_field;
487
733
  const sidebarImageUrl = imageFieldName ? resolveFileUrl(localDoc[imageFieldName], finalBaseURL) : void 0;
488
734
  const conflictLabels = conflictFields.map(fieldname => {
489
735
  const field = meta?.fields.find(metaField => metaField.fieldname === fieldname);
490
736
  return field?.label || fieldname;
491
737
  }).join(", ");
492
- return (
493
- // flexBasis auto (not the flex:1 shorthand's 0%): inside scroll-flow page
494
- // scaffolds (LC-29 templates) the parent is auto-height, and a 0% basis
495
- // collapses this stack to zero height on web — content then paints over
496
- // whatever follows. Bounded parents still fill (grow 1) exactly as before.
497
- /* @__PURE__ */
498
- jsxs(YStack, {
499
- ...knobProps.gapLg,
738
+ const formTabItems = (shownTabs ?? []).map(tab => ({
739
+ value: tab.key,
740
+ label: tab.label,
741
+ content: /* @__PURE__ */jsx(SchemaForm, {
742
+ schema: tab.schema,
743
+ doc: localDoc,
744
+ setValue: (field, value) => setValue(field, value),
745
+ errors,
746
+ disabled: fieldsDisabled,
747
+ overrides,
748
+ readOnlyFields,
749
+ sectionHeadingLevel,
750
+ order
751
+ })
752
+ }));
753
+ const tabItems = showConnections && name && effectiveConnections.length > 0 ? [...formTabItems, {
754
+ value: "__connections",
755
+ label: t("Connections"),
756
+ content: /* @__PURE__ */jsx(FrappeFormConnections, {
757
+ connection: frappeConfig,
758
+ connections: effectiveConnections,
759
+ name
760
+ })
761
+ }] : formTabItems;
762
+ const effectiveTab = activeTab && tabItems.some(tab => tab.value === activeTab) ? activeTab : tabItems[0]?.value;
763
+ const localName = localDoc.name;
764
+ const sidebar = showSidebar && name && meta ? /* @__PURE__ */jsx(FormSidebar, {
765
+ imageUrl: sidebarImageUrl,
766
+ sections: buildSidebarSections(localDoc, shareRows, t, assignmentRows),
767
+ metadata: mapDocToSidebarMetadata(localDoc, t)
768
+ }) : void 0;
769
+ return frame(
770
+ // flexBasis auto (not the flex:1 shorthand's 0%): inside scroll-flow page
771
+ // scaffolds (LC-29 templates) the parent is auto-height, and a 0% basis
772
+ // collapses this stack to zero height on web — content then paints over
773
+ // whatever follows. Bounded parents still fill (grow 1) exactly as before.
774
+ /* @__PURE__ */
775
+ jsxs(YStack, {
776
+ ...knobProps.gapLg,
777
+ flexGrow: 1,
778
+ flexShrink: 1,
779
+ flexBasis: "auto",
780
+ children: [/* @__PURE__ */jsx(FrappeReconnectIndicator, {
781
+ config: frappeConfig
782
+ }), connectionReads.map(read => /* @__PURE__ */jsx(FrappeRowsReader, {
783
+ connection: frappeConfig,
784
+ doctype: read.link.doctype,
785
+ options: read.options,
786
+ onChange: read.onChange
787
+ }, read.link.doctype)), wasDeleted && /* @__PURE__ */jsx(XStack, {
788
+ role: "alert",
789
+ alignItems: "center",
790
+ ...knobProps.containerRadius,
791
+ ...knobProps.panelPadding,
792
+ backgroundColor: "$red3",
793
+ testID: "frappe-form-deleted-banner",
794
+ children: /* @__PURE__ */jsx(Text, {
795
+ color: formCommonColors.error,
796
+ ...knobProps.body,
797
+ children: hasUnsavedChanges ? t("This {{doctype}} was deleted on the server. Fields are read-only and your unsaved edits can no longer be saved.", {
798
+ doctype
799
+ }) : t("This {{doctype}} was deleted on the server. Fields are read-only.", {
800
+ doctype
801
+ })
802
+ })
803
+ }), !wasDeleted && conflictFields.length > 0 && /* @__PURE__ */jsx(XStack, {
804
+ role: "status",
805
+ alignItems: "center",
806
+ ...knobProps.containerRadius,
807
+ ...knobProps.panelPadding,
808
+ backgroundColor: "$orange3",
809
+ testID: "frappe-form-conflict-banner",
810
+ children: /* @__PURE__ */jsx(Text, {
811
+ color: "$orange11",
812
+ ...knobProps.body,
813
+ children: t("Changed elsewhere while you were editing: {{fields}}. Your edits are kept \u2014 saving will overwrite the newer server values.", {
814
+ fields: conflictLabels
815
+ })
816
+ })
817
+ }), /* @__PURE__ */jsxs(XStack, {
500
818
  flexGrow: 1,
501
819
  flexShrink: 1,
502
820
  flexBasis: "auto",
503
- children: [/* @__PURE__ */jsx(FrappeReconnectIndicator, {
504
- config: frappeConfig
505
- }), wasDeleted && /* @__PURE__ */jsx(XStack, {
506
- role: "alert",
507
- alignItems: "center",
508
- ...knobProps.containerRadius,
509
- ...knobProps.panelPadding,
510
- backgroundColor: "$red3",
511
- testID: "frappe-form-deleted-banner",
512
- children: /* @__PURE__ */jsx(Text, {
513
- color: formCommonColors.error,
514
- ...knobProps.body,
515
- children: hasUnsavedChanges ? t("This {{doctype}} was deleted on the server. Fields are read-only and your unsaved edits can no longer be saved.", {
516
- doctype
517
- }) : t("This {{doctype}} was deleted on the server. Fields are read-only.", {
518
- doctype
519
- })
520
- })
521
- }), !wasDeleted && conflictFields.length > 0 && /* @__PURE__ */jsx(XStack, {
522
- role: "status",
523
- alignItems: "center",
524
- ...knobProps.containerRadius,
525
- ...knobProps.panelPadding,
526
- backgroundColor: "$orange3",
527
- testID: "frappe-form-conflict-banner",
528
- children: /* @__PURE__ */jsx(Text, {
529
- color: "$orange11",
530
- ...knobProps.body,
531
- children: t("Changed elsewhere while you were editing: {{fields}}. Your edits are kept \u2014 saving will overwrite the newer server values.", {
532
- fields: conflictLabels
533
- })
534
- })
535
- }), /* @__PURE__ */jsxs(XStack, {
536
- flexGrow: 1,
537
- flexShrink: 1,
538
- flexBasis: "auto",
821
+ ...knobProps.gapLg,
822
+ children: [routePage ? null : sidebar, /* @__PURE__ */jsxs(YStack, {
823
+ flex: 1,
539
824
  ...knobProps.gapLg,
540
- children: [showSidebar && name && meta && /* @__PURE__ */jsx(FormSidebar, {
541
- imageUrl: sidebarImageUrl,
542
- sections: buildSidebarSections(localDoc, shareRows, t, assignmentRows),
543
- metadata: mapDocToSidebarMetadata(localDoc, t)
544
- }), /* @__PURE__ */jsxs(YStack, {
545
- flex: 1,
825
+ children: [children ?
826
+ // Render-prop mode
827
+ children({
828
+ doc: localDoc,
829
+ setValue,
830
+ isSubmitting,
831
+ errors,
832
+ meta,
833
+ disabled: fieldsDisabled,
834
+ connections: connectionRows,
835
+ connectionsLoading
836
+ }) : shownTabs ? /* @__PURE__ */jsxs(YStack, {
546
837
  ...knobProps.gapLg,
547
- children: [children ?
548
- // Render-prop mode
549
- children({
550
- doc: localDoc,
551
- setValue,
552
- isSubmitting,
553
- errors,
554
- meta,
838
+ children: [promptNamed && /* @__PURE__ */jsx(Input, {
839
+ label: t("Name"),
840
+ value: typeof localName === "string" ? localName : "",
841
+ onChangeText: value => setValue("name", value),
842
+ placeholder: t("New document name"),
843
+ error: errors.name,
555
844
  disabled: effectiveDisabled
556
- }) : formSchema ?
557
- // Schema-driven mode using generic SchemaForm from @multiplatform.one/forms
558
- /* @__PURE__ */
559
- jsx(SchemaForm, {
560
- schema: formSchema,
561
- doc: localDoc,
562
- setValue: (field, value) => setValue(field, value),
563
- errors,
564
- disabled: effectiveDisabled,
565
- overrides,
566
- hideFields,
567
- readOnlyFields,
568
- sectionHeadingLevel,
569
- order
570
- }) :
571
- // Metadata unavailable (should be covered by metaError branch above)
572
- /* @__PURE__ */
573
- jsx(YStack, {
574
- ...knobProps.panelPadding,
575
- alignItems: "center",
576
- children: /* @__PURE__ */jsx(Text, {
577
- color: formCommonColors.muted,
578
- ...knobProps.body,
579
- children: t("Form schema unavailable")
580
- })
581
- }), errors.general && /* @__PURE__ */jsx(Text, {
582
- color: formCommonColors.error,
845
+ }), tabItems.length > 1 ? /* @__PURE__ */jsx(Tabs, {
846
+ items: tabItems,
847
+ value: effectiveTab,
848
+ onChange: setActiveTab,
849
+ lazyMount: true
850
+ }) : tabItems[0]?.content ?? null]
851
+ }) :
852
+ // Metadata unavailable (should be covered by metaError branch above)
853
+ /* @__PURE__ */
854
+ jsx(YStack, {
855
+ ...knobProps.panelPadding,
856
+ alignItems: "center",
857
+ children: /* @__PURE__ */jsx(Text, {
858
+ color: formCommonColors.muted,
583
859
  ...knobProps.body,
584
- children: errors.general
585
- }), showToolbar && /* @__PURE__ */jsxs(XStack, {
586
- ...knobProps.gap,
587
- justifyContent: "flex-end",
588
- alignItems: "center",
589
- paddingTop: "$3",
590
- children: [hasUnsavedChanges && /* @__PURE__ */jsx(Text, {
591
- color: "$orange11",
592
- marginInlineEnd: "auto",
593
- ...knobProps.body,
594
- children: t("Not Saved")
595
- }), name && onDelete && !wasDeleted && /* @__PURE__ */jsx(Button, {
596
- outlined: true,
597
- error: true,
598
- icon: TrashIcon,
599
- loading: isSubmitting,
600
- disabled: effectiveDisabled,
601
- disabledReason: t("Form is read-only"),
602
- disabledReasonPlacement: "inline",
603
- onPress: handleDelete,
604
- children: t("Delete")
605
- }), onCancel && /* @__PURE__ */jsx(Button, {
860
+ children: t("Form schema unavailable")
861
+ })
862
+ }), errors.general && /* @__PURE__ */jsx(Text, {
863
+ color: formCommonColors.error,
864
+ ...knobProps.body,
865
+ children: errors.general
866
+ }), showToolbar && !readsWithoutMeta && /* @__PURE__ */jsxs(XStack, {
867
+ ...knobProps.gap,
868
+ justifyContent: "flex-end",
869
+ alignItems: "center",
870
+ paddingTop: "$3",
871
+ children: [hasUnsavedChanges && !onEdit && /* @__PURE__ */jsx(Text, {
872
+ color: "$orange11",
873
+ marginInlineEnd: "auto",
874
+ ...knobProps.body,
875
+ children: t("Not Saved")
876
+ }), name && onDelete && !wasDeleted && /* @__PURE__ */jsx(Button, {
877
+ outlined: true,
878
+ error: true,
879
+ icon: TrashIcon,
880
+ loading: isSubmitting,
881
+ disabled: effectiveDisabled,
882
+ disabledReason: t("Form is read-only"),
883
+ disabledReasonPlacement: "inline",
884
+ onPress: handleDelete,
885
+ children: t("Delete")
886
+ }), onEdit ? /* @__PURE__ */jsx(Button, {
887
+ accent: true,
888
+ icon: PencilSimpleIcon,
889
+ disabled: effectiveDisabled,
890
+ disabledReason: t("Form is read-only"),
891
+ disabledReasonPlacement: "inline",
892
+ onPress: onEdit,
893
+ children: t("Edit")
894
+ }) : /* @__PURE__ */jsxs(Fragment, {
895
+ children: [onCancel && /* @__PURE__ */jsx(Button, {
606
896
  outlined: true,
607
897
  icon: XIcon,
608
- disabled: isSubmitting || disabled,
898
+ disabled,
609
899
  disabledReason: t("Form is read-only"),
610
900
  disabledReasonPlacement: "inline",
611
901
  onPress: handleCancel,
@@ -622,13 +912,13 @@ function FrappeForm({
622
912
  })]
623
913
  })]
624
914
  })]
625
- }), showTimeline && name && /* @__PURE__ */jsx(Timeline, {
626
- doctype,
627
- docname: name,
628
- label: t("Activity")
629
915
  })]
630
- })
631
- );
916
+ }), showTimeline && name && !readsWithoutMeta && /* @__PURE__ */jsx(Timeline, {
917
+ doctype,
918
+ docname: name,
919
+ label: t("Activity")
920
+ })]
921
+ }), routePage ? sidebar : void 0);
632
922
  }
633
923
  export { FrappeForm, buildSidebarSections, mapDocToSidebarMetadata, resolveFileUrl };
634
924
  //# sourceMappingURL=FrappeForm.mjs.map