@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,66 @@
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 { Field } from '@byline/core'
10
+ import { resolveFieldDefaultValue } from '@byline/core'
11
+
12
+ export const placeholderStoredFileValue = {
13
+ fileId: crypto.randomUUID(),
14
+ filename: 'placeholder',
15
+ originalFilename: 'placeholder',
16
+ mimeType: 'application/octet-stream',
17
+ fileSize: 0,
18
+ storageProvider: 'placeholder',
19
+ storagePath: 'pending',
20
+ storageUrl: null,
21
+ fileHash: null,
22
+ imageWidth: null,
23
+ imageHeight: null,
24
+ imageFormat: null,
25
+ processingStatus: 'pending',
26
+ thumbnailGenerated: false,
27
+ }
28
+
29
+ export const placeholderForField = (f: Field): any => {
30
+ switch (f.type) {
31
+ case 'text':
32
+ case 'textArea':
33
+ return ''
34
+ case 'checkbox':
35
+ return false
36
+ case 'integer':
37
+ return 0
38
+ case 'richText':
39
+ case 'datetime':
40
+ return undefined
41
+ case 'select':
42
+ return ''
43
+ case 'file':
44
+ case 'image':
45
+ return placeholderStoredFileValue
46
+ default:
47
+ return null
48
+ }
49
+ }
50
+
51
+ export const defaultScalarForField = async (
52
+ f: Field,
53
+ getFieldValues: () => Record<string, any>
54
+ ): Promise<any> => {
55
+ const schemaDefault = await resolveFieldDefaultValue(f, {
56
+ data: getFieldValues(),
57
+ now: () => new Date(),
58
+ uuid: () => crypto.randomUUID(),
59
+ })
60
+
61
+ if (schemaDefault !== undefined) {
62
+ return schemaDefault
63
+ }
64
+
65
+ return placeholderForField(f)
66
+ }
@@ -0,0 +1,22 @@
1
+ /**
2
+ * FieldRenderer — main field-type switch wrapper.
3
+ *
4
+ * Override handles:
5
+ * .byline-field-localized-wrap — wrapper added when a non-self-badging
6
+ * field needs an absolutely-positioned
7
+ * locale badge in the corner
8
+ * .byline-field-localized-badge — the absolutely-positioned badge slot
9
+ */
10
+
11
+ .localized-wrap,
12
+ :global(.byline-field-localized-wrap) {
13
+ position: relative;
14
+ }
15
+
16
+ .localized-badge,
17
+ :global(.byline-field-localized-badge) {
18
+ position: absolute;
19
+ top: 0;
20
+ right: 0;
21
+ line-height: 1;
22
+ }
@@ -0,0 +1,255 @@
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 {
10
+ ArrayField as ArrayFieldType,
11
+ BlocksField as BlocksFieldType,
12
+ Field,
13
+ FieldComponentSlots,
14
+ GroupField as GroupFieldType,
15
+ } from '@byline/core'
16
+ import { getClientConfig } from '@byline/core'
17
+ import cx from 'classnames'
18
+
19
+ import { ArrayField } from './array/array-field'
20
+ import { BlocksField } from './blocks/blocks-field'
21
+ import { CheckboxField } from './checkbox/checkbox-field'
22
+ import { DateTimeField } from './datetime/datetime-field'
23
+ import styles from './field-renderer.module.css'
24
+ import { FileField } from './file/file-field'
25
+ import { GroupField } from './group/group-field'
26
+ import { ImageField } from './image/image-field'
27
+ import { LocaleBadge } from './locale-badge'
28
+ import { NumericalField } from './numerical/numerical-field'
29
+ import { RelationField } from './relation/relation-field'
30
+ import { SelectField } from './select/select-field'
31
+ import { TextField } from './text/text-field'
32
+ import { TextAreaField } from './text-area/text-area-field'
33
+ import { useFieldChangeHandler } from './use-field-change-handler'
34
+
35
+ // ---------------------------------------------------------------------------
36
+ // FieldRenderer — the main field type switch. Delegates to the appropriate
37
+ // field widget based on `field.type`.
38
+ // ---------------------------------------------------------------------------
39
+
40
+ interface FieldRendererProps {
41
+ field: Field
42
+ defaultValue?: any
43
+ basePath?: string
44
+ disableSorting?: boolean
45
+ hideLabel?: boolean
46
+ /** Collection path (e.g. `'media'`) forwarded to upload-capable fields. */
47
+ collectionPath?: string
48
+ /**
49
+ * The active content locale (e.g. `'en'`, `'fr'`). When provided and
50
+ * `field.localized === true`, a small locale badge is shown so the editor
51
+ * knows they are working on a localised field in the current language.
52
+ */
53
+ contentLocale?: string
54
+ /**
55
+ * Optional UI component slot overrides from the admin config.
56
+ * Forwarded to value-field widgets that support custom slots.
57
+ */
58
+ components?: FieldComponentSlots
59
+ }
60
+
61
+ export const FieldRenderer = ({
62
+ field,
63
+ defaultValue,
64
+ basePath,
65
+ disableSorting,
66
+ hideLabel,
67
+ collectionPath,
68
+ contentLocale,
69
+ components,
70
+ }: FieldRendererProps) => {
71
+ const path = basePath ? `${basePath}.${field.name}` : field.name
72
+ const htmlId = path.replace(/[[\].]/g, '-')
73
+
74
+ const handleChange = useFieldChangeHandler(field, path)
75
+
76
+ // When a locale is active and the field is localised, inject a badge into
77
+ // the field label so the editor knows they are editing locale-specific content.
78
+ const isLocalised = (field as any).localized === true
79
+
80
+ const badge =
81
+ isLocalised && contentLocale && !hideLabel ? <LocaleBadge locale={contentLocale} /> : null
82
+
83
+ /**
84
+ * Render the underlying field widget. If the field is localised, we wrap it
85
+ * so we can append the locale badge after the label.
86
+ */
87
+ const renderField = () => {
88
+ switch (field.type) {
89
+ case 'text':
90
+ return (
91
+ <TextField
92
+ field={hideLabel ? { ...field, label: undefined } : field}
93
+ defaultValue={defaultValue}
94
+ onChange={handleChange}
95
+ path={path}
96
+ id={htmlId}
97
+ locale={isLocalised ? contentLocale : undefined}
98
+ components={components}
99
+ />
100
+ )
101
+ case 'textArea':
102
+ return (
103
+ <TextAreaField
104
+ field={hideLabel ? { ...field, label: undefined } : field}
105
+ defaultValue={defaultValue}
106
+ onChange={handleChange}
107
+ path={path}
108
+ id={htmlId}
109
+ locale={isLocalised ? contentLocale : undefined}
110
+ components={components}
111
+ />
112
+ )
113
+ case 'checkbox':
114
+ return (
115
+ <CheckboxField
116
+ field={hideLabel ? { ...field, label: undefined } : field}
117
+ defaultValue={defaultValue}
118
+ onChange={handleChange}
119
+ path={path}
120
+ id={htmlId}
121
+ />
122
+ )
123
+ case 'select':
124
+ return (
125
+ <SelectField
126
+ field={hideLabel ? { ...field, label: undefined } : field}
127
+ defaultValue={defaultValue}
128
+ onChange={handleChange}
129
+ path={path}
130
+ id={htmlId}
131
+ />
132
+ )
133
+ case 'richText': {
134
+ const RichTextEditor = getClientConfig().fields?.richText?.editor
135
+ if (!RichTextEditor) {
136
+ throw new Error(
137
+ 'No richText editor registered. Install @byline/richtext-lexical and set ' +
138
+ '`fields.richText.editor` in your admin config.'
139
+ )
140
+ }
141
+ return (
142
+ <RichTextEditor
143
+ field={hideLabel ? { ...field, label: undefined } : field}
144
+ defaultValue={defaultValue}
145
+ onChange={handleChange}
146
+ path={path}
147
+ instanceKey={htmlId}
148
+ locale={isLocalised ? contentLocale : undefined}
149
+ />
150
+ )
151
+ }
152
+ case 'datetime':
153
+ return (
154
+ <DateTimeField
155
+ field={hideLabel ? { ...field, label: undefined } : field}
156
+ defaultValue={defaultValue}
157
+ onChange={handleChange}
158
+ path={path}
159
+ id={htmlId}
160
+ />
161
+ )
162
+ case 'integer':
163
+ return (
164
+ <NumericalField
165
+ field={hideLabel ? { ...field, label: undefined } : field}
166
+ defaultValue={defaultValue}
167
+ onChange={handleChange}
168
+ path={path}
169
+ id={htmlId}
170
+ components={components}
171
+ />
172
+ )
173
+ case 'file':
174
+ return (
175
+ <FileField
176
+ field={hideLabel ? { ...field, label: undefined } : field}
177
+ defaultValue={defaultValue}
178
+ onChange={handleChange}
179
+ path={path}
180
+ />
181
+ )
182
+ case 'image':
183
+ return (
184
+ <ImageField
185
+ field={hideLabel ? { ...field, label: undefined } : field}
186
+ defaultValue={defaultValue}
187
+ onChange={handleChange}
188
+ path={path}
189
+ collectionPath={collectionPath}
190
+ />
191
+ )
192
+ case 'relation':
193
+ return (
194
+ <RelationField
195
+ field={hideLabel ? { ...field, label: undefined } : field}
196
+ defaultValue={defaultValue}
197
+ onChange={handleChange}
198
+ path={path}
199
+ id={htmlId}
200
+ />
201
+ )
202
+ case 'group':
203
+ // Render a group field as a fixed-order inline field group.
204
+ return (
205
+ <GroupField
206
+ field={
207
+ hideLabel
208
+ ? ({ ...field, label: undefined } as unknown as GroupFieldType)
209
+ : (field as unknown as GroupFieldType)
210
+ }
211
+ defaultValue={defaultValue}
212
+ path={path}
213
+ />
214
+ )
215
+ case 'blocks':
216
+ if (!field.blocks) return null
217
+ return (
218
+ <BlocksField
219
+ field={field as unknown as BlocksFieldType}
220
+ defaultValue={defaultValue}
221
+ path={path}
222
+ />
223
+ )
224
+ case 'array':
225
+ if (!field.fields) return null
226
+ return (
227
+ <ArrayField
228
+ field={field as unknown as ArrayFieldType}
229
+ defaultValue={defaultValue}
230
+ path={path}
231
+ disableSorting={disableSorting}
232
+ />
233
+ )
234
+ default:
235
+ return null
236
+ }
237
+ }
238
+
239
+ // text and textArea render the badge inside their own Label row;
240
+ // the outer wrapper is only needed for other field types.
241
+ const selfBadge = field.type === 'text' || field.type === 'textArea' || field.type === 'richText'
242
+
243
+ if (badge && !selfBadge) {
244
+ return (
245
+ <div className={cx('byline-field-localized-wrap', styles['localized-wrap'])}>
246
+ {renderField()}
247
+ <span className={cx('byline-field-localized-badge', styles['localized-badge'])}>
248
+ {badge}
249
+ </span>
250
+ </div>
251
+ )
252
+ }
253
+
254
+ return renderField()
255
+ }
@@ -0,0 +1,88 @@
1
+ /**
2
+ * FileField — placeholder file widget showing stored file metadata.
3
+ *
4
+ * Override handles:
5
+ * .byline-field-file — wrapper div
6
+ * .byline-field-file-dirty — dirty-state border on the wrapper
7
+ * .byline-field-file-header — label/help row
8
+ * .byline-field-file-label — primary label text
9
+ * .byline-field-file-help — secondary help text
10
+ * .byline-field-file-action — action button (e.g. "Upload (coming soon)")
11
+ * .byline-field-file-empty — empty-state hint text
12
+ * .byline-field-file-meta — metadata list
13
+ * .byline-field-file-meta-key — metadata field-name span
14
+ */
15
+
16
+ .dirty,
17
+ :global(.byline-field-file-dirty) {
18
+ padding: var(--spacing-12);
19
+ border: var(--border-width-thin) var(--border-style-solid) var(--blue-300);
20
+ border-radius: var(--border-radius-md);
21
+ }
22
+
23
+ .header,
24
+ :global(.byline-field-file-header) {
25
+ display: flex;
26
+ align-items: baseline;
27
+ justify-content: space-between;
28
+ margin-bottom: 0.25rem;
29
+ }
30
+
31
+ .label,
32
+ :global(.byline-field-file-label) {
33
+ color: var(--gray-100);
34
+ font-size: var(--font-size-sm);
35
+ font-weight: var(--font-weight-medium);
36
+ }
37
+
38
+ .help,
39
+ :global(.byline-field-file-help) {
40
+ margin-top: 0.125rem;
41
+ color: var(--gray-400);
42
+ font-size: var(--font-size-xs);
43
+ }
44
+
45
+ .action,
46
+ :global(.byline-field-file-action) {
47
+ background: none;
48
+ border: none;
49
+ padding: 0;
50
+ color: var(--blue-300);
51
+ font-size: var(--font-size-xs);
52
+ cursor: pointer;
53
+ }
54
+
55
+ .action:hover,
56
+ :global(.byline-field-file-action):hover {
57
+ color: var(--blue-200);
58
+ text-decoration: underline;
59
+ text-underline-offset: 2px;
60
+ }
61
+
62
+ .action:disabled,
63
+ :global(.byline-field-file-action):disabled {
64
+ cursor: not-allowed;
65
+ opacity: 0.6;
66
+ }
67
+
68
+ .empty,
69
+ :global(.byline-field-file-empty) {
70
+ color: var(--gray-500);
71
+ font-size: var(--font-size-xs);
72
+ font-style: italic;
73
+ }
74
+
75
+ .meta,
76
+ :global(.byline-field-file-meta) {
77
+ display: flex;
78
+ flex-direction: column;
79
+ gap: 0.125rem;
80
+ margin-top: 0.25rem;
81
+ color: var(--gray-200);
82
+ font-size: var(--font-size-xs);
83
+ }
84
+
85
+ .meta-key,
86
+ :global(.byline-field-file-meta-key) {
87
+ font-weight: var(--font-weight-semibold);
88
+ }
@@ -0,0 +1,107 @@
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 { FileField as FieldType, StoredFileValue } from '@byline/core'
10
+ import { ErrorText } from '@infonomic/uikit/react'
11
+ import cx from 'classnames'
12
+
13
+ import { useFieldError, useFieldValue, useIsDirty } from '../../forms/form-context'
14
+ import styles from './file-field.module.css'
15
+
16
+ interface FileFieldProps {
17
+ field: FieldType
18
+ // Stored value is currently a plain object with file metadata
19
+ // coming from the seed data / storage layer.
20
+ value?: StoredFileValue | null
21
+ defaultValue?: StoredFileValue | null
22
+ onChange?: (value: StoredFileValue | null) => void
23
+ path?: string
24
+ }
25
+
26
+ export const FileField = ({
27
+ field,
28
+ value,
29
+ defaultValue,
30
+ onChange: _onChange,
31
+ path,
32
+ }: FileFieldProps) => {
33
+ const fieldPath = path ?? field.name
34
+ const fieldError = useFieldError(fieldPath)
35
+ const isDirty = useIsDirty(fieldPath)
36
+ const fieldValue = useFieldValue<StoredFileValue | null | undefined>(fieldPath)
37
+ const incomingValue = value ?? fieldValue ?? defaultValue ?? null
38
+
39
+ const isPlaceholderStoredFileValue = (v: unknown): boolean => {
40
+ if (!v || typeof v !== 'object') return false
41
+ const maybe = v as Partial<StoredFileValue>
42
+ return maybe.storageProvider === 'placeholder' && maybe.storagePath === 'pending'
43
+ }
44
+
45
+ const effectiveValue: StoredFileValue | null = isPlaceholderStoredFileValue(incomingValue)
46
+ ? null
47
+ : incomingValue
48
+
49
+ return (
50
+ <div
51
+ className={cx(
52
+ 'byline-field-file',
53
+ field.name,
54
+ isDirty && ['byline-field-file-dirty', styles.dirty]
55
+ )}
56
+ >
57
+ <div className={cx('byline-field-file-header', styles.header)}>
58
+ <div>
59
+ <div className={cx('byline-field-file-label', styles.label)}>
60
+ {field.label ?? field.name}
61
+ {field.optional ? '' : ' *'}
62
+ </div>
63
+ {field.helpText && (
64
+ <div className={cx('byline-field-file-help', styles.help)}>{field.helpText}</div>
65
+ )}
66
+ </div>
67
+ {/* Placeholder action area for future upload UI */}
68
+ <button type="button" className={cx('byline-field-file-action', styles.action)} disabled>
69
+ Upload (coming soon)
70
+ </button>
71
+ </div>
72
+
73
+ {effectiveValue == null ? (
74
+ <div className={cx('byline-field-file-empty', styles.empty)}>No file selected</div>
75
+ ) : (
76
+ <div className={cx('byline-field-file-meta', styles.meta)}>
77
+ <div>
78
+ <span className={cx('byline-field-file-meta-key', styles['meta-key'])}>Filename:</span>{' '}
79
+ {effectiveValue.filename}
80
+ </div>
81
+ <div>
82
+ <span className={cx('byline-field-file-meta-key', styles['meta-key'])}>Original:</span>{' '}
83
+ {effectiveValue.originalFilename}
84
+ </div>
85
+ <div>
86
+ <span className={cx('byline-field-file-meta-key', styles['meta-key'])}>Type:</span>{' '}
87
+ {effectiveValue.mimeType}
88
+ </div>
89
+ <div>
90
+ <span className={cx('byline-field-file-meta-key', styles['meta-key'])}>Size:</span>{' '}
91
+ {effectiveValue.fileSize}
92
+ </div>
93
+ <div>
94
+ <span className={cx('byline-field-file-meta-key', styles['meta-key'])}>Storage:</span>{' '}
95
+ {effectiveValue.storageProvider}
96
+ </div>
97
+ <div>
98
+ <span className={cx('byline-field-file-meta-key', styles['meta-key'])}>Path:</span>{' '}
99
+ {effectiveValue.storagePath}
100
+ </div>
101
+ </div>
102
+ )}
103
+
104
+ {fieldError && <ErrorText id={`${field.name}-error`} text={fieldError} />}
105
+ </div>
106
+ )
107
+ }
@@ -0,0 +1,43 @@
1
+ /**
2
+ * GroupField — fixed-order group of child fields.
3
+ *
4
+ * Override handles:
5
+ * .byline-field-group — outer wrapper
6
+ * .byline-field-group-header — label/help text block
7
+ * .byline-field-group-title — title heading
8
+ * .byline-field-group-required — required asterisk
9
+ * .byline-field-group-help — help text below title
10
+ * .byline-field-group-body — vertical stack of children
11
+ */
12
+
13
+ .header,
14
+ :global(.byline-field-group-header) {
15
+ display: flex;
16
+ flex-direction: column;
17
+ gap: 0.125rem;
18
+ margin-bottom: var(--spacing-8);
19
+ }
20
+
21
+ .title,
22
+ :global(.byline-field-group-title) {
23
+ font-size: 1rem;
24
+ font-weight: var(--font-weight-medium);
25
+ }
26
+
27
+ .required,
28
+ :global(.byline-field-group-required) {
29
+ color: var(--red-500);
30
+ }
31
+
32
+ .help,
33
+ :global(.byline-field-group-help) {
34
+ color: var(--gray-500);
35
+ font-size: var(--font-size-xs);
36
+ }
37
+
38
+ .body,
39
+ :global(.byline-field-group-body) {
40
+ display: flex;
41
+ flex-direction: column;
42
+ gap: var(--spacing-8);
43
+ }
@@ -0,0 +1,84 @@
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 { useMemo } from 'react'
10
+
11
+ import type { Field, GroupField as GroupFieldType } from '@byline/core'
12
+ import { ErrorText } from '@infonomic/uikit/react'
13
+ import cx from 'classnames'
14
+
15
+ import { placeholderForField } from '../../fields/field-helpers'
16
+ import { FieldRenderer } from '../../fields/field-renderer'
17
+ import { useFieldError } from '../../forms/form-context'
18
+ import styles from './group-field.module.css'
19
+
20
+ // ---------------------------------------------------------------------------
21
+ // GroupField — renders a fixed-order group of child fields wrapped in a
22
+ // single div. No drag-and-drop. No add/remove.
23
+ // The outer div carries the field type ('group') and field name as classes
24
+ // so consumers can target individual groups via CSS.
25
+ //
26
+ // Stable override handles: `.byline-field-group`, `.byline-field-group-header`,
27
+ // `.byline-field-group-title`, `.byline-field-group-help`,
28
+ // `.byline-field-group-body`.
29
+ // ---------------------------------------------------------------------------
30
+
31
+ interface GroupFieldProps {
32
+ field: GroupFieldType
33
+ defaultValue: any
34
+ path: string
35
+ }
36
+
37
+ export const GroupField = ({ field, defaultValue, path }: GroupFieldProps) => {
38
+ const fieldError = useFieldError(field.name)
39
+ // Default value for a group field is a plain object: { rating: 5, comment: '...' }
40
+ // Normalize to a plain object if not already one.
41
+ const groupData = useMemo(() => {
42
+ if (defaultValue && typeof defaultValue === 'object' && !Array.isArray(defaultValue)) {
43
+ return defaultValue
44
+ }
45
+ // Fallback: build a placeholder object from child field definitions
46
+ const placeholder: Record<string, any> = {}
47
+ for (const childField of field.fields as Field[]) {
48
+ placeholder[childField.name] = placeholderForField(childField)
49
+ }
50
+ return placeholder
51
+ }, [defaultValue, field.fields])
52
+
53
+ return (
54
+ <div className={`byline-field-group ${field.name}`}>
55
+ {field.label && (
56
+ <div className={cx('byline-field-group-header', styles.header)}>
57
+ <h3 className={cx('byline-field-group-title', styles.title)}>
58
+ {field.label}{' '}
59
+ {!field.optional && (
60
+ <span className={cx('byline-field-group-required', styles.required)}>*</span>
61
+ )}
62
+ </h3>
63
+ {field.helpText && (
64
+ <p className={cx('byline-field-group-help', styles.help)}>{field.helpText}</p>
65
+ )}
66
+ </div>
67
+ )}
68
+ <div className={cx('byline-field-group-body', styles.body)}>
69
+ {(field.fields as Field[]).map((innerField) => {
70
+ return (
71
+ <FieldRenderer
72
+ key={innerField.name}
73
+ field={innerField}
74
+ defaultValue={groupData[innerField.name]}
75
+ basePath={path}
76
+ disableSorting={true}
77
+ />
78
+ )
79
+ })}
80
+ </div>
81
+ {fieldError && <ErrorText id={`${field.name}-error`} text={fieldError} />}
82
+ </div>
83
+ )
84
+ }