@olaboot/esm-form-engine-lib 4.1.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 (628) hide show
  1. package/LICENSE.txt +401 -0
  2. package/README.md +202 -0
  3. package/dist/adapters/control-adapter.d.ts +3 -0
  4. package/dist/adapters/control-adapter.d.ts.map +1 -0
  5. package/dist/adapters/control-adapter.js +17 -0
  6. package/dist/adapters/encounter-datetime-adapter.d.ts +3 -0
  7. package/dist/adapters/encounter-datetime-adapter.d.ts.map +1 -0
  8. package/dist/adapters/encounter-datetime-adapter.js +26 -0
  9. package/dist/adapters/encounter-diagnosis-adapter.d.ts +10 -0
  10. package/dist/adapters/encounter-diagnosis-adapter.d.ts.map +1 -0
  11. package/dist/adapters/encounter-diagnosis-adapter.js +89 -0
  12. package/dist/adapters/encounter-diagnosis-adapter.test.js +217 -0
  13. package/dist/adapters/encounter-location-adapter.d.ts +3 -0
  14. package/dist/adapters/encounter-location-adapter.d.ts.map +1 -0
  15. package/dist/adapters/encounter-location-adapter.js +25 -0
  16. package/dist/adapters/encounter-provider-adapter.d.ts +3 -0
  17. package/dist/adapters/encounter-provider-adapter.d.ts.map +1 -0
  18. package/dist/adapters/encounter-provider-adapter.js +34 -0
  19. package/dist/adapters/encounter-role-adapter.d.ts +3 -0
  20. package/dist/adapters/encounter-role-adapter.d.ts.map +1 -0
  21. package/dist/adapters/encounter-role-adapter.js +40 -0
  22. package/dist/adapters/inline-date-adapter.d.ts +3 -0
  23. package/dist/adapters/inline-date-adapter.d.ts.map +1 -0
  24. package/dist/adapters/inline-date-adapter.js +56 -0
  25. package/dist/adapters/obs-adapter.d.ts +29 -0
  26. package/dist/adapters/obs-adapter.d.ts.map +1 -0
  27. package/dist/adapters/obs-adapter.js +284 -0
  28. package/dist/adapters/obs-adapter.test.js +1443 -0
  29. package/dist/adapters/obs-comment-adapter.d.ts +4 -0
  30. package/dist/adapters/obs-comment-adapter.d.ts.map +1 -0
  31. package/dist/adapters/obs-comment-adapter.js +52 -0
  32. package/dist/adapters/orders-adapter.d.ts +4 -0
  33. package/dist/adapters/orders-adapter.d.ts.map +1 -0
  34. package/dist/adapters/orders-adapter.js +64 -0
  35. package/dist/adapters/patient-identifier-adapter.d.ts +3 -0
  36. package/dist/adapters/patient-identifier-adapter.d.ts.map +1 -0
  37. package/dist/adapters/patient-identifier-adapter.js +40 -0
  38. package/dist/adapters/person-attribute-adapter.d.ts +3 -0
  39. package/dist/adapters/person-attribute-adapter.d.ts.map +1 -0
  40. package/dist/adapters/person-attribute-adapter.js +39 -0
  41. package/dist/adapters/person-attribute-adapter.test.js +146 -0
  42. package/dist/adapters/program-state-adapter.d.ts +3 -0
  43. package/dist/adapters/program-state-adapter.d.ts.map +1 -0
  44. package/dist/adapters/program-state-adapter.js +41 -0
  45. package/dist/adapters/program-state-adapter.test.js +411 -0
  46. package/dist/api/index.d.ts +27 -0
  47. package/dist/api/index.d.ts.map +1 -0
  48. package/dist/api/index.js +170 -0
  49. package/dist/components/error/error-modal.component.d.ts +7 -0
  50. package/dist/components/error/error-modal.component.d.ts.map +1 -0
  51. package/dist/components/error/error-modal.component.js +31 -0
  52. package/dist/components/error/error.scss +4 -0
  53. package/dist/components/extension/extension-parcel.component.d.ts +5 -0
  54. package/dist/components/extension/extension-parcel.component.d.ts.map +1 -0
  55. package/dist/components/extension/extension-parcel.component.js +35 -0
  56. package/dist/components/field-label/field-label.component.d.ts +12 -0
  57. package/dist/components/field-label/field-label.component.d.ts.map +1 -0
  58. package/dist/components/field-label/field-label.component.js +33 -0
  59. package/dist/components/field-label/field-label.scss +15 -0
  60. package/dist/components/group/obs-group.component.d.ts +5 -0
  61. package/dist/components/group/obs-group.component.d.ts.map +1 -0
  62. package/dist/components/group/obs-group.component.js +48 -0
  63. package/dist/components/group/obs-group.scss +16 -0
  64. package/dist/components/inputs/content-switcher/content-switcher.component.d.ts +5 -0
  65. package/dist/components/inputs/content-switcher/content-switcher.component.d.ts.map +1 -0
  66. package/dist/components/inputs/content-switcher/content-switcher.component.js +70 -0
  67. package/dist/components/inputs/content-switcher/content-switcher.scss +55 -0
  68. package/dist/components/inputs/date/date.component.d.ts +5 -0
  69. package/dist/components/inputs/date/date.component.d.ts.map +1 -0
  70. package/dist/components/inputs/date/date.component.js +125 -0
  71. package/dist/components/inputs/date/date.scss +37 -0
  72. package/dist/components/inputs/date/date.test.js +85 -0
  73. package/dist/components/inputs/file/file-thumbnail.component.d.ts +10 -0
  74. package/dist/components/inputs/file/file-thumbnail.component.d.ts.map +1 -0
  75. package/dist/components/inputs/file/file-thumbnail.component.js +51 -0
  76. package/dist/components/inputs/file/file-thumbnail.scss +42 -0
  77. package/dist/components/inputs/file/file.component.d.ts +5 -0
  78. package/dist/components/inputs/file/file.component.d.ts.map +1 -0
  79. package/dist/components/inputs/file/file.component.js +90 -0
  80. package/dist/components/inputs/file/file.scss +21 -0
  81. package/dist/components/inputs/fixed-value/fixed-value.component.d.ts +5 -0
  82. package/dist/components/inputs/fixed-value/fixed-value.component.d.ts.map +1 -0
  83. package/dist/components/inputs/fixed-value/fixed-value.component.js +14 -0
  84. package/dist/components/inputs/markdown/markdown-wrapper.component.d.ts +6 -0
  85. package/dist/components/inputs/markdown/markdown-wrapper.component.d.ts.map +1 -0
  86. package/dist/components/inputs/markdown/markdown-wrapper.component.js +20 -0
  87. package/dist/components/inputs/markdown/markdown.component.d.ts +5 -0
  88. package/dist/components/inputs/markdown/markdown.component.d.ts.map +1 -0
  89. package/dist/components/inputs/markdown/markdown.component.js +26 -0
  90. package/dist/components/inputs/multi-select/multi-select.component.d.ts +5 -0
  91. package/dist/components/inputs/multi-select/multi-select.component.d.ts.map +1 -0
  92. package/dist/components/inputs/multi-select/multi-select.component.js +134 -0
  93. package/dist/components/inputs/multi-select/multi-select.scss +25 -0
  94. package/dist/components/inputs/multi-select/multi-select.test.js +106 -0
  95. package/dist/components/inputs/number/number.component.d.ts +5 -0
  96. package/dist/components/inputs/number/number.component.d.ts.map +1 -0
  97. package/dist/components/inputs/number/number.component.js +77 -0
  98. package/dist/components/inputs/number/number.scss +15 -0
  99. package/dist/components/inputs/number/number.test.js +98 -0
  100. package/dist/components/inputs/radio/radio.component.d.ts +5 -0
  101. package/dist/components/inputs/radio/radio.component.d.ts.map +1 -0
  102. package/dist/components/inputs/radio/radio.component.js +69 -0
  103. package/dist/components/inputs/radio/radio.scss +36 -0
  104. package/dist/components/inputs/radio/radio.test.js +190 -0
  105. package/dist/components/inputs/select/dropdown.component.d.ts +5 -0
  106. package/dist/components/inputs/select/dropdown.component.d.ts.map +1 -0
  107. package/dist/components/inputs/select/dropdown.component.js +82 -0
  108. package/dist/components/inputs/select/dropdown.scss +11 -0
  109. package/dist/components/inputs/select/dropdown.test.js +157 -0
  110. package/dist/components/inputs/text/text.component.d.ts +5 -0
  111. package/dist/components/inputs/text/text.component.d.ts.map +1 -0
  112. package/dist/components/inputs/text/text.component.js +62 -0
  113. package/dist/components/inputs/text/text.scss +15 -0
  114. package/dist/components/inputs/text/text.test.js +184 -0
  115. package/dist/components/inputs/text-area/text-area.component.d.ts +5 -0
  116. package/dist/components/inputs/text-area/text-area.component.d.ts.map +1 -0
  117. package/dist/components/inputs/text-area/text-area.component.js +60 -0
  118. package/dist/components/inputs/text-area/text-area.scss +11 -0
  119. package/dist/components/inputs/toggle/toggle.component.d.ts +5 -0
  120. package/dist/components/inputs/toggle/toggle.component.d.ts.map +1 -0
  121. package/dist/components/inputs/toggle/toggle.component.js +57 -0
  122. package/dist/components/inputs/toggle/toggle.scss +12 -0
  123. package/dist/components/inputs/ui-select-extended/ui-select-extended.component.d.ts +5 -0
  124. package/dist/components/inputs/ui-select-extended/ui-select-extended.component.d.ts.map +1 -0
  125. package/dist/components/inputs/ui-select-extended/ui-select-extended.component.js +203 -0
  126. package/dist/components/inputs/ui-select-extended/ui-select-extended.scss +19 -0
  127. package/dist/components/inputs/ui-select-extended/ui-select-extended.test.js +250 -0
  128. package/dist/components/inputs/unspecified/unspecified.component.d.ts +11 -0
  129. package/dist/components/inputs/unspecified/unspecified.component.d.ts.map +1 -0
  130. package/dist/components/inputs/unspecified/unspecified.component.js +65 -0
  131. package/dist/components/inputs/unspecified/unspecified.scss +7 -0
  132. package/dist/components/inputs/unspecified/unspecified.test.js +152 -0
  133. package/dist/components/inputs/workspace-launcher/workspace-launcher.component.d.ts +5 -0
  134. package/dist/components/inputs/workspace-launcher/workspace-launcher.component.d.ts.map +1 -0
  135. package/dist/components/inputs/workspace-launcher/workspace-launcher.component.js +64 -0
  136. package/dist/components/inputs/workspace-launcher/workspace-launcher.scss +21 -0
  137. package/dist/components/inputs/workspace-launcher/workspace-launcher.test.js +174 -0
  138. package/dist/components/label/label.component.d.ts +8 -0
  139. package/dist/components/label/label.component.d.ts.map +1 -0
  140. package/dist/components/label/label.component.js +15 -0
  141. package/dist/components/label/label.scss +15 -0
  142. package/dist/components/loaders/loader.component.d.ts +4 -0
  143. package/dist/components/loaders/loader.component.d.ts.map +1 -0
  144. package/dist/components/loaders/loader.component.js +14 -0
  145. package/dist/components/loaders/loader.scss +20 -0
  146. package/dist/components/patient-banner/patient-banner.component.d.ts +7 -0
  147. package/dist/components/patient-banner/patient-banner.component.d.ts.map +1 -0
  148. package/dist/components/patient-banner/patient-banner.component.js +16 -0
  149. package/dist/components/patient-banner/patient-banner.scss +12 -0
  150. package/dist/components/previous-value-review/previous-value-review.component.d.ts +12 -0
  151. package/dist/components/previous-value-review/previous-value-review.component.d.ts.map +1 -0
  152. package/dist/components/previous-value-review/previous-value-review.component.js +29 -0
  153. package/dist/components/previous-value-review/previous-value-review.scss +36 -0
  154. package/dist/components/processor-factory/form-processor-factory.component.d.ts +10 -0
  155. package/dist/components/processor-factory/form-processor-factory.component.d.ts.map +1 -0
  156. package/dist/components/processor-factory/form-processor-factory.component.js +114 -0
  157. package/dist/components/renderer/custom-hooks-renderer.component.d.ts +13 -0
  158. package/dist/components/renderer/custom-hooks-renderer.component.d.ts.map +1 -0
  159. package/dist/components/renderer/custom-hooks-renderer.component.js +13 -0
  160. package/dist/components/renderer/field/fieldLogic.d.ts +16 -0
  161. package/dist/components/renderer/field/fieldLogic.d.ts.map +1 -0
  162. package/dist/components/renderer/field/fieldLogic.js +238 -0
  163. package/dist/components/renderer/field/fieldLogic.test.js +140 -0
  164. package/dist/components/renderer/field/fieldRenderUtils.d.ts +9 -0
  165. package/dist/components/renderer/field/fieldRenderUtils.d.ts.map +1 -0
  166. package/dist/components/renderer/field/fieldRenderUtils.js +8 -0
  167. package/dist/components/renderer/field/fieldRenderUtils.test.js +51 -0
  168. package/dist/components/renderer/field/form-field-renderer.component.d.ts +19 -0
  169. package/dist/components/renderer/field/form-field-renderer.component.d.ts.map +1 -0
  170. package/dist/components/renderer/field/form-field-renderer.component.js +214 -0
  171. package/dist/components/renderer/field/form-field-renderer.scss +5 -0
  172. package/dist/components/renderer/form/form-renderer.component.d.ts +10 -0
  173. package/dist/components/renderer/form/form-renderer.component.d.ts.map +1 -0
  174. package/dist/components/renderer/form/form-renderer.component.js +102 -0
  175. package/dist/components/renderer/form/state.d.ts +41 -0
  176. package/dist/components/renderer/form/state.d.ts.map +1 -0
  177. package/dist/components/renderer/form/state.js +69 -0
  178. package/dist/components/renderer/page/page.renderer.component.d.ts +9 -0
  179. package/dist/components/renderer/page/page.renderer.component.d.ts.map +1 -0
  180. package/dist/components/renderer/page/page.renderer.component.js +85 -0
  181. package/dist/components/renderer/page/page.renderer.scss +74 -0
  182. package/dist/components/renderer/section/section-renderer.component.d.ts +6 -0
  183. package/dist/components/renderer/section/section-renderer.component.d.ts.map +1 -0
  184. package/dist/components/renderer/section/section-renderer.component.js +20 -0
  185. package/dist/components/renderer/section/section-renderer.scss +19 -0
  186. package/dist/components/repeat/helpers.d.ts +6 -0
  187. package/dist/components/repeat/helpers.d.ts.map +1 -0
  188. package/dist/components/repeat/helpers.js +64 -0
  189. package/dist/components/repeat/helpers.test.js +25 -0
  190. package/dist/components/repeat/repeat-controls.component.d.ts +12 -0
  191. package/dist/components/repeat/repeat-controls.component.d.ts.map +1 -0
  192. package/dist/components/repeat/repeat-controls.component.js +22 -0
  193. package/dist/components/repeat/repeat-controls.scss +7 -0
  194. package/dist/components/repeat/repeat.component.d.ts +5 -0
  195. package/dist/components/repeat/repeat.component.d.ts.map +1 -0
  196. package/dist/components/repeat/repeat.component.js +185 -0
  197. package/dist/components/repeat/repeat.scss +30 -0
  198. package/dist/components/repeat/repeat.test.js +25 -0
  199. package/dist/components/sidebar/page-observer.d.ts +20 -0
  200. package/dist/components/sidebar/page-observer.d.ts.map +1 -0
  201. package/dist/components/sidebar/page-observer.js +60 -0
  202. package/dist/components/sidebar/sidebar.component.d.ts +14 -0
  203. package/dist/components/sidebar/sidebar.component.d.ts.map +1 -0
  204. package/dist/components/sidebar/sidebar.component.js +77 -0
  205. package/dist/components/sidebar/sidebar.scss +114 -0
  206. package/dist/components/sidebar/useCurrentActivePage.d.ts +34 -0
  207. package/dist/components/sidebar/useCurrentActivePage.d.ts.map +1 -0
  208. package/dist/components/sidebar/useCurrentActivePage.js +114 -0
  209. package/dist/components/sidebar/useCurrentActivePage.test.js +208 -0
  210. package/dist/components/sidebar/usePageObserver.d.ts +11 -0
  211. package/dist/components/sidebar/usePageObserver.d.ts.map +1 -0
  212. package/dist/components/sidebar/usePageObserver.js +42 -0
  213. package/dist/components/value/value.component.d.ts +6 -0
  214. package/dist/components/value/value.component.d.ts.map +1 -0
  215. package/dist/components/value/value.component.js +24 -0
  216. package/dist/components/value/value.scss +17 -0
  217. package/dist/components/value/view/field-value-view.component.d.ts +10 -0
  218. package/dist/components/value/view/field-value-view.component.d.ts.map +1 -0
  219. package/dist/components/value/view/field-value-view.component.js +29 -0
  220. package/dist/components/value/view/field-value-view.scss +31 -0
  221. package/dist/constants.d.ts +9 -0
  222. package/dist/constants.d.ts.map +1 -0
  223. package/dist/constants.js +13 -0
  224. package/dist/datasources/concept-data-source.d.ts +6 -0
  225. package/dist/datasources/concept-data-source.d.ts.map +1 -0
  226. package/dist/datasources/concept-data-source.js +35 -0
  227. package/dist/datasources/data-source.d.ts +10 -0
  228. package/dist/datasources/data-source.d.ts.map +1 -0
  229. package/dist/datasources/data-source.js +41 -0
  230. package/dist/datasources/encounter-role-datasource.d.ts +6 -0
  231. package/dist/datasources/encounter-role-datasource.d.ts.map +1 -0
  232. package/dist/datasources/encounter-role-datasource.js +13 -0
  233. package/dist/datasources/historical-data-source.d.ts +6 -0
  234. package/dist/datasources/historical-data-source.d.ts.map +1 -0
  235. package/dist/datasources/historical-data-source.js +24 -0
  236. package/dist/datasources/location-data-source.d.ts +6 -0
  237. package/dist/datasources/location-data-source.d.ts.map +1 -0
  238. package/dist/datasources/location-data-source.js +24 -0
  239. package/dist/datasources/provider-datasource.d.ts +6 -0
  240. package/dist/datasources/provider-datasource.d.ts.map +1 -0
  241. package/dist/datasources/provider-datasource.js +13 -0
  242. package/dist/datasources/select-concept-answers-datasource.d.ts +9 -0
  243. package/dist/datasources/select-concept-answers-datasource.d.ts.map +1 -0
  244. package/dist/datasources/select-concept-answers-datasource.js +19 -0
  245. package/dist/declarations.d.js +0 -0
  246. package/dist/external-function-context.d.ts +7 -0
  247. package/dist/external-function-context.d.ts.map +1 -0
  248. package/dist/external-function-context.js +2 -0
  249. package/dist/form-engine.component.d.ts +23 -0
  250. package/dist/form-engine.component.d.ts.map +1 -0
  251. package/dist/form-engine.component.js +174 -0
  252. package/dist/form-engine.scss +148 -0
  253. package/dist/form-engine.test.js +1253 -0
  254. package/dist/globals.d.ts +3 -0
  255. package/dist/globals.d.ts.map +1 -0
  256. package/dist/globals.js +2 -0
  257. package/dist/hooks/useConcepts.d.ts +23 -0
  258. package/dist/hooks/useConcepts.d.ts.map +1 -0
  259. package/dist/hooks/useConcepts.js +31 -0
  260. package/dist/hooks/useDataSourceDependentValue.d.ts +4 -0
  261. package/dist/hooks/useDataSourceDependentValue.d.ts.map +1 -0
  262. package/dist/hooks/useDataSourceDependentValue.js +14 -0
  263. package/dist/hooks/useEncounter.d.ts +7 -0
  264. package/dist/hooks/useEncounter.d.ts.map +1 -0
  265. package/dist/hooks/useEncounter.js +38 -0
  266. package/dist/hooks/useEncounterRole.d.ts +7 -0
  267. package/dist/hooks/useEncounterRole.d.ts.map +1 -0
  268. package/dist/hooks/useEncounterRole.js +18 -0
  269. package/dist/hooks/useEvaluateFormFieldExpressions.d.ts +7 -0
  270. package/dist/hooks/useEvaluateFormFieldExpressions.d.ts.map +1 -0
  271. package/dist/hooks/useEvaluateFormFieldExpressions.js +112 -0
  272. package/dist/hooks/useExternalFormAction.d.ts +43 -0
  273. package/dist/hooks/useExternalFormAction.d.ts.map +1 -0
  274. package/dist/hooks/useExternalFormAction.js +71 -0
  275. package/dist/hooks/useFormCollapse.d.ts +6 -0
  276. package/dist/hooks/useFormCollapse.d.ts.map +1 -0
  277. package/dist/hooks/useFormCollapse.js +35 -0
  278. package/dist/hooks/useFormFieldValidators.d.ts +3 -0
  279. package/dist/hooks/useFormFieldValidators.d.ts.map +1 -0
  280. package/dist/hooks/useFormFieldValidators.js +20 -0
  281. package/dist/hooks/useFormFieldValueAdapters.d.ts +3 -0
  282. package/dist/hooks/useFormFieldValueAdapters.d.ts.map +1 -0
  283. package/dist/hooks/useFormFieldValueAdapters.js +21 -0
  284. package/dist/hooks/useFormFields.d.ts +6 -0
  285. package/dist/hooks/useFormFields.d.ts.map +1 -0
  286. package/dist/hooks/useFormFields.js +62 -0
  287. package/dist/hooks/useFormFieldsMeta.d.ts +4 -0
  288. package/dist/hooks/useFormFieldsMeta.d.ts.map +1 -0
  289. package/dist/hooks/useFormFieldsMeta.js +42 -0
  290. package/dist/hooks/useFormJson.d.ts +19 -0
  291. package/dist/hooks/useFormJson.d.ts.map +1 -0
  292. package/dist/hooks/useFormJson.js +198 -0
  293. package/dist/hooks/useFormJson.test.js +194 -0
  294. package/dist/hooks/useFormStateHelpers.d.ts +15 -0
  295. package/dist/hooks/useFormStateHelpers.d.ts.map +1 -0
  296. package/dist/hooks/useFormStateHelpers.js +83 -0
  297. package/dist/hooks/useFormWorkspaceSize.d.ts +7 -0
  298. package/dist/hooks/useFormWorkspaceSize.d.ts.map +1 -0
  299. package/dist/hooks/useFormWorkspaceSize.js +46 -0
  300. package/dist/hooks/useFormWorkspaceSize.test.js +141 -0
  301. package/dist/hooks/useInitialValues.d.ts +9 -0
  302. package/dist/hooks/useInitialValues.d.ts.map +1 -0
  303. package/dist/hooks/useInitialValues.js +29 -0
  304. package/dist/hooks/useInitialValues.test.js +78 -0
  305. package/dist/hooks/usePatientData.d.ts +6 -0
  306. package/dist/hooks/usePatientData.d.ts.map +1 -0
  307. package/dist/hooks/usePatientData.js +30 -0
  308. package/dist/hooks/usePatientPrograms.d.ts +7 -0
  309. package/dist/hooks/usePatientPrograms.d.ts.map +1 -0
  310. package/dist/hooks/usePatientPrograms.js +22 -0
  311. package/dist/hooks/usePostSubmissionActions.d.ts +13 -0
  312. package/dist/hooks/usePostSubmissionActions.d.ts.map +1 -0
  313. package/dist/hooks/usePostSubmissionActions.js +23 -0
  314. package/dist/hooks/usePostSubmissionActions.test.js +55 -0
  315. package/dist/hooks/useProcessorDependencies.d.ts +8 -0
  316. package/dist/hooks/useProcessorDependencies.d.ts.map +1 -0
  317. package/dist/hooks/useProcessorDependencies.js +33 -0
  318. package/dist/index.d.ts +12 -0
  319. package/dist/index.d.ts.map +1 -0
  320. package/dist/index.js +11 -0
  321. package/dist/lifecycle.d.ts +11 -0
  322. package/dist/lifecycle.d.ts.map +1 -0
  323. package/dist/lifecycle.js +25 -0
  324. package/dist/post-submission-actions/mark-patient-deceased-action.d.ts +4 -0
  325. package/dist/post-submission-actions/mark-patient-deceased-action.d.ts.map +1 -0
  326. package/dist/post-submission-actions/mark-patient-deceased-action.js +53 -0
  327. package/dist/post-submission-actions/program-enrollment-action.d.ts +4 -0
  328. package/dist/post-submission-actions/program-enrollment-action.d.ts.map +1 -0
  329. package/dist/post-submission-actions/program-enrollment-action.js +105 -0
  330. package/dist/processors/encounter/encounter-form-processor.d.ts +26 -0
  331. package/dist/processors/encounter/encounter-form-processor.d.ts.map +1 -0
  332. package/dist/processors/encounter/encounter-form-processor.js +376 -0
  333. package/dist/processors/encounter/encounter-form-processor.test.js +207 -0
  334. package/dist/processors/encounter/encounter-processor-helper.d.ts +19 -0
  335. package/dist/processors/encounter/encounter-processor-helper.d.ts.map +1 -0
  336. package/dist/processors/encounter/encounter-processor-helper.js +293 -0
  337. package/dist/processors/form-processor.d.ts +25 -0
  338. package/dist/processors/form-processor.d.ts.map +1 -0
  339. package/dist/processors/form-processor.js +26 -0
  340. package/dist/provider/form-factory-helper.d.ts +8 -0
  341. package/dist/provider/form-factory-helper.d.ts.map +1 -0
  342. package/dist/provider/form-factory-helper.js +73 -0
  343. package/dist/provider/form-factory-provider.d.ts +48 -0
  344. package/dist/provider/form-factory-provider.d.ts.map +1 -0
  345. package/dist/provider/form-factory-provider.js +136 -0
  346. package/dist/provider/form-provider.d.ts +26 -0
  347. package/dist/provider/form-provider.d.ts.map +1 -0
  348. package/dist/provider/form-provider.js +17 -0
  349. package/dist/registry/inbuilt-components/InbuiltPostSubmissionActions.d.ts +4 -0
  350. package/dist/registry/inbuilt-components/InbuiltPostSubmissionActions.d.ts.map +1 -0
  351. package/dist/registry/inbuilt-components/InbuiltPostSubmissionActions.js +10 -0
  352. package/dist/registry/inbuilt-components/control-templates.d.ts +4 -0
  353. package/dist/registry/inbuilt-components/control-templates.d.ts.map +1 -0
  354. package/dist/registry/inbuilt-components/control-templates.js +54 -0
  355. package/dist/registry/inbuilt-components/inbuiltControls.d.ts +7 -0
  356. package/dist/registry/inbuilt-components/inbuiltControls.d.ts.map +1 -0
  357. package/dist/registry/inbuilt-components/inbuiltControls.js +94 -0
  358. package/dist/registry/inbuilt-components/inbuiltDataSources.d.ts +8 -0
  359. package/dist/registry/inbuilt-components/inbuiltDataSources.d.ts.map +1 -0
  360. package/dist/registry/inbuilt-components/inbuiltDataSources.js +36 -0
  361. package/dist/registry/inbuilt-components/inbuiltFieldValueAdapters.d.ts +4 -0
  362. package/dist/registry/inbuilt-components/inbuiltFieldValueAdapters.d.ts.map +1 -0
  363. package/dist/registry/inbuilt-components/inbuiltFieldValueAdapters.js +71 -0
  364. package/dist/registry/inbuilt-components/inbuiltTransformers.d.ts +4 -0
  365. package/dist/registry/inbuilt-components/inbuiltTransformers.d.ts.map +1 -0
  366. package/dist/registry/inbuilt-components/inbuiltTransformers.js +7 -0
  367. package/dist/registry/inbuilt-components/inbuiltValidators.d.ts +7 -0
  368. package/dist/registry/inbuilt-components/inbuiltValidators.d.ts.map +1 -0
  369. package/dist/registry/inbuilt-components/inbuiltValidators.js +29 -0
  370. package/dist/registry/inbuilt-components/template-component-map.d.ts +5 -0
  371. package/dist/registry/inbuilt-components/template-component-map.d.ts.map +1 -0
  372. package/dist/registry/inbuilt-components/template-component-map.js +27 -0
  373. package/dist/registry/registry.d.ts +61 -0
  374. package/dist/registry/registry.d.ts.map +1 -0
  375. package/dist/registry/registry.js +184 -0
  376. package/dist/registry/registry.test.js +17 -0
  377. package/dist/setup-tests.js +30 -0
  378. package/dist/transformers/default-schema-transformer.d.ts +4 -0
  379. package/dist/transformers/default-schema-transformer.d.ts.map +1 -0
  380. package/dist/transformers/default-schema-transformer.js +308 -0
  381. package/dist/transformers/default-schema-transformer.test.js +319 -0
  382. package/dist/types/domain.d.ts +219 -0
  383. package/dist/types/domain.d.ts.map +1 -0
  384. package/dist/types/domain.js +1 -0
  385. package/dist/types/index.d.ts +126 -0
  386. package/dist/types/index.d.ts.map +1 -0
  387. package/dist/types/index.js +2 -0
  388. package/dist/types/schema.d.ts +243 -0
  389. package/dist/types/schema.d.ts.map +1 -0
  390. package/dist/types/schema.js +1 -0
  391. package/dist/typings.d.js +1 -0
  392. package/dist/utils/boolean-utils.d.ts +13 -0
  393. package/dist/utils/boolean-utils.d.ts.map +1 -0
  394. package/dist/utils/boolean-utils.js +22 -0
  395. package/dist/utils/common-expression-helpers.d.ts +261 -0
  396. package/dist/utils/common-expression-helpers.d.ts.map +1 -0
  397. package/dist/utils/common-expression-helpers.js +538 -0
  398. package/dist/utils/common-expression-helpers.test.js +461 -0
  399. package/dist/utils/common-utils.d.ts +51 -0
  400. package/dist/utils/common-utils.d.ts.map +1 -0
  401. package/dist/utils/common-utils.js +102 -0
  402. package/dist/utils/common-utils.test.js +134 -0
  403. package/dist/utils/error-utils.d.ts +11 -0
  404. package/dist/utils/error-utils.d.ts.map +1 -0
  405. package/dist/utils/error-utils.js +34 -0
  406. package/dist/utils/expression-runner.d.ts +25 -0
  407. package/dist/utils/expression-runner.d.ts.map +1 -0
  408. package/dist/utils/expression-runner.js +104 -0
  409. package/dist/utils/expression-runner.test.js +362 -0
  410. package/dist/utils/form-helper.d.ts +37 -0
  411. package/dist/utils/form-helper.d.ts.map +1 -0
  412. package/dist/utils/form-helper.js +239 -0
  413. package/dist/utils/form-helper.test.js +638 -0
  414. package/dist/utils/form-page-utils.d.ts +3 -0
  415. package/dist/utils/form-page-utils.d.ts.map +1 -0
  416. package/dist/utils/form-page-utils.js +10 -0
  417. package/dist/utils/forms-loader.d.ts +45 -0
  418. package/dist/utils/forms-loader.d.ts.map +1 -0
  419. package/dist/utils/forms-loader.js +246 -0
  420. package/dist/utils/forms-loader.test.js +333 -0
  421. package/dist/utils/post-submission-action-helper.d.ts +2 -0
  422. package/dist/utils/post-submission-action-helper.d.ts.map +1 -0
  423. package/dist/utils/post-submission-action-helper.js +57 -0
  424. package/dist/utils/test-utils.js +66 -0
  425. package/dist/utils/zscore-service.d.ts +6 -0
  426. package/dist/utils/zscore-service.d.ts.map +1 -0
  427. package/dist/utils/zscore-service.js +54 -0
  428. package/dist/validators/conditional-answered-validator.d.ts +3 -0
  429. package/dist/validators/conditional-answered-validator.d.ts.map +1 -0
  430. package/dist/validators/conditional-answered-validator.js +18 -0
  431. package/dist/validators/conditional-answered-validator.test.js +63 -0
  432. package/dist/validators/date-validator.d.ts +3 -0
  433. package/dist/validators/date-validator.d.ts.map +1 -0
  434. package/dist/validators/date-validator.js +21 -0
  435. package/dist/validators/date-validator.test.js +53 -0
  436. package/dist/validators/default-value-validator.d.ts +3 -0
  437. package/dist/validators/default-value-validator.d.ts.map +1 -0
  438. package/dist/validators/default-value-validator.js +46 -0
  439. package/dist/validators/default-value-validator.test.js +95 -0
  440. package/dist/validators/form-validator.d.ts +9 -0
  441. package/dist/validators/form-validator.d.ts.map +1 -0
  442. package/dist/validators/form-validator.js +82 -0
  443. package/dist/validators/form-validator.test.js +158 -0
  444. package/dist/validators/js-expression-validator.d.ts +3 -0
  445. package/dist/validators/js-expression-validator.d.ts.map +1 -0
  446. package/dist/validators/js-expression-validator.js +25 -0
  447. package/dist/validators/js-expression-validator.test.js +115 -0
  448. package/dist/validators/schema.d.ts +1 -0
  449. package/dist/validators/schema.d.ts.map +1 -0
  450. package/dist/validators/schema.js +32 -0
  451. package/dist/zscore/bfa_boys_5_above.json +2522 -0
  452. package/dist/zscore/bfa_girls_5_above.json +2522 -0
  453. package/dist/zscore/hfa_boys_5_above.json +2186 -0
  454. package/dist/zscore/hfa_boys_below5.json +22286 -0
  455. package/dist/zscore/hfa_girls_5_above.json +2186 -0
  456. package/dist/zscore/hfa_girls_below5.json +22286 -0
  457. package/dist/zscore/wfl_boys_below5.json +7814 -0
  458. package/dist/zscore/wfl_girls_below5.json +7814 -0
  459. package/dist/zscore-tests/bmi-age.test.js +84 -0
  460. package/dist/zscore-tests/height-age.test.js +88 -0
  461. package/dist/zscore-tests/weight-height.test.js +82 -0
  462. package/package.json +105 -0
  463. package/src/adapters/control-adapter.ts +29 -0
  464. package/src/adapters/encounter-datetime-adapter.ts +38 -0
  465. package/src/adapters/encounter-diagnosis-adapter.ts +121 -0
  466. package/src/adapters/encounter-location-adapter.ts +39 -0
  467. package/src/adapters/encounter-provider-adapter.ts +48 -0
  468. package/src/adapters/encounter-role-adapter.ts +54 -0
  469. package/src/adapters/inline-date-adapter.ts +59 -0
  470. package/src/adapters/obs-adapter.ts +349 -0
  471. package/src/adapters/obs-comment-adapter.ts +61 -0
  472. package/src/adapters/orders-adapter.ts +82 -0
  473. package/src/adapters/patient-identifier-adapter.ts +46 -0
  474. package/src/adapters/person-attribute-adapter.ts +45 -0
  475. package/src/adapters/program-state-adapter.ts +57 -0
  476. package/src/api/index.ts +224 -0
  477. package/src/components/error/error-modal.component.tsx +37 -0
  478. package/src/components/error/error.scss +4 -0
  479. package/src/components/extension/extension-parcel.component.tsx +32 -0
  480. package/src/components/field-label/field-label.component.tsx +55 -0
  481. package/src/components/field-label/field-label.scss +15 -0
  482. package/src/components/group/obs-group.component.tsx +59 -0
  483. package/src/components/group/obs-group.scss +16 -0
  484. package/src/components/inputs/content-switcher/content-switcher.component.tsx +81 -0
  485. package/src/components/inputs/content-switcher/content-switcher.scss +55 -0
  486. package/src/components/inputs/date/date.component.tsx +141 -0
  487. package/src/components/inputs/date/date.scss +37 -0
  488. package/src/components/inputs/file/file-thumbnail.component.tsx +55 -0
  489. package/src/components/inputs/file/file-thumbnail.scss +42 -0
  490. package/src/components/inputs/file/file.component.tsx +98 -0
  491. package/src/components/inputs/file/file.scss +21 -0
  492. package/src/components/inputs/fixed-value/fixed-value.component.tsx +19 -0
  493. package/src/components/inputs/markdown/markdown-wrapper.component.tsx +14 -0
  494. package/src/components/inputs/markdown/markdown.component.tsx +24 -0
  495. package/src/components/inputs/multi-select/multi-select.component.tsx +152 -0
  496. package/src/components/inputs/multi-select/multi-select.scss +25 -0
  497. package/src/components/inputs/number/number.component.tsx +85 -0
  498. package/src/components/inputs/number/number.scss +15 -0
  499. package/src/components/inputs/radio/radio.component.tsx +81 -0
  500. package/src/components/inputs/radio/radio.scss +36 -0
  501. package/src/components/inputs/select/dropdown.component.tsx +86 -0
  502. package/src/components/inputs/select/dropdown.scss +11 -0
  503. package/src/components/inputs/text/text.component.tsx +67 -0
  504. package/src/components/inputs/text/text.scss +15 -0
  505. package/src/components/inputs/text-area/text-area.component.tsx +63 -0
  506. package/src/components/inputs/text-area/text-area.scss +11 -0
  507. package/src/components/inputs/toggle/toggle.component.tsx +66 -0
  508. package/src/components/inputs/toggle/toggle.scss +12 -0
  509. package/src/components/inputs/ui-select-extended/ui-select-extended.component.tsx +208 -0
  510. package/src/components/inputs/ui-select-extended/ui-select-extended.scss +19 -0
  511. package/src/components/inputs/unspecified/unspecified.component.tsx +84 -0
  512. package/src/components/inputs/unspecified/unspecified.scss +7 -0
  513. package/src/components/inputs/workspace-launcher/workspace-launcher.component.tsx +80 -0
  514. package/src/components/inputs/workspace-launcher/workspace-launcher.scss +21 -0
  515. package/src/components/label/label.component.tsx +20 -0
  516. package/src/components/label/label.scss +15 -0
  517. package/src/components/loaders/loader.component.tsx +16 -0
  518. package/src/components/loaders/loader.scss +20 -0
  519. package/src/components/patient-banner/patient-banner.component.tsx +20 -0
  520. package/src/components/patient-banner/patient-banner.scss +12 -0
  521. package/src/components/previous-value-review/previous-value-review.component.tsx +49 -0
  522. package/src/components/previous-value-review/previous-value-review.scss +36 -0
  523. package/src/components/processor-factory/form-processor-factory.component.tsx +128 -0
  524. package/src/components/renderer/custom-hooks-renderer.component.tsx +30 -0
  525. package/src/components/renderer/field/fieldLogic.ts +314 -0
  526. package/src/components/renderer/field/fieldRenderUtils.ts +16 -0
  527. package/src/components/renderer/field/form-field-renderer.component.tsx +291 -0
  528. package/src/components/renderer/field/form-field-renderer.scss +5 -0
  529. package/src/components/renderer/form/form-renderer.component.tsx +123 -0
  530. package/src/components/renderer/form/state.ts +59 -0
  531. package/src/components/renderer/page/page.renderer.component.tsx +120 -0
  532. package/src/components/renderer/page/page.renderer.scss +74 -0
  533. package/src/components/renderer/section/section-renderer.component.tsx +25 -0
  534. package/src/components/renderer/section/section-renderer.scss +19 -0
  535. package/src/components/repeat/helpers.ts +77 -0
  536. package/src/components/repeat/repeat-controls.component.tsx +38 -0
  537. package/src/components/repeat/repeat-controls.scss +7 -0
  538. package/src/components/repeat/repeat.component.tsx +206 -0
  539. package/src/components/repeat/repeat.scss +30 -0
  540. package/src/components/sidebar/page-observer.ts +58 -0
  541. package/src/components/sidebar/sidebar.component.tsx +121 -0
  542. package/src/components/sidebar/sidebar.scss +114 -0
  543. package/src/components/sidebar/useCurrentActivePage.ts +137 -0
  544. package/src/components/sidebar/usePageObserver.ts +45 -0
  545. package/src/components/value/value.component.tsx +30 -0
  546. package/src/components/value/value.scss +17 -0
  547. package/src/components/value/view/field-value-view.component.tsx +36 -0
  548. package/src/components/value/view/field-value-view.scss +31 -0
  549. package/src/constants.ts +14 -0
  550. package/src/datasources/concept-data-source.ts +42 -0
  551. package/src/datasources/data-source.ts +34 -0
  552. package/src/datasources/encounter-role-datasource.ts +15 -0
  553. package/src/datasources/historical-data-source.ts +11 -0
  554. package/src/datasources/location-data-source.ts +27 -0
  555. package/src/datasources/provider-datasource.ts +15 -0
  556. package/src/datasources/select-concept-answers-datasource.ts +25 -0
  557. package/src/declarations.d.ts +2 -0
  558. package/src/external-function-context.tsx +8 -0
  559. package/src/form-engine.component.tsx +222 -0
  560. package/src/form-engine.scss +148 -0
  561. package/src/globals.ts +2 -0
  562. package/src/hooks/useConcepts.ts +58 -0
  563. package/src/hooks/useDataSourceDependentValue.ts +16 -0
  564. package/src/hooks/useEncounter.ts +40 -0
  565. package/src/hooks/useEncounterRole.ts +15 -0
  566. package/src/hooks/useEvaluateFormFieldExpressions.ts +152 -0
  567. package/src/hooks/useExternalFormAction.ts +94 -0
  568. package/src/hooks/useFormCollapse.ts +36 -0
  569. package/src/hooks/useFormFieldValidators.ts +22 -0
  570. package/src/hooks/useFormFieldValueAdapters.ts +23 -0
  571. package/src/hooks/useFormFields.ts +65 -0
  572. package/src/hooks/useFormFieldsMeta.ts +48 -0
  573. package/src/hooks/useFormJson.ts +257 -0
  574. package/src/hooks/useFormStateHelpers.ts +72 -0
  575. package/src/hooks/useFormWorkspaceSize.ts +52 -0
  576. package/src/hooks/useInitialValues.ts +39 -0
  577. package/src/hooks/usePatientData.ts +32 -0
  578. package/src/hooks/usePatientPrograms.ts +38 -0
  579. package/src/hooks/usePostSubmissionActions.ts +31 -0
  580. package/src/hooks/useProcessorDependencies.ts +42 -0
  581. package/src/index.ts +11 -0
  582. package/src/lifecycle.ts +32 -0
  583. package/src/post-submission-actions/mark-patient-deceased-action.ts +68 -0
  584. package/src/post-submission-actions/program-enrollment-action.ts +137 -0
  585. package/src/processors/encounter/encounter-form-processor.ts +445 -0
  586. package/src/processors/encounter/encounter-processor-helper.ts +387 -0
  587. package/src/processors/form-processor.ts +40 -0
  588. package/src/provider/form-factory-helper.ts +106 -0
  589. package/src/provider/form-factory-provider.tsx +211 -0
  590. package/src/provider/form-provider.tsx +39 -0
  591. package/src/registry/inbuilt-components/InbuiltPostSubmissionActions.ts +13 -0
  592. package/src/registry/inbuilt-components/control-templates.ts +57 -0
  593. package/src/registry/inbuilt-components/inbuiltControls.ts +99 -0
  594. package/src/registry/inbuilt-components/inbuiltDataSources.ts +41 -0
  595. package/src/registry/inbuilt-components/inbuiltFieldValueAdapters.ts +74 -0
  596. package/src/registry/inbuilt-components/inbuiltTransformers.ts +10 -0
  597. package/src/registry/inbuilt-components/inbuiltValidators.ts +33 -0
  598. package/src/registry/inbuilt-components/template-component-map.ts +28 -0
  599. package/src/registry/registry.ts +290 -0
  600. package/src/transformers/default-schema-transformer.ts +340 -0
  601. package/src/types/domain.ts +237 -0
  602. package/src/types/index.ts +153 -0
  603. package/src/types/schema.ts +259 -0
  604. package/src/typings.d.ts +9 -0
  605. package/src/utils/boolean-utils.ts +25 -0
  606. package/src/utils/common-expression-helpers.ts +636 -0
  607. package/src/utils/common-utils.ts +108 -0
  608. package/src/utils/error-utils.ts +37 -0
  609. package/src/utils/expression-runner.ts +172 -0
  610. package/src/utils/form-helper.ts +283 -0
  611. package/src/utils/form-page-utils.ts +13 -0
  612. package/src/utils/forms-loader.ts +306 -0
  613. package/src/utils/post-submission-action-helper.ts +71 -0
  614. package/src/utils/zscore-service.ts +59 -0
  615. package/src/validators/conditional-answered-validator.ts +17 -0
  616. package/src/validators/date-validator.ts +19 -0
  617. package/src/validators/default-value-validator.ts +36 -0
  618. package/src/validators/form-validator.ts +95 -0
  619. package/src/validators/js-expression-validator.ts +44 -0
  620. package/src/validators/schema.ts +34 -0
  621. package/src/zscore/bfa_boys_5_above.json +2522 -0
  622. package/src/zscore/bfa_girls_5_above.json +2522 -0
  623. package/src/zscore/hfa_boys_5_above.json +2186 -0
  624. package/src/zscore/hfa_boys_below5.json +22286 -0
  625. package/src/zscore/hfa_girls_5_above.json +2186 -0
  626. package/src/zscore/hfa_girls_below5.json +22286 -0
  627. package/src/zscore/wfl_boys_below5.json +7814 -0
  628. package/src/zscore/wfl_girls_below5.json +7814 -0
