@byline/ui 0.9.3

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 (368) hide show
  1. package/LICENSE +373 -0
  2. package/README.md +17 -0
  3. package/dist/admin/components/admin-account/change-password.d.ts +9 -0
  4. package/dist/admin/components/admin-account/change-password.d.ts.map +1 -0
  5. package/dist/admin/components/admin-account/change-password.js +192 -0
  6. package/dist/admin/components/admin-account/change-password.module.js +8 -0
  7. package/dist/admin/components/admin-account/change-password_module.css +27 -0
  8. package/dist/admin/components/admin-account/container.d.ts +30 -0
  9. package/dist/admin/components/admin-account/container.d.ts.map +1 -0
  10. package/dist/admin/components/admin-account/container.js +299 -0
  11. package/dist/admin/components/admin-account/container.module.js +28 -0
  12. package/dist/admin/components/admin-account/container_module.css +106 -0
  13. package/dist/admin/components/admin-account/update.d.ts +9 -0
  14. package/dist/admin/components/admin-account/update.d.ts.map +1 -0
  15. package/dist/admin/components/admin-account/update.js +207 -0
  16. package/dist/admin/components/admin-account/update.module.js +8 -0
  17. package/dist/admin/components/admin-account/update_module.css +27 -0
  18. package/dist/admin/components/admin-permissions/inspector.d.ts +5 -0
  19. package/dist/admin/components/admin-permissions/inspector.d.ts.map +1 -0
  20. package/dist/admin/components/admin-permissions/inspector.js +284 -0
  21. package/dist/admin/components/admin-permissions/inspector.module.js +56 -0
  22. package/dist/admin/components/admin-permissions/inspector_module.css +238 -0
  23. package/dist/admin/components/admin-roles/create.d.ts +8 -0
  24. package/dist/admin/components/admin-roles/create.d.ts.map +1 -0
  25. package/dist/admin/components/admin-roles/create.js +177 -0
  26. package/dist/admin/components/admin-roles/create.module.js +8 -0
  27. package/dist/admin/components/admin-roles/create_module.css +27 -0
  28. package/dist/admin/components/admin-roles/permissions.d.ts +11 -0
  29. package/dist/admin/components/admin-roles/permissions.d.ts.map +1 -0
  30. package/dist/admin/components/admin-roles/permissions.js +303 -0
  31. package/dist/admin/components/admin-roles/permissions.module.js +44 -0
  32. package/dist/admin/components/admin-roles/permissions_module.css +192 -0
  33. package/dist/admin/components/admin-roles/update.d.ts +9 -0
  34. package/dist/admin/components/admin-roles/update.d.ts.map +1 -0
  35. package/dist/admin/components/admin-roles/update.js +166 -0
  36. package/dist/admin/components/admin-roles/update.module.js +8 -0
  37. package/dist/admin/components/admin-roles/update_module.css +27 -0
  38. package/dist/admin/components/admin-users/create.d.ts +9 -0
  39. package/dist/admin/components/admin-users/create.d.ts.map +1 -0
  40. package/dist/admin/components/admin-users/create.js +268 -0
  41. package/dist/admin/components/admin-users/create.module.js +10 -0
  42. package/dist/admin/components/admin-users/create_module.css +45 -0
  43. package/dist/admin/components/admin-users/roles.d.ts +12 -0
  44. package/dist/admin/components/admin-users/roles.d.ts.map +1 -0
  45. package/dist/admin/components/admin-users/roles.js +148 -0
  46. package/dist/admin/components/admin-users/roles.module.js +18 -0
  47. package/dist/admin/components/admin-users/roles_module.css +75 -0
  48. package/dist/admin/components/admin-users/set-password.d.ts +9 -0
  49. package/dist/admin/components/admin-users/set-password.d.ts.map +1 -0
  50. package/dist/admin/components/admin-users/set-password.js +170 -0
  51. package/dist/admin/components/admin-users/set-password.module.js +9 -0
  52. package/dist/admin/components/admin-users/set-password_module.css +31 -0
  53. package/dist/admin/components/admin-users/update.d.ts +9 -0
  54. package/dist/admin/components/admin-users/update.d.ts.map +1 -0
  55. package/dist/admin/components/admin-users/update.js +254 -0
  56. package/dist/admin/components/admin-users/update.module.js +9 -0
  57. package/dist/admin/components/admin-users/update_module.css +34 -0
  58. package/dist/admin/components/auth/sign-in-form.d.ts +14 -0
  59. package/dist/admin/components/auth/sign-in-form.d.ts.map +1 -0
  60. package/dist/admin/components/auth/sign-in-form.js +107 -0
  61. package/dist/admin/components/auth/sign-in-form.module.js +10 -0
  62. package/dist/admin/components/auth/sign-in-form_module.css +35 -0
  63. package/dist/admin/components/collections/diff-modal.d.ts +23 -0
  64. package/dist/admin/components/collections/diff-modal.d.ts.map +1 -0
  65. package/dist/admin/components/collections/diff-modal.js +147 -0
  66. package/dist/admin/components/collections/diff-modal.module.js +14 -0
  67. package/dist/admin/components/collections/diff-modal_module.css +56 -0
  68. package/dist/admin/components/collections/status-badge.d.ts +26 -0
  69. package/dist/admin/components/collections/status-badge.d.ts.map +1 -0
  70. package/dist/admin/components/collections/status-badge.js +35 -0
  71. package/dist/admin/components/collections/status-badge.module.js +7 -0
  72. package/dist/admin/components/collections/status-badge_module.css +20 -0
  73. package/dist/admin/group.d.ts +28 -0
  74. package/dist/admin/group.d.ts.map +1 -0
  75. package/dist/admin/group.js +14 -0
  76. package/dist/admin/group.module.js +6 -0
  77. package/dist/admin/group_module.css +19 -0
  78. package/dist/admin/row.d.ts +26 -0
  79. package/dist/admin/row.d.ts.map +1 -0
  80. package/dist/admin/row.js +8 -0
  81. package/dist/admin/row.module.js +5 -0
  82. package/dist/admin/row_module.css +18 -0
  83. package/dist/admin/tabs.d.ts +33 -0
  84. package/dist/admin/tabs.d.ts.map +1 -0
  85. package/dist/admin/tabs.js +34 -0
  86. package/dist/admin/tabs.module.js +10 -0
  87. package/dist/admin/tabs_module.css +68 -0
  88. package/dist/dnd/draggable-sortable/demo/draggable-list-demo.js +105 -0
  89. package/dist/dnd/draggable-sortable/demo/draggable-list-demo.module.js +12 -0
  90. package/dist/dnd/draggable-sortable/demo/draggable-list-demo_module.css +39 -0
  91. package/dist/dnd/draggable-sortable/draggable-sortable-item/index.d.ts +19 -0
  92. package/dist/dnd/draggable-sortable/draggable-sortable-item/index.d.ts.map +1 -0
  93. package/dist/dnd/draggable-sortable/draggable-sortable-item/index.js +27 -0
  94. package/dist/dnd/draggable-sortable/draggable-sortable-item/types.d.ts +25 -0
  95. package/dist/dnd/draggable-sortable/draggable-sortable-item/types.d.ts.map +1 -0
  96. package/dist/dnd/draggable-sortable/draggable-sortable-item/types.js +1 -0
  97. package/dist/dnd/draggable-sortable/draggable-sortable.d.ts +17 -0
  98. package/dist/dnd/draggable-sortable/draggable-sortable.d.ts.map +1 -0
  99. package/dist/dnd/draggable-sortable/draggable-sortable.js +46 -0
  100. package/dist/dnd/draggable-sortable/index.d.ts +5 -0
  101. package/dist/dnd/draggable-sortable/index.d.ts.map +1 -0
  102. package/dist/dnd/draggable-sortable/index.js +4 -0
  103. package/dist/dnd/draggable-sortable/types.d.ts +26 -0
  104. package/dist/dnd/draggable-sortable/types.d.ts.map +1 -0
  105. package/dist/dnd/draggable-sortable/types.js +1 -0
  106. package/dist/dnd/draggable-sortable/use-draggable-sortable/index.d.ts +16 -0
  107. package/dist/dnd/draggable-sortable/use-draggable-sortable/index.d.ts.map +1 -0
  108. package/dist/dnd/draggable-sortable/use-draggable-sortable/index.js +28 -0
  109. package/dist/dnd/draggable-sortable/use-draggable-sortable/types.d.ts +23 -0
  110. package/dist/dnd/draggable-sortable/use-draggable-sortable/types.d.ts.map +1 -0
  111. package/dist/dnd/draggable-sortable/use-draggable-sortable/types.js +1 -0
  112. package/dist/dnd/draggable-sortable/utils.d.ts +14 -0
  113. package/dist/dnd/draggable-sortable/utils.d.ts.map +1 -0
  114. package/dist/dnd/draggable-sortable/utils.js +10 -0
  115. package/dist/fields/array/array-field.d.ts +15 -0
  116. package/dist/fields/array/array-field.d.ts.map +1 -0
  117. package/dist/fields/array/array-field.js +176 -0
  118. package/dist/fields/array/array-field.module.js +11 -0
  119. package/dist/fields/array/array-field_module.css +32 -0
  120. package/dist/fields/blocks/blocks-field.d.ts +14 -0
  121. package/dist/fields/blocks/blocks-field.d.ts.map +1 -0
  122. package/dist/fields/blocks/blocks-field.js +244 -0
  123. package/dist/fields/blocks/blocks-field.module.js +26 -0
  124. package/dist/fields/blocks/blocks-field_module.css +107 -0
  125. package/dist/fields/checkbox/checkbox-field.d.ts +17 -0
  126. package/dist/fields/checkbox/checkbox-field.d.ts.map +1 -0
  127. package/dist/fields/checkbox/checkbox-field.js +27 -0
  128. package/dist/fields/column-formatter.d.ts +21 -0
  129. package/dist/fields/column-formatter.d.ts.map +1 -0
  130. package/dist/fields/column-formatter.js +15 -0
  131. package/dist/fields/date-time-formatter.d.ts +17 -0
  132. package/dist/fields/date-time-formatter.d.ts.map +1 -0
  133. package/dist/fields/date-time-formatter.js +8 -0
  134. package/dist/fields/datetime/datetime-field.d.ts +17 -0
  135. package/dist/fields/datetime/datetime-field.d.ts.map +1 -0
  136. package/dist/fields/datetime/datetime-field.js +37 -0
  137. package/dist/fields/datetime/datetime-field.module.js +5 -0
  138. package/dist/fields/datetime/datetime-field_module.css +4 -0
  139. package/dist/fields/draggable-context-menu.d.ts +7 -0
  140. package/dist/fields/draggable-context-menu.d.ts.map +1 -0
  141. package/dist/fields/draggable-context-menu.js +83 -0
  142. package/dist/fields/draggable-context-menu.module.js +15 -0
  143. package/dist/fields/draggable-context-menu_module.css +91 -0
  144. package/dist/fields/field-helpers.d.ts +27 -0
  145. package/dist/fields/field-helpers.d.ts.map +1 -0
  146. package/dist/fields/field-helpers.js +48 -0
  147. package/dist/fields/field-renderer.d.ts +31 -0
  148. package/dist/fields/field-renderer.d.ts.map +1 -0
  149. package/dist/fields/field-renderer.js +189 -0
  150. package/dist/fields/field-renderer.module.js +8 -0
  151. package/dist/fields/field-renderer_module.css +11 -0
  152. package/dist/fields/file/file-field.d.ts +18 -0
  153. package/dist/fields/file/file-field.d.ts.map +1 -0
  154. package/dist/fields/file/file-field.js +125 -0
  155. package/dist/fields/file/file-field.module.js +13 -0
  156. package/dist/fields/file/file-field_module.css +64 -0
  157. package/dist/fields/group/group-field.d.ts +16 -0
  158. package/dist/fields/group/group-field.d.ts.map +1 -0
  159. package/dist/fields/group/group-field.js +59 -0
  160. package/dist/fields/group/group-field.module.js +9 -0
  161. package/dist/fields/group/group-field_module.css +27 -0
  162. package/dist/fields/image/image-field.d.ts +20 -0
  163. package/dist/fields/image/image-field.d.ts.map +1 -0
  164. package/dist/fields/image/image-field.js +198 -0
  165. package/dist/fields/image/image-field.module.js +21 -0
  166. package/dist/fields/image/image-field_module.css +96 -0
  167. package/dist/fields/image/image-upload-field.d.ts +22 -0
  168. package/dist/fields/image/image-upload-field.d.ts.map +1 -0
  169. package/dist/fields/image/image-upload-field.js +187 -0
  170. package/dist/fields/image/image-upload-field.module.js +19 -0
  171. package/dist/fields/image/image-upload-field_module.css +92 -0
  172. package/dist/fields/local-date-time.d.ts +28 -0
  173. package/dist/fields/local-date-time.d.ts.map +1 -0
  174. package/dist/fields/local-date-time.js +49 -0
  175. package/dist/fields/locale-badge.d.ts +19 -0
  176. package/dist/fields/locale-badge.d.ts.map +1 -0
  177. package/dist/fields/locale-badge.js +10 -0
  178. package/dist/fields/locale-badge.module.js +5 -0
  179. package/dist/fields/locale-badge_module.css +27 -0
  180. package/dist/fields/numerical/numerical-field.d.ts +19 -0
  181. package/dist/fields/numerical/numerical-field.d.ts.map +1 -0
  182. package/dist/fields/numerical/numerical-field.js +73 -0
  183. package/dist/fields/relation/relation-display.d.ts +41 -0
  184. package/dist/fields/relation/relation-display.d.ts.map +1 -0
  185. package/dist/fields/relation/relation-display.js +58 -0
  186. package/dist/fields/relation/relation-display.module.js +9 -0
  187. package/dist/fields/relation/relation-display_module.css +21 -0
  188. package/dist/fields/relation/relation-field.d.ts +19 -0
  189. package/dist/fields/relation/relation-field.d.ts.map +1 -0
  190. package/dist/fields/relation/relation-field.js +133 -0
  191. package/dist/fields/relation/relation-field.module.js +13 -0
  192. package/dist/fields/relation/relation-field_module.css +62 -0
  193. package/dist/fields/relation/relation-picker.d.ts +50 -0
  194. package/dist/fields/relation/relation-picker.d.ts.map +1 -0
  195. package/dist/fields/relation/relation-picker.js +233 -0
  196. package/dist/fields/relation/relation-picker.module.js +26 -0
  197. package/dist/fields/relation/relation-picker_module.css +124 -0
  198. package/dist/fields/relation/relation-summary.d.ts +32 -0
  199. package/dist/fields/relation/relation-summary.d.ts.map +1 -0
  200. package/dist/fields/relation/relation-summary.js +50 -0
  201. package/dist/fields/relation/relation-summary.module.js +11 -0
  202. package/dist/fields/relation/relation-summary_module.css +37 -0
  203. package/dist/fields/select/select-field.d.ts +17 -0
  204. package/dist/fields/select/select-field.d.ts.map +1 -0
  205. package/dist/fields/select/select-field.js +42 -0
  206. package/dist/fields/select/select-field.module.js +5 -0
  207. package/dist/fields/select/select-field_module.css +4 -0
  208. package/dist/fields/sortable-item.d.ts +16 -0
  209. package/dist/fields/sortable-item.d.ts.map +1 -0
  210. package/dist/fields/sortable-item.js +80 -0
  211. package/dist/fields/sortable-item.module.js +22 -0
  212. package/dist/fields/sortable-item_module.css +124 -0
  213. package/dist/fields/text/text-field.d.ts +21 -0
  214. package/dist/fields/text/text-field.d.ts.map +1 -0
  215. package/dist/fields/text/text-field.js +104 -0
  216. package/dist/fields/text/text-field.module.js +6 -0
  217. package/dist/fields/text/text-field_module.css +5 -0
  218. package/dist/fields/text-area/text-area-field.d.ts +21 -0
  219. package/dist/fields/text-area/text-area-field.d.ts.map +1 -0
  220. package/dist/fields/text-area/text-area-field.js +105 -0
  221. package/dist/fields/text-area/text-area-field.module.js +6 -0
  222. package/dist/fields/text-area/text-area-field_module.css +5 -0
  223. package/dist/fields/use-field-change-handler.d.ts +24 -0
  224. package/dist/fields/use-field-change-handler.d.ts.map +1 -0
  225. package/dist/fields/use-field-change-handler.js +52 -0
  226. package/dist/forms/document-actions.d.ts +14 -0
  227. package/dist/forms/document-actions.d.ts.map +1 -0
  228. package/dist/forms/document-actions.js +153 -0
  229. package/dist/forms/document-actions.module.js +18 -0
  230. package/dist/forms/document-actions_module.css +66 -0
  231. package/dist/forms/form-context.d.ts +78 -0
  232. package/dist/forms/form-context.d.ts.map +1 -0
  233. package/dist/forms/form-context.js +420 -0
  234. package/dist/forms/form-renderer.d.ts +66 -0
  235. package/dist/forms/form-renderer.d.ts.map +1 -0
  236. package/dist/forms/form-renderer.js +555 -0
  237. package/dist/forms/form-renderer.module.js +46 -0
  238. package/dist/forms/form-renderer_module.css +242 -0
  239. package/dist/forms/navigation-guard.d.ts +55 -0
  240. package/dist/forms/navigation-guard.d.ts.map +1 -0
  241. package/dist/forms/navigation-guard.js +22 -0
  242. package/dist/forms/path-widget.d.ts +33 -0
  243. package/dist/forms/path-widget.d.ts.map +1 -0
  244. package/dist/forms/path-widget.js +101 -0
  245. package/dist/forms/path-widget.module.js +8 -0
  246. package/dist/forms/path-widget_module.css +29 -0
  247. package/dist/forms/upload-executor.d.ts +58 -0
  248. package/dist/forms/upload-executor.d.ts.map +1 -0
  249. package/dist/forms/upload-executor.js +92 -0
  250. package/dist/react.d.ts +55 -0
  251. package/dist/react.d.ts.map +1 -0
  252. package/dist/react.js +48 -0
  253. package/dist/services/admin-services-context.d.ts +17 -0
  254. package/dist/services/admin-services-context.d.ts.map +1 -0
  255. package/dist/services/admin-services-context.js +13 -0
  256. package/dist/services/admin-services-types.d.ts +130 -0
  257. package/dist/services/admin-services-types.d.ts.map +1 -0
  258. package/dist/services/admin-services-types.js +1 -0
  259. package/dist/services/field-services-context.d.ts +17 -0
  260. package/dist/services/field-services-context.d.ts.map +1 -0
  261. package/dist/services/field-services-context.js +13 -0
  262. package/dist/services/field-services-types.d.ts +64 -0
  263. package/dist/services/field-services-types.d.ts.map +1 -0
  264. package/dist/services/field-services-types.js +1 -0
  265. package/package.json +133 -0
  266. package/src/admin/components/admin-account/change-password.module.css +40 -0
  267. package/src/admin/components/admin-account/change-password.tsx +232 -0
  268. package/src/admin/components/admin-account/container.module.css +158 -0
  269. package/src/admin/components/admin-account/container.tsx +230 -0
  270. package/src/admin/components/admin-account/update.module.css +40 -0
  271. package/src/admin/components/admin-account/update.tsx +263 -0
  272. package/src/admin/components/admin-permissions/inspector.module.css +326 -0
  273. package/src/admin/components/admin-permissions/inspector.tsx +298 -0
  274. package/src/admin/components/admin-roles/create.module.css +40 -0
  275. package/src/admin/components/admin-roles/create.tsx +218 -0
  276. package/src/admin/components/admin-roles/permissions.module.css +279 -0
  277. package/src/admin/components/admin-roles/permissions.tsx +396 -0
  278. package/src/admin/components/admin-roles/update.module.css +40 -0
  279. package/src/admin/components/admin-roles/update.tsx +218 -0
  280. package/src/admin/components/admin-users/create.module.css +63 -0
  281. package/src/admin/components/admin-users/create.tsx +323 -0
  282. package/src/admin/components/admin-users/roles.module.css +119 -0
  283. package/src/admin/components/admin-users/roles.tsx +172 -0
  284. package/src/admin/components/admin-users/set-password.module.css +46 -0
  285. package/src/admin/components/admin-users/set-password.tsx +199 -0
  286. package/src/admin/components/admin-users/update.module.css +49 -0
  287. package/src/admin/components/admin-users/update.tsx +328 -0
  288. package/src/admin/components/auth/sign-in-form.module.css +53 -0
  289. package/src/admin/components/auth/sign-in-form.tsx +118 -0
  290. package/src/admin/components/collections/diff-modal.module.css +79 -0
  291. package/src/admin/components/collections/diff-modal.tsx +171 -0
  292. package/src/admin/components/collections/status-badge.module.css +31 -0
  293. package/src/admin/components/collections/status-badge.tsx +69 -0
  294. package/src/admin/group.module.css +41 -0
  295. package/src/admin/group.tsx +40 -0
  296. package/src/admin/row.module.css +32 -0
  297. package/src/admin/row.tsx +33 -0
  298. package/src/admin/tabs.module.css +107 -0
  299. package/src/admin/tabs.tsx +74 -0
  300. package/src/declarations.d.ts +4 -0
  301. package/src/dnd/draggable-sortable/demo/draggable-list-demo.module.css +65 -0
  302. package/src/dnd/draggable-sortable/demo/draggable-list-demo.tsx +117 -0
  303. package/src/dnd/draggable-sortable/draggable-sortable-item/index.tsx +54 -0
  304. package/src/dnd/draggable-sortable/draggable-sortable-item/types.ts +30 -0
  305. package/src/dnd/draggable-sortable/draggable-sortable.tsx +86 -0
  306. package/src/dnd/draggable-sortable/index.ts +5 -0
  307. package/src/dnd/draggable-sortable/types.ts +24 -0
  308. package/src/dnd/draggable-sortable/use-draggable-sortable/index.tsx +50 -0
  309. package/src/dnd/draggable-sortable/use-draggable-sortable/types.ts +25 -0
  310. package/src/dnd/draggable-sortable/utils.ts +29 -0
  311. package/src/fields/array/array-field.module.css +48 -0
  312. package/src/fields/array/array-field.tsx +266 -0
  313. package/src/fields/blocks/blocks-field.module.css +148 -0
  314. package/src/fields/blocks/blocks-field.tsx +312 -0
  315. package/src/fields/checkbox/checkbox-field.tsx +53 -0
  316. package/src/fields/column-formatter.tsx +31 -0
  317. package/src/fields/date-time-formatter.tsx +22 -0
  318. package/src/fields/datetime/datetime-field.module.css +13 -0
  319. package/src/fields/datetime/datetime-field.tsx +54 -0
  320. package/src/fields/draggable-context-menu.module.css +127 -0
  321. package/src/fields/draggable-context-menu.tsx +85 -0
  322. package/src/fields/field-helpers.ts +66 -0
  323. package/src/fields/field-renderer.module.css +22 -0
  324. package/src/fields/field-renderer.tsx +255 -0
  325. package/src/fields/file/file-field.module.css +88 -0
  326. package/src/fields/file/file-field.tsx +107 -0
  327. package/src/fields/group/group-field.module.css +43 -0
  328. package/src/fields/group/group-field.tsx +84 -0
  329. package/src/fields/image/image-field.module.css +129 -0
  330. package/src/fields/image/image-field.tsx +212 -0
  331. package/src/fields/image/image-upload-field.module.css +123 -0
  332. package/src/fields/image/image-upload-field.tsx +270 -0
  333. package/src/fields/local-date-time.tsx +88 -0
  334. package/src/fields/locale-badge.module.css +37 -0
  335. package/src/fields/locale-badge.tsx +32 -0
  336. package/src/fields/numerical/numerical-field.tsx +112 -0
  337. package/src/fields/relation/relation-display.module.css +36 -0
  338. package/src/fields/relation/relation-display.tsx +130 -0
  339. package/src/fields/relation/relation-field.module.css +83 -0
  340. package/src/fields/relation/relation-field.tsx +202 -0
  341. package/src/fields/relation/relation-picker.module.css +168 -0
  342. package/src/fields/relation/relation-picker.tsx +325 -0
  343. package/src/fields/relation/relation-summary.module.css +55 -0
  344. package/src/fields/relation/relation-summary.tsx +123 -0
  345. package/src/fields/select/select-field.module.css +13 -0
  346. package/src/fields/select/select-field.tsx +56 -0
  347. package/src/fields/sortable-item.module.css +167 -0
  348. package/src/fields/sortable-item.tsx +101 -0
  349. package/src/fields/text/text-field.module.css +13 -0
  350. package/src/fields/text/text-field.tsx +146 -0
  351. package/src/fields/text-area/text-area-field.module.css +13 -0
  352. package/src/fields/text-area/text-area-field.tsx +147 -0
  353. package/src/fields/use-field-change-handler.ts +112 -0
  354. package/src/forms/document-actions.module.css +94 -0
  355. package/src/forms/document-actions.tsx +149 -0
  356. package/src/forms/form-context.tsx +620 -0
  357. package/src/forms/form-renderer.module.css +318 -0
  358. package/src/forms/form-renderer.tsx +786 -0
  359. package/src/forms/navigation-guard.tsx +98 -0
  360. package/src/forms/path-widget.module.css +41 -0
  361. package/src/forms/path-widget.test.tsx +217 -0
  362. package/src/forms/path-widget.tsx +141 -0
  363. package/src/forms/upload-executor.ts +190 -0
  364. package/src/react.ts +79 -0
  365. package/src/services/admin-services-context.tsx +35 -0
  366. package/src/services/admin-services-types.ts +177 -0
  367. package/src/services/field-services-context.tsx +35 -0
  368. package/src/services/field-services-types.ts +68 -0
@@ -0,0 +1,620 @@
1
+ /**
2
+ * This Source Code is subject to the terms of the Mozilla Public
3
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
4
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5
+ *
6
+ * Copyright (c) Infonomic Company Limited
7
+ */
8
+
9
+ import type React from 'react'
10
+ import { createContext, useCallback, useContext, useEffect, useRef, useState } from 'react'
11
+
12
+ import type { Field, FieldBeforeChangeResult, FieldHookContext } from '@byline/core'
13
+ import { normalizeHooks } from '@byline/core'
14
+ import type { DocumentPatch, FieldSetPatch } from '@byline/core/patches'
15
+ import { get as getNestedValue, set as setNestedValue } from 'lodash-es'
16
+
17
+ interface FormError {
18
+ field: string
19
+ message: string
20
+ }
21
+
22
+ /**
23
+ * Represents a file that has been selected but not yet uploaded.
24
+ * The file is held locally until form submission.
25
+ */
26
+ export interface PendingUpload {
27
+ /** The actual File object to upload */
28
+ file: File
29
+ /** Blob URL for local preview (must be revoked on cleanup) */
30
+ previewUrl: string
31
+ /** The collection path for the upload endpoint */
32
+ collectionPath: string
33
+ }
34
+
35
+ type FieldListener = (value: any) => void
36
+ type ErrorsListener = (errors: FormError[]) => void
37
+ type MetaListener = () => void
38
+ type SystemPathListener = (value: string | null) => void
39
+
40
+ interface FormContextType {
41
+ setFieldValue: (name: string, value: any) => void
42
+ setFieldStore: (name: string, value: any) => void
43
+ getFieldValue: (name: string) => any
44
+ getFieldValues: () => Record<string, any>
45
+ getPatches: () => DocumentPatch[]
46
+ appendPatch: (patch: DocumentPatch) => void
47
+ resetPatches: () => void
48
+ hasChanges: () => boolean
49
+ resetHasChanges: () => void
50
+ runFieldHooks: (fields: Field[]) => Promise<FormError[]>
51
+ validateForm: (fields: Field[]) => FormError[]
52
+ errors: FormError[]
53
+ clearErrors: () => void
54
+ setFieldError: (field: string, message: string) => void
55
+ clearFieldError: (field: string) => void
56
+ isDirty: (fieldName: string) => boolean
57
+ subscribeField: (name: string, listener: FieldListener) => () => void
58
+ subscribeErrors: (listener: ErrorsListener) => () => void
59
+ subscribeMeta: (listener: MetaListener) => () => void
60
+ // Pending uploads (deferred until save)
61
+ addPendingUpload: (fieldPath: string, upload: PendingUpload) => void
62
+ removePendingUpload: (fieldPath: string) => void
63
+ getPendingUploads: () => Map<string, PendingUpload>
64
+ hasPendingUploads: () => boolean
65
+ clearPendingUploads: () => void
66
+ // System-managed `documentVersions.path` slot, edited by the path widget.
67
+ // `null` means the widget will fall back to live-derived preview / the
68
+ // server-side default; a non-null value is sent verbatim to the server.
69
+ getSystemPath: () => string | null
70
+ setSystemPath: (value: string | null) => void
71
+ subscribeSystemPath: (listener: SystemPathListener) => () => void
72
+ }
73
+
74
+ const FormContext = createContext<FormContextType | null>(null)
75
+
76
+ export const useFormContext = () => {
77
+ const context = useContext(FormContext)
78
+ if (context == null) {
79
+ throw new Error('useFormContext must be used within a FormProvider')
80
+ }
81
+ return context
82
+ }
83
+
84
+ export const FormProvider = ({
85
+ children,
86
+ initialData = {},
87
+ }: {
88
+ children: React.ReactNode
89
+ initialData?: Record<string, any>
90
+ }) => {
91
+ const fieldValues = useRef<Record<string, any>>(
92
+ JSON.parse(JSON.stringify(initialData?.fields ?? initialData))
93
+ )
94
+ const initialValues = useRef<Record<string, any>>(initialData?.fields ?? initialData)
95
+ const errorsRef = useRef<FormError[]>([])
96
+ const dirtyFields = useRef<Set<string>>(new Set())
97
+ const patchesRef = useRef<DocumentPatch[]>([])
98
+ const pendingUploadsRef = useRef<Map<string, PendingUpload>>(new Map())
99
+
100
+ const fieldListeners = useRef<Map<string, Set<FieldListener>>>(new Map())
101
+ const errorListeners = useRef<Set<ErrorsListener>>(new Set())
102
+ const metaListeners = useRef<Set<MetaListener>>(new Set())
103
+
104
+ // System path slot — initialised from the loaded version's top-level
105
+ // `path` (edit mode) or `null` (create mode). Edits via `setSystemPath`
106
+ // mark the form dirty so the Save button enables.
107
+ const systemPathRef = useRef<string | null>(
108
+ typeof initialData?.path === 'string' && (initialData.path as string).length > 0
109
+ ? (initialData.path as string)
110
+ : null
111
+ )
112
+ const initialSystemPath = useRef<string | null>(systemPathRef.current)
113
+ const systemPathListeners = useRef<Set<SystemPathListener>>(new Set())
114
+
115
+ const subscribeField = useCallback((name: string, listener: FieldListener) => {
116
+ if (!fieldListeners.current.has(name)) {
117
+ fieldListeners.current.set(name, new Set())
118
+ }
119
+ fieldListeners.current.get(name)?.add(listener)
120
+ return () => {
121
+ const listeners = fieldListeners.current.get(name)
122
+ if (listeners) {
123
+ listeners.delete(listener)
124
+ if (listeners.size === 0) {
125
+ fieldListeners.current.delete(name)
126
+ }
127
+ }
128
+ }
129
+ }, [])
130
+
131
+ const subscribeErrors = useCallback((listener: ErrorsListener) => {
132
+ errorListeners.current.add(listener)
133
+ return () => {
134
+ errorListeners.current.delete(listener)
135
+ }
136
+ }, [])
137
+
138
+ const subscribeMeta = useCallback((listener: MetaListener) => {
139
+ metaListeners.current.add(listener)
140
+ return () => {
141
+ metaListeners.current.delete(listener)
142
+ }
143
+ }, [])
144
+
145
+ const notifyFieldListeners = useCallback((name: string, value: any) => {
146
+ const listeners = fieldListeners.current.get(name)
147
+ if (listeners) {
148
+ listeners.forEach((listener) => {
149
+ listener(value)
150
+ })
151
+ }
152
+ }, [])
153
+
154
+ const notifyErrorListeners = useCallback(() => {
155
+ errorListeners.current.forEach((listener) => {
156
+ listener(errorsRef.current)
157
+ })
158
+ }, [])
159
+
160
+ const notifyMetaListeners = useCallback(() => {
161
+ metaListeners.current.forEach((listener) => {
162
+ listener()
163
+ })
164
+ }, [])
165
+
166
+ const updateFieldStoreInternal = useCallback(
167
+ (name: string, value: any) => {
168
+ const newFieldValues = { ...fieldValues.current }
169
+
170
+ // Keep nested path values up to date for generic usage and patches.
171
+ setNestedValue(newFieldValues, name, value)
172
+
173
+ fieldValues.current = newFieldValues
174
+ dirtyFields.current.add(name)
175
+
176
+ notifyFieldListeners(name, value)
177
+ notifyMetaListeners()
178
+ },
179
+ [notifyFieldListeners, notifyMetaListeners]
180
+ )
181
+
182
+ const setFieldStore = useCallback(
183
+ (name: string, value: any) => {
184
+ updateFieldStoreInternal(name, value)
185
+ },
186
+ [updateFieldStoreInternal]
187
+ )
188
+
189
+ const setFieldValue = useCallback(
190
+ (name: string, value: any) => {
191
+ updateFieldStoreInternal(name, value)
192
+
193
+ const patch: FieldSetPatch = {
194
+ kind: 'field.set',
195
+ path: name,
196
+ value,
197
+ }
198
+
199
+ // Optimization: Coalesce consecutive field.set patches for the same path
200
+ const lastPatch = patchesRef.current[patchesRef.current.length - 1]
201
+ if (lastPatch && lastPatch.kind === 'field.set' && lastPatch.path === name) {
202
+ const newPatches = [...patchesRef.current]
203
+ newPatches[newPatches.length - 1] = patch
204
+ patchesRef.current = newPatches
205
+ } else {
206
+ patchesRef.current = [...patchesRef.current, patch]
207
+ }
208
+
209
+ // Clear field-specific errors when value changes
210
+ if (errorsRef.current.some((error) => error.field === name)) {
211
+ errorsRef.current = errorsRef.current.filter((error) => error.field !== name)
212
+ notifyErrorListeners()
213
+ }
214
+ },
215
+ [updateFieldStoreInternal, notifyErrorListeners]
216
+ )
217
+
218
+ const getFieldValues = useCallback(() => fieldValues.current, [])
219
+
220
+ const getPatches = useCallback(() => patchesRef.current, [])
221
+ const appendPatch = useCallback(
222
+ (patch: DocumentPatch) => {
223
+ patchesRef.current = [...patchesRef.current, patch]
224
+ // Mark a generic dirty flag so hasChanges() becomes true even
225
+ // for patches that don't correspond to a specific field.set.
226
+ dirtyFields.current.add('__patch__')
227
+ notifyMetaListeners()
228
+ if (process.env.NODE_ENV !== 'production') {
229
+ // eslint-disable-next-line no-console
230
+ console.debug('FormContext.appendPatch', { patch, dirtyCount: dirtyFields.current.size })
231
+ }
232
+ },
233
+ [notifyMetaListeners]
234
+ )
235
+
236
+ const getFieldValue = useCallback((name: string) => {
237
+ const dirty = dirtyFields.current.has(name)
238
+ const currentValue = getNestedValue(fieldValues.current, name)
239
+
240
+ if (currentValue !== undefined) {
241
+ return currentValue
242
+ }
243
+ if (!dirty) {
244
+ return getNestedValue(initialValues.current, name)
245
+ }
246
+ return undefined
247
+ }, [])
248
+
249
+ const hasChanges = useCallback(() => {
250
+ return dirtyFields.current.size > 0
251
+ }, [])
252
+
253
+ const resetHasChanges = useCallback(() => {
254
+ dirtyFields.current.clear()
255
+ patchesRef.current = []
256
+ initialSystemPath.current = systemPathRef.current
257
+ notifyMetaListeners()
258
+ }, [notifyMetaListeners])
259
+
260
+ const isDirty = useCallback((fieldName: string) => {
261
+ return dirtyFields.current.has(fieldName)
262
+ }, [])
263
+
264
+ // -------------------------------------------------------------------------
265
+ // System path slot
266
+ // -------------------------------------------------------------------------
267
+
268
+ const getSystemPath = useCallback(() => systemPathRef.current, [])
269
+
270
+ const setSystemPath = useCallback(
271
+ (value: string | null) => {
272
+ systemPathRef.current = value
273
+ if (value !== initialSystemPath.current) {
274
+ dirtyFields.current.add('__systemPath__')
275
+ } else {
276
+ dirtyFields.current.delete('__systemPath__')
277
+ }
278
+ systemPathListeners.current.forEach((listener) => {
279
+ listener(value)
280
+ })
281
+ notifyMetaListeners()
282
+ },
283
+ [notifyMetaListeners]
284
+ )
285
+
286
+ const subscribeSystemPath = useCallback((listener: SystemPathListener) => {
287
+ systemPathListeners.current.add(listener)
288
+ return () => {
289
+ systemPathListeners.current.delete(listener)
290
+ }
291
+ }, [])
292
+
293
+ // ---------------------------------------------------------------------------
294
+ // Pending uploads (deferred until save)
295
+ // ---------------------------------------------------------------------------
296
+
297
+ const addPendingUpload = useCallback(
298
+ (fieldPath: string, upload: PendingUpload) => {
299
+ // If there's an existing pending upload for this path, revoke its blob URL
300
+ const existing = pendingUploadsRef.current.get(fieldPath)
301
+ if (existing) {
302
+ URL.revokeObjectURL(existing.previewUrl)
303
+ }
304
+ pendingUploadsRef.current.set(fieldPath, upload)
305
+ dirtyFields.current.add(fieldPath)
306
+ notifyMetaListeners()
307
+ },
308
+ [notifyMetaListeners]
309
+ )
310
+
311
+ const removePendingUpload = useCallback(
312
+ (fieldPath: string) => {
313
+ const existing = pendingUploadsRef.current.get(fieldPath)
314
+ if (existing) {
315
+ URL.revokeObjectURL(existing.previewUrl)
316
+ pendingUploadsRef.current.delete(fieldPath)
317
+ notifyMetaListeners()
318
+ }
319
+ },
320
+ [notifyMetaListeners]
321
+ )
322
+
323
+ const getPendingUploads = useCallback(() => {
324
+ return new Map(pendingUploadsRef.current)
325
+ }, [])
326
+
327
+ const hasPendingUploads = useCallback(() => {
328
+ return pendingUploadsRef.current.size > 0
329
+ }, [])
330
+
331
+ const clearPendingUploads = useCallback(() => {
332
+ // Revoke all blob URLs to prevent memory leaks
333
+ for (const upload of pendingUploadsRef.current.values()) {
334
+ URL.revokeObjectURL(upload.previewUrl)
335
+ }
336
+ pendingUploadsRef.current.clear()
337
+ }, [])
338
+
339
+ // Cleanup blob URLs on unmount
340
+ useEffect(() => {
341
+ return () => {
342
+ for (const upload of pendingUploadsRef.current.values()) {
343
+ URL.revokeObjectURL(upload.previewUrl)
344
+ }
345
+ }
346
+ }, [])
347
+
348
+ const validateForm = useCallback(
349
+ (fields: Field[]): FormError[] => {
350
+ const formErrors: FormError[] = []
351
+ const data = getFieldValues()
352
+
353
+ for (const field of fields) {
354
+ const value = getFieldValue(field.name)
355
+
356
+ // Required field validation
357
+ if (!field.optional && (value == null || value === '')) {
358
+ formErrors.push({
359
+ field: field.name,
360
+ message: `${field.label} is required`,
361
+ })
362
+ }
363
+
364
+ // Type-specific validation
365
+ if (value != null && value !== '') {
366
+ switch (field.type) {
367
+ case 'text':
368
+ if (typeof value !== 'string') {
369
+ formErrors.push({
370
+ field: field.name,
371
+ message: `${field.label} must be text`,
372
+ })
373
+ }
374
+ break
375
+ case 'checkbox':
376
+ if (typeof value !== 'boolean') {
377
+ formErrors.push({
378
+ field: field.name,
379
+ message: `${field.label} must be true or false`,
380
+ })
381
+ }
382
+ break
383
+ case 'select':
384
+ if ('options' in field && field.options) {
385
+ const validValues = field.options.map((opt) => opt.value)
386
+ if (!validValues.includes(value)) {
387
+ formErrors.push({
388
+ field: field.name,
389
+ message: `${field.label} must be one of: ${validValues.join(', ')}`,
390
+ })
391
+ }
392
+ }
393
+ break
394
+ case 'datetime':
395
+ if (value instanceof Date === false && typeof value !== 'string') {
396
+ formErrors.push({
397
+ field: field.name,
398
+ message: `${field.label} must be a valid date`,
399
+ })
400
+ }
401
+ break
402
+ }
403
+ }
404
+
405
+ // Custom validate function — applies to all field types including structure fields.
406
+ if (field.validate) {
407
+ const error = field.validate(value, data)
408
+ if (error) {
409
+ formErrors.push({ field: field.name, message: error })
410
+ }
411
+ }
412
+ }
413
+
414
+ errorsRef.current = formErrors
415
+ notifyErrorListeners()
416
+ return formErrors
417
+ },
418
+ [getFieldValue, getFieldValues, notifyErrorListeners]
419
+ )
420
+
421
+ const clearErrors = useCallback(() => {
422
+ errorsRef.current = []
423
+ notifyErrorListeners()
424
+ }, [notifyErrorListeners])
425
+
426
+ const setFieldError = useCallback(
427
+ (field: string, message: string) => {
428
+ // Replace any existing error for this field, or add a new one
429
+ const filtered = errorsRef.current.filter((e) => e.field !== field)
430
+ filtered.push({ field, message })
431
+ errorsRef.current = filtered
432
+ notifyErrorListeners()
433
+ },
434
+ [notifyErrorListeners]
435
+ )
436
+
437
+ const clearFieldError = useCallback(
438
+ (field: string) => {
439
+ if (errorsRef.current.some((e) => e.field === field)) {
440
+ errorsRef.current = errorsRef.current.filter((e) => e.field !== field)
441
+ notifyErrorListeners()
442
+ }
443
+ },
444
+ [notifyErrorListeners]
445
+ )
446
+
447
+ /**
448
+ * Run `beforeValidate` hooks for every top-level field that defines one.
449
+ * Called at submit time, before `validateForm()`. Hooks may return
450
+ * `{ value }` to auto-populate a field, or `{ error }` to block submit.
451
+ */
452
+ const runFieldHooks = useCallback(
453
+ async (fields: Field[]): Promise<FormError[]> => {
454
+ const hookErrors: FormError[] = []
455
+ const data = { ...fieldValues.current }
456
+
457
+ for (const field of fields) {
458
+ const fns = normalizeHooks(field.hooks?.beforeValidate)
459
+ if (fns.length === 0) continue
460
+
461
+ const path = field.name
462
+ const value = getFieldValue(path)
463
+
464
+ const ctx: FieldHookContext = {
465
+ value,
466
+ previousValue: value,
467
+ data,
468
+ path,
469
+ field,
470
+ operation: 'submit',
471
+ }
472
+
473
+ try {
474
+ for (const fn of fns) {
475
+ const result = (await fn(ctx)) as FieldBeforeChangeResult | undefined
476
+ if (result?.error) {
477
+ hookErrors.push({ field: path, message: result.error })
478
+ }
479
+ if (result?.value !== undefined) {
480
+ // Auto-populate: write the derived value into the store
481
+ setFieldValue(path, result.value)
482
+ // Keep ctx and data snapshot in sync for subsequent hooks
483
+ ctx.value = result.value
484
+ data[path] = result.value
485
+ }
486
+ }
487
+ } catch (err) {
488
+ const message = err instanceof Error ? err.message : 'Unexpected hook error'
489
+ hookErrors.push({ field: path, message })
490
+ }
491
+ }
492
+
493
+ if (hookErrors.length > 0) {
494
+ errorsRef.current = [...errorsRef.current, ...hookErrors]
495
+ notifyErrorListeners()
496
+ }
497
+
498
+ return hookErrors
499
+ },
500
+ [getFieldValue, setFieldValue, notifyErrorListeners]
501
+ )
502
+
503
+ return (
504
+ <FormContext.Provider
505
+ value={{
506
+ setFieldValue,
507
+ setFieldStore,
508
+ getFieldValue,
509
+ getFieldValues,
510
+ getPatches,
511
+ appendPatch,
512
+ resetPatches: () => {
513
+ patchesRef.current = []
514
+ },
515
+ hasChanges,
516
+ resetHasChanges,
517
+ runFieldHooks,
518
+ validateForm,
519
+ errors: errorsRef.current,
520
+ clearErrors,
521
+ setFieldError,
522
+ clearFieldError,
523
+ isDirty,
524
+ subscribeField,
525
+ subscribeErrors,
526
+ subscribeMeta,
527
+ addPendingUpload,
528
+ removePendingUpload,
529
+ getPendingUploads,
530
+ hasPendingUploads,
531
+ clearPendingUploads,
532
+ getSystemPath,
533
+ setSystemPath,
534
+ subscribeSystemPath,
535
+ }}
536
+ >
537
+ {children}
538
+ </FormContext.Provider>
539
+ )
540
+ }
541
+
542
+ /**
543
+ * Subscribe to the system `path` slot edited by the path widget.
544
+ * Returns the current value (or `null` when no override is set).
545
+ */
546
+ export const useSystemPath = (): string | null => {
547
+ const { getSystemPath, subscribeSystemPath } = useFormContext()
548
+ const [value, setValue] = useState<string | null>(() => getSystemPath())
549
+
550
+ useEffect(() => {
551
+ return subscribeSystemPath((next) => setValue(next))
552
+ }, [subscribeSystemPath])
553
+
554
+ return value
555
+ }
556
+
557
+ export const useFormStore = () => {
558
+ return useFormContext()
559
+ }
560
+
561
+ export const useFieldError = (name: string) => {
562
+ const { errors, subscribeErrors } = useFormContext()
563
+ const [error, setError] = useState<string | undefined>(
564
+ errors.find((e) => e.field === name)?.message
565
+ )
566
+
567
+ useEffect(() => {
568
+ const unsubscribe = subscribeErrors((currentErrors) => {
569
+ const fieldError = currentErrors.find((e) => e.field === name)
570
+ setError(fieldError?.message)
571
+ })
572
+ return unsubscribe
573
+ }, [subscribeErrors, name])
574
+
575
+ return error
576
+ }
577
+
578
+ export const useFormMeta = () => {
579
+ const { hasChanges, subscribeMeta } = useFormContext()
580
+ const [hasChangesValue, setHasChangesValue] = useState(hasChanges())
581
+
582
+ useEffect(() => {
583
+ const unsubscribe = subscribeMeta(() => {
584
+ setHasChangesValue(hasChanges())
585
+ })
586
+ return unsubscribe
587
+ }, [subscribeMeta, hasChanges])
588
+
589
+ return {
590
+ hasChanges: hasChangesValue,
591
+ }
592
+ }
593
+
594
+ export const useIsDirty = (name: string) => {
595
+ const { isDirty, subscribeMeta } = useFormContext()
596
+ const [dirty, setDirty] = useState(isDirty(name))
597
+
598
+ useEffect(() => {
599
+ const unsubscribe = subscribeMeta(() => {
600
+ setDirty(isDirty(name))
601
+ })
602
+ return unsubscribe
603
+ }, [subscribeMeta, isDirty, name])
604
+
605
+ return dirty
606
+ }
607
+
608
+ export const useFieldValue = <T = any>(name: string): T | undefined => {
609
+ const { getFieldValue, subscribeField } = useFormContext()
610
+ const [value, setValue] = useState<T | undefined>(() => getFieldValue(name))
611
+
612
+ useEffect(() => {
613
+ const unsubscribe = subscribeField(name, (nextValue) => {
614
+ setValue(nextValue)
615
+ })
616
+ return unsubscribe
617
+ }, [subscribeField, name])
618
+
619
+ return value
620
+ }