@@ -0,0 +1,94 @@
1
+ import { useEffect } from 'react';
2
+ import { reportError } from '../utils/error-utils';
3
+ import { useTranslation } from 'react-i18next';
4
+
5
+ interface SubmitEventDetail {
6
+ formUuid: string;
7
+ patientUuid: string;
8
+ action: string;
9
+ }
10
+
11
+ interface UseExternalFormActionProps {
12
+ patientUuid: string;
13
+ formUuid: string;
14
+ setIsSubmitting: (boolean) => void;
15
+ setIsValidating: (boolean) => void;
16
+ }
17
+
18
+ /**
19
+ * useExternalFormAction
20
+ *
21
+ * A custom React hook that listens for a global `CustomEvent` (`ampath-form-action`) and triggers
22
+ * specific actions (such as form submission or validation) by updating external state via provided handlers.
23
+ *
24
+ * This is especially useful in scenarios where the Form Engine is embedded inside another application
25
+ * or UI shell and form behavior (e.g. validation or submission) needs to be triggered programmatically,
26
+ * such as from a toolbar button, modal footer, or an iframe parent.
27
+ *
28
+ * The hook ensures that the received event matches the current `formUuid` and `patientUuid` before executing any action.
29
+ *
30
+ * ### Supported Actions
31
+ * - `"onSubmit"` — Triggers form submission
32
+ * - `"validateForm"` — Triggers form validation
33
+ *
34
+ * @param patientUuid - The UUID of the current patient, used to verify that the action is intended for this instance.
35
+ * @param formUuid - The UUID of the current form, used to validate the target of the action.
36
+ * @param setIsSubmitting - A `setState` handler that initiates form submission when set to `true`.
37
+ * @param setIsValidating - A `setState` handler that initiates form validation when set to `true`.
38
+ *
39
+ * @example
40
+ *
41
+ * // Elsewhere in the app, dispatching the event:
42
+ * window.dispatchEvent(
43
+ * new CustomEvent('ampath-form-action', {
44
+ * detail: {
45
+ * formUuid: '289417aa-31d5-3a06-bae8-a22d870bcf1d',
46
+ * patientUuid: '9ee7a509-d639-4d91-979a-cd605b4d0ad1/chart',
47
+ * action: 'onSubmit',
48
+ * },
49
+ * })
50
+ * );
51
+ */
52
+
53
+ export function useExternalFormAction({
54
+ patientUuid,
55
+ formUuid,
56
+ setIsSubmitting,
57
+ setIsValidating,
58
+ }: UseExternalFormActionProps) {
59
+ const { t } = useTranslation();
60
+
61
+ useEffect(() => {
62
+ const handleSubmit = (event: Event) => {
63
+ const customEvent = event as CustomEvent<SubmitEventDetail>;
64
+ const { formUuid: targetFormUuid, patientUuid: targetPatientUuid, action } = customEvent.detail;
65
+
66
+ if (!action || !targetFormUuid || !targetPatientUuid) {
67
+ reportError(
68
+ new Error('The form action event is missing required details (formUuid, patientUuid, or action).'),
69
+ t('formActionFailed', 'Form action failed'),
70
+ );
71
+ return;
72
+ }
73
+
74
+ if (targetFormUuid === formUuid && targetPatientUuid === patientUuid) {
75
+ switch (action) {
76
+ case 'onSubmit':
77
+ setIsSubmitting(true);
78
+ break;
79
+ case 'validateForm':
80
+ setIsValidating(true);
81
+ break;
82
+ default:
83
+ reportError(new Error(`Unsupported form action: "${action}"`), t('formActionFailed', 'Form action failed'));
84
+ break;
85
+ }
86
+ }
87
+ };
88
+
89
+ window.addEventListener('ampath-form-action', handleSubmit);
90
+ return () => {
91
+ window.removeEventListener('ampath-form-action', handleSubmit);
92
+ };
93
+ }, [setIsSubmitting, setIsValidating, formUuid, patientUuid]);
94
+ }
@@ -0,0 +1,36 @@
1
+ import { useCallback, useEffect, useState } from 'react';
2
+ import type { FormExpanded, SessionMode } from '../types';
3
+
4
+ export function useFormCollapse(sessionMode: SessionMode) {
5
+ const [isFormExpanded, setIsFormExpanded] = useState<FormExpanded>(undefined);
6
+
7
+ const hideFormCollapseToggle = useCallback(() => {
8
+ const HideFormCollapseToggle = new CustomEvent('openmrs:form-view-embedded', { detail: { value: false } });
9
+ window.dispatchEvent(HideFormCollapseToggle);
10
+ }, []);
11
+
12
+ const handleFormCollapseToggle = useCallback((event) => {
13
+ setIsFormExpanded(event.detail.value);
14
+ }, []);
15
+
16
+ useEffect(() => {
17
+ const FormCollapseToggleVisibleEvent = new CustomEvent('openmrs:form-view-embedded', {
18
+ detail: { value: sessionMode != 'embedded-view' },
19
+ });
20
+
21
+ window.dispatchEvent(FormCollapseToggleVisibleEvent);
22
+ }, [sessionMode]);
23
+
24
+ useEffect(() => {
25
+ window.addEventListener('openmrs:form-collapse-toggle', handleFormCollapseToggle);
26
+
27
+ return () => {
28
+ window.removeEventListener('openmrs:form-collapse-toggle', handleFormCollapseToggle);
29
+ };
30
+ }, []);
31
+
32
+ return {
33
+ isFormExpanded,
34
+ hideFormCollapseToggle,
35
+ };
36
+ }
@@ -0,0 +1,22 @@
1
+ import { useEffect, useState } from 'react';
2
+ import { getRegisteredValidator } from '../registry/registry';
3
+ import { type FormField, type FormFieldValidator } from '../types';
4
+
5
+ export function useFormFieldValidators(fields: FormField[]) {
6
+ const [validators, setValidators] = useState<Record<string, FormFieldValidator>>();
7
+
8
+ useEffect(() => {
9
+ const supportedTypes = new Set<string>();
10
+ fields.forEach((field) => {
11
+ field.validators?.forEach((validator) => supportedTypes.add(validator.type));
12
+ });
13
+ const supportedTypesArray = Array.from(supportedTypes);
14
+ Promise.all(supportedTypesArray.map((type) => getRegisteredValidator(type))).then((validators) => {
15
+ setValidators(
16
+ Object.assign({}, ...validators.map((validator, index) => ({ [supportedTypesArray[index]]: validator }))),
17
+ );
18
+ });
19
+ }, [fields]);
20
+
21
+ return validators;
22
+ }
@@ -0,0 +1,23 @@
1
+ import { useState, useEffect } from 'react';
2
+ import { type FormField, type FormFieldValueAdapter } from '../types';
3
+ import { getRegisteredFieldValueAdapter } from '../registry/registry';
4
+
5
+ export const useFormFieldValueAdapters = (fields: FormField[]) => {
6
+ const [adapters, setAdapters] = useState<Record<string, FormFieldValueAdapter>>({});
7
+
8
+ useEffect(() => {
9
+ const supportedTypes = new Set<string>();
10
+ fields.forEach((field) => {
11
+ supportedTypes.add(field.type);
12
+ });
13
+ const supportedTypesArray = Array.from(supportedTypes);
14
+ Promise.all(supportedTypesArray.map((type) => getRegisteredFieldValueAdapter(type))).then((adapters) => {
15
+ const adaptersByType = supportedTypesArray.map((type, index) => ({
16
+ [type]: adapters[index],
17
+ }));
18
+ setAdapters(Object.assign({}, ...adaptersByType));
19
+ });
20
+ }, [fields]);
21
+
22
+ return adapters;
23
+ };
@@ -0,0 +1,65 @@
1
+ import { useMemo } from 'react';
2
+ import { type FormField, type FormSchema } from '../types';
3
+
4
+ export function useFormFields(form: FormSchema): { formFields: FormField[]; conceptReferences: Set<string> } {
5
+ const [flattenedFields, conceptReferences] = useMemo(() => {
6
+ const flattenedFieldsTemp: FormField[] = [];
7
+ const conceptReferencesTemp = new Set<string>();
8
+
9
+ const processFlattenedFields = (
10
+ fields: FormField[],
11
+ ): {
12
+ flattenedFields: FormField[];
13
+ conceptReferences: Set<string>;
14
+ } => {
15
+ const flattenedFields: FormField[] = [];
16
+ const conceptReferences = new Set<string>();
17
+
18
+ const processField = (field: FormField, parentGroupId?: string) => {
19
+ // Add group ID to nested fields if applicable
20
+ const processedField = parentGroupId ? { ...field, meta: { ...field.meta, groupId: parentGroupId } } : field;
21
+
22
+ // Add field to flattened list
23
+ flattenedFields.push(processedField);
24
+
25
+ // Collect concept references
26
+ if (processedField.questionOptions?.concept) {
27
+ conceptReferences.add(processedField.questionOptions.concept);
28
+ }
29
+
30
+ // Collect concept references from answers
31
+ processedField.questionOptions?.answers?.forEach((answer) => {
32
+ if (answer.concept) {
33
+ conceptReferences.add(answer.concept);
34
+ }
35
+ });
36
+
37
+ // Recursively process nested questions for obsGroup
38
+ if (processedField.type === 'obsGroup' && processedField.questions) {
39
+ processedField.questions.forEach((nestedField) => {
40
+ processField(nestedField, processedField.id);
41
+ });
42
+ }
43
+ };
44
+
45
+ // Process all input fields
46
+ fields.forEach((field) => processField(field));
47
+
48
+ return { flattenedFields, conceptReferences };
49
+ };
50
+
51
+ form.pages?.forEach((page) =>
52
+ page.sections?.forEach((section) => {
53
+ if (section.questions) {
54
+ const { flattenedFields, conceptReferences } = processFlattenedFields(section.questions);
55
+ flattenedFieldsTemp.push(...flattenedFields);
56
+ conceptReferences.forEach((conceptReference) => conceptReferencesTemp.add(conceptReference));
57
+ }
58
+ }),
59
+ );
60
+
61
+ return [flattenedFieldsTemp, conceptReferencesTemp];
62
+ }, [form]);
63
+
64
+ return { formFields: flattenedFields, conceptReferences };
65
+ }
@@ -0,0 +1,48 @@
1
+ import { type FormField } from '../types';
2
+ import { useMemo } from 'react';
3
+ import { codedTypes } from '../constants';
4
+ import { findConceptByReference } from '../utils/form-helper';
5
+ import { type OpenmrsResource } from '@openmrs/esm-framework';
6
+
7
+ export function useFormFieldsMeta(rawFormFields: FormField[], concepts: OpenmrsResource[]) {
8
+ const formFields = useMemo(() => {
9
+ if (rawFormFields.length && concepts?.length) {
10
+ return rawFormFields.map((field) => {
11
+ const matchingConcept = findConceptByReference(field.questionOptions.concept, concepts);
12
+ field.questionOptions.concept = matchingConcept ? matchingConcept.uuid : field.questionOptions.concept;
13
+ field.label = field.label ? field.label : matchingConcept?.display;
14
+ if (
15
+ codedTypes.includes(field.questionOptions.rendering) &&
16
+ !field.questionOptions.answers?.length &&
17
+ matchingConcept?.conceptClass?.display === 'Question' &&
18
+ matchingConcept?.answers?.length
19
+ ) {
20
+ field.questionOptions.answers = matchingConcept.answers.map((answer) => {
21
+ return {
22
+ concept: answer?.uuid,
23
+ label: answer?.display,
24
+ };
25
+ });
26
+ }
27
+ field.meta = {
28
+ ...(field.meta || {}),
29
+ concept: matchingConcept,
30
+ };
31
+ if (field.questionOptions.answers) {
32
+ field.questionOptions.answers = field.questionOptions.answers.map((answer) => {
33
+ const matchingAnswerConcept = findConceptByReference(answer.concept, concepts);
34
+ return {
35
+ ...answer,
36
+ concept: matchingAnswerConcept ? matchingAnswerConcept.uuid : answer.concept,
37
+ label: answer.label ? answer.label : matchingAnswerConcept?.display,
38
+ };
39
+ });
40
+ }
41
+ return field;
42
+ });
43
+ }
44
+ return rawFormFields ?? [];
45
+ }, [concepts, rawFormFields]);
46
+
47
+ return formFields;
48
+ }
@@ -0,0 +1,257 @@
1
+ import { useEffect, useState } from 'react';
2
+ import { type FormSchemaTransformer, type FormSchema, type FormSection, type ReferencedForm , type PreFilledQuestions } from '../types';
3
+ import { isTrue } from '../utils/boolean-utils';
4
+ import { applyFormIntent } from '../utils/forms-loader';
5
+ import { fetchOpenMRSForm, fetchClobData } from '../api';
6
+ import { getRegisteredFormSchemaTransformers } from '../registry/registry';
7
+ import { formEngineAppName } from '../globals';
8
+
9
+ export function useFormJson(
10
+ formUuid: string,
11
+ rawFormJson: any,
12
+ encounterUuid: string,
13
+ formSessionIntent: string,
14
+ preFilledQuestions?: PreFilledQuestions,
15
+ ) {
16
+ const [formJson, setFormJson] = useState<FormSchema>(null);
17
+ const [error, setError] = useState(validateFormsArgs(formUuid, rawFormJson));
18
+
19
+ useEffect(() => {
20
+ const abortController = new AbortController();
21
+
22
+ const setFormJsonWithTranslations = (formJson: FormSchema) => {
23
+ if (formJson?.translations) {
24
+ const language = window.i18next.language;
25
+ window.i18next.addResourceBundle(language, formEngineAppName, formJson.translations, true, true);
26
+ }
27
+ setFormJson(formJson);
28
+ };
29
+
30
+ loadFormJson(formUuid, rawFormJson, formSessionIntent, preFilledQuestions)
31
+ .then((formJson) => {
32
+ setFormJsonWithTranslations({ ...formJson, encounter: encounterUuid });
33
+ })
34
+ .catch((error) => {
35
+ if (error.name !== 'AbortError') {
36
+ console.error(error);
37
+ setError(new Error('Error loading form JSON: ' + error.message));
38
+ }
39
+ });
40
+
41
+ return () => {
42
+ abortController.abort();
43
+ };
44
+ }, [formSessionIntent, formUuid, rawFormJson, encounterUuid]);
45
+
46
+ return {
47
+ formJson,
48
+ isLoading: !formJson && !error,
49
+ formError: error,
50
+ };
51
+ }
52
+
53
+ /**
54
+ * Fetches a form JSON schema from OpenMRS and recursively fetches its subForms if they available.
55
+ *
56
+ * If `rawFormJson` is provided, it will be used as the raw form JSON object. Otherwise, the form JSON will be fetched from OpenMRS using the `formIdentifier` parameter.
57
+ *
58
+ * @param rawFormJson The raw form JSON object to be used if `formIdentifier` is not provided.
59
+ * @param formIdentifier The UUID or name of the form to be fetched from OpenMRS if `rawFormJson` is not provided.
60
+ * @param formSessionIntent An optional parameter that represents the current intent.
61
+ * @param preFilledQuestions An optional parameter that represents the pre-filled questions.
62
+ * @returns A well-built form object that might include subForms.
63
+ */
64
+ export async function loadFormJson(
65
+ formIdentifier: string,
66
+ rawFormJson?: FormSchema,
67
+ formSessionIntent?: string,
68
+ preFilledQuestions?: PreFilledQuestions,
69
+ ): Promise<FormSchema> {
70
+ const openmrsFormResponse = await fetchOpenMRSForm(formIdentifier);
71
+ const clobDataResponse = await fetchClobData(openmrsFormResponse);
72
+ const transformers = await getRegisteredFormSchemaTransformers();
73
+ const formJson: FormSchema = clobDataResponse
74
+ ? { ...clobDataResponse, uuid: openmrsFormResponse.uuid }
75
+ : parseFormJson(rawFormJson);
76
+
77
+ // Sub forms
78
+ const subFormRefs = extractSubFormRefs(formJson);
79
+ const subForms = await loadSubForms(subFormRefs, formSessionIntent);
80
+ updateFormJsonWithSubForms(formJson, subForms);
81
+
82
+ // Form components
83
+ const formComponentsRefs = getReferencedForms(formJson);
84
+ const resolvedFormComponents = await loadFormComponents(formComponentsRefs);
85
+ const formNameToAliasMap = formComponentsRefs.reduce((acc, form) => {
86
+ acc[form.formName] = form.alias;
87
+ return acc;
88
+ }, {});
89
+
90
+ const formComponents = mapFormComponents(resolvedFormComponents);
91
+ updateFormJsonWithComponents(formJson, formComponents, formNameToAliasMap);
92
+ return refineFormJson(formJson, transformers, formSessionIntent, preFilledQuestions);
93
+ }
94
+
95
+ function extractSubFormRefs(formJson: FormSchema): string[] {
96
+ return formJson.pages
97
+ .filter((page) => page.isSubform && !page.subform.form && page.subform?.name)
98
+ .map((page) => page.subform?.name);
99
+ }
100
+
101
+ async function loadSubForms(subFormRefs: string[], formSessionIntent?: string): Promise<FormSchema[]> {
102
+ return Promise.all(subFormRefs.map((subForm) => loadFormJson(subForm, null, formSessionIntent)));
103
+ }
104
+
105
+ function updateFormJsonWithSubForms(formJson: FormSchema, subForms: FormSchema[]): void {
106
+ subForms.forEach((subForm) => {
107
+ const matchingPage = formJson.pages.find((page) => page.subform?.name === subForm.name);
108
+ if (matchingPage) {
109
+ matchingPage.subform.form = subForm;
110
+ }
111
+ });
112
+ }
113
+
114
+ function validateFormsArgs(formUuid: string, rawFormJson: any): Error {
115
+ if (!formUuid && !rawFormJson) {
116
+ return new Error('InvalidArgumentsErr: Neither formUuid nor formJson was provided');
117
+ }
118
+ if (formUuid && rawFormJson) {
119
+ return new Error('InvalidArgumentsErr: Both formUuid and formJson cannot be provided at the same time.');
120
+ }
121
+ }
122
+
123
+ /**
124
+ * Refines the input form JSON object by parsing it, removing inline sub forms, applying form schema transformers, setting the encounter type, and applying form intents if provided.
125
+ * @param {any} formJson - The input form JSON object or string.
126
+ * @param {string} [formSessionIntent] - The optional form session intent.
127
+ * @param {PreFilledQuestions} [preFilledQuestions] - The optional pre-filled questions.
128
+ * @returns {FormSchema} - The refined form JSON object of type FormSchema.
129
+ */
130
+ function refineFormJson(
131
+ formJson: any,
132
+ schemaTransformers: FormSchemaTransformer[] = [],
133
+ formSessionIntent?: string,
134
+ preFilledQuestions?: PreFilledQuestions,
135
+ ): FormSchema {
136
+ removeInlineSubForms(formJson, formSessionIntent);
137
+ // apply form schema transformers
138
+ schemaTransformers.reduce((draftForm, transformer) => transformer.transform(draftForm, preFilledQuestions), formJson);
139
+ setEncounterType(formJson);
140
+ return applyFormIntent(formSessionIntent, formJson);
141
+ }
142
+
143
+ /**
144
+ * Parses the input form JSON and returns a deep copy of the object.
145
+ * @param {any} formJson - The input form JSON object or string.
146
+ * @returns {FormSchema} - The parsed form JSON object of type FormSchema.
147
+ */
148
+ function parseFormJson(formJson: any): FormSchema {
149
+ return typeof formJson === 'string' ? JSON.parse(formJson) : JSON.parse(JSON.stringify(formJson));
150
+ }
151
+
152
+ /**
153
+ * Removes inline sub forms from the form JSON and replaces them with their pages if the encounter type matches.
154
+ * @param {FormSchema} formJson - The input form JSON object of type FormSchema.
155
+ * @param {string} formSessionIntent - The form session intent.
156
+ */
157
+ function removeInlineSubForms(formJson: FormSchema, formSessionIntent: string): void {
158
+ for (let i = formJson.pages.length - 1; i >= 0; i--) {
159
+ const page = formJson.pages[i];
160
+ if (
161
+ isTrue(page.isSubform) &&
162
+ !isTrue(page.isHidden) &&
163
+ page.subform?.form?.encounterType === formJson.encounterType
164
+ ) {
165
+ const nonSubformPages = page.subform.form.pages.filter((page) => !isTrue(page.isSubform));
166
+ formJson.pages.splice(i, 1, ...refineFormJson(page.subform.form, [], formSessionIntent).pages);
167
+ }
168
+ }
169
+ }
170
+
171
+ /**
172
+ * Sets the encounter type for the form JSON if it's provided through the `encounter` attribute.
173
+ * @param {FormSchema} formJson - The input form JSON object of type FormSchema.
174
+ */
175
+ function setEncounterType(formJson: FormSchema): void {
176
+ if (formJson.encounter && typeof formJson.encounter === 'string' && !formJson.encounterType) {
177
+ formJson.encounterType = formJson.encounter;
178
+ delete formJson.encounter;
179
+ }
180
+ }
181
+
182
+ /**
183
+ * Functions to support reusable Form Components
184
+ */
185
+ function getReferencedForms(formJson: FormSchema): Array<ReferencedForm> {
186
+ const referencedForms: Array<any> = formJson?.referencedForms;
187
+ if (!referencedForms) {
188
+ return [];
189
+ }
190
+ return referencedForms;
191
+ }
192
+
193
+ async function loadFormComponents(formComponentRefs: Array<ReferencedForm>): Promise<FormSchema[]> {
194
+ return Promise.all(formComponentRefs.map((formComponent) => loadFormJson(formComponent.formName, null, null)));
195
+ }
196
+
197
+ function mapFormComponents(formComponents: Array<FormSchema>): Map<string, FormSchema> {
198
+ const formComponentsMap: Map<string, FormSchema> = new Map();
199
+
200
+ formComponents.forEach((formComponent) => {
201
+ formComponentsMap.set(formComponent.name, formComponent);
202
+ });
203
+
204
+ return formComponentsMap;
205
+ }
206
+
207
+ function updateFormJsonWithComponents(
208
+ formJson: FormSchema,
209
+ formComponents: Map<string, FormSchema>,
210
+ formNameToAliasMap: Record<string, string>,
211
+ ): void {
212
+ formComponents.forEach((component, targetFormName) => {
213
+ //loop through pages and search sections for reference key
214
+ formJson.pages.forEach((page) => {
215
+ if (page.sections) {
216
+ page.sections.forEach((section) => {
217
+ if (
218
+ section.reference &&
219
+ (section.reference.form === targetFormName || section.reference.form === formNameToAliasMap[targetFormName])
220
+ ) {
221
+ // resolve referenced component section
222
+ let resolvedFormSection = getReferencedFormSection(section, component);
223
+ // add resulting referenced component section to section
224
+ Object.assign(section, resolvedFormSection);
225
+ }
226
+ });
227
+ }
228
+ });
229
+ });
230
+ }
231
+
232
+ function getReferencedFormSection(formSection: FormSection, formComponent: FormSchema): FormSection {
233
+ let referencedFormSection: FormSection;
234
+
235
+ // search for component page and section reference from component
236
+ let matchingComponentPage = formComponent.pages.filter((page) => page.label === formSection.reference.page);
237
+ if (matchingComponentPage.length > 0) {
238
+ let matchingComponentSection = matchingComponentPage[0].sections.filter(
239
+ (componentSection) => componentSection.label === formSection.reference.section,
240
+ );
241
+ if (matchingComponentSection.length > 0) {
242
+ referencedFormSection = matchingComponentSection[0];
243
+ }
244
+ }
245
+
246
+ return filterExcludedQuestions(referencedFormSection, formSection.reference);
247
+ }
248
+
249
+ function filterExcludedQuestions(formSection: FormSection, reference: any): FormSection {
250
+ if (reference?.excludeQuestions) {
251
+ const excludeQuestions = reference.excludeQuestions;
252
+ formSection.questions = formSection.questions.filter((question) => {
253
+ return !excludeQuestions.includes(question.id);
254
+ });
255
+ }
256
+ return formSection;
257
+ }
@@ -0,0 +1,72 @@
1
+ import { type Dispatch, useCallback } from 'react';
2
+ import { type FormField, type FormSchema } from '../types';
3
+ import { type Action } from '../components/renderer/form/state';
4
+ import { cloneDeep } from 'lodash-es';
5
+ import { updateFormSectionReferences } from '../utils/common-utils';
6
+
7
+ export function useFormStateHelpers(dispatch: Dispatch<Action>, formFields: FormField[]) {
8
+ const addFormField = useCallback((field: FormField) => {
9
+ dispatch({ type: 'ADD_FORM_FIELD', value: field });
10
+ }, []);
11
+ const updateFormField = useCallback(
12
+ (field: FormField) => {
13
+ if (field.meta.groupId) {
14
+ const group = formFields.find((f) => f.id === field.meta.groupId);
15
+ if (group) {
16
+ group.questions = group.questions.map((child) => {
17
+ if (child.id === field.id) {
18
+ return field;
19
+ }
20
+ return child;
21
+ });
22
+ updateFormField(group);
23
+ }
24
+ }
25
+ dispatch({ type: 'UPDATE_FORM_FIELD', value: cloneDeep(field) });
26
+ },
27
+ [formFields],
28
+ );
29
+
30
+ const getFormField = useCallback(
31
+ (fieldId: string) => {
32
+ return formFields.find((field) => field.id === fieldId);
33
+ },
34
+ [formFields.length],
35
+ );
36
+
37
+ const removeFormField = useCallback((fieldId: string) => {
38
+ dispatch({ type: 'REMOVE_FORM_FIELD', value: fieldId });
39
+ }, []);
40
+
41
+ const setInvalidFields = useCallback((fields: FormField[]) => {
42
+ dispatch({ type: 'SET_INVALID_FIELDS', value: fields });
43
+ }, []);
44
+
45
+ const addInvalidField = useCallback((field: FormField) => {
46
+ dispatch({ type: 'ADD_INVALID_FIELD', value: field });
47
+ }, []);
48
+
49
+ const removeInvalidField = useCallback((fieldId: string) => {
50
+ dispatch({ type: 'REMOVE_INVALID_FIELD', value: fieldId });
51
+ }, []);
52
+
53
+ const setForm = useCallback((formJson: FormSchema) => {
54
+ dispatch({ type: 'SET_FORM_JSON', value: updateFormSectionReferences(formJson) });
55
+ }, []);
56
+
57
+ const setDeletedFields = useCallback((fields: FormField[]) => {
58
+ dispatch({ type: 'SET_DELETED_FIELDS', value: fields });
59
+ }, []);
60
+
61
+ return {
62
+ addFormField,
63
+ updateFormField,
64
+ getFormField,
65
+ removeFormField,
66
+ setInvalidFields,
67
+ addInvalidField,
68
+ removeInvalidField,
69
+ setForm,
70
+ setDeletedFields,
71
+ };
72
+ }
@@ -0,0 +1,52 @@
1
+ import { useLayoutEffect, useMemo, useState } from 'react';
2
+ import { pxToRem } from '../utils/common-utils';
3
+
4
+ /**
5
+ * The width of the supported workspace variants in rem
6
+ */
7
+ const narrowWorkspaceWidth = 26.25;
8
+ const widerWorkspaceWidth = 32.25;
9
+ const extraWideWorkspaceWidth = 48.25;
10
+
11
+ type WorkspaceSize = 'narrow' | 'wider' | 'extra-wide' | 'ultra-wide';
12
+
13
+ /**
14
+ * This hook evaluates the size of the current workspace based on the width of the container element
15
+ */
16
+ export function useFormWorkspaceSize(rootRef: React.RefObject<HTMLDivElement>): WorkspaceSize {
17
+ // width in rem
18
+ const [containerWidth, setContainerWidth] = useState(0);
19
+ const size = useMemo(() => {
20
+ if (containerWidth <= narrowWorkspaceWidth) {
21
+ return 'narrow';
22
+ } else if (containerWidth <= widerWorkspaceWidth) {
23
+ return 'wider';
24
+ } else if (containerWidth <= extraWideWorkspaceWidth) {
25
+ return 'extra-wide';
26
+ } else {
27
+ return 'ultra-wide';
28
+ }
29
+ }, [containerWidth]);
30
+
31
+ useLayoutEffect(() => {
32
+ const handleResize = () => {
33
+ const containerWidth = rootRef.current?.parentElement?.offsetWidth;
34
+ const rootFontSize = parseInt(getComputedStyle(document.documentElement).fontSize);
35
+ containerWidth && setContainerWidth(pxToRem(containerWidth, rootFontSize));
36
+ };
37
+ handleResize();
38
+ const resizeObserver = new ResizeObserver((entries) => {
39
+ handleResize();
40
+ });
41
+
42
+ if (rootRef.current?.parentElement) {
43
+ resizeObserver.observe(rootRef.current?.parentElement);
44
+ }
45
+
46
+ return () => {
47
+ resizeObserver.disconnect();
48
+ };
49
+ }, [rootRef]);
50
+
51
+ return size;
52
+ }