@tft/crispr-forms 12.2.22 → 13.0.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 (338) hide show
  1. package/esm2020/index.mjs +2 -0
  2. package/esm2020/lib/abstracts/autocomplete-field.abstract.mjs +30 -0
  3. package/esm2020/lib/abstracts/crispr-control.mixin.mjs +27 -0
  4. package/esm2020/lib/abstracts/crispr-field.abstract.mjs +17 -0
  5. package/esm2020/lib/abstracts/index.mjs +4 -0
  6. package/esm2020/lib/crispr-forms.module.mjs +66 -0
  7. package/esm2020/lib/field-component-map.const.mjs +25 -0
  8. package/esm2020/lib/field-container/field-container.component.mjs +85 -0
  9. package/esm2020/lib/field-container/index.mjs +2 -0
  10. package/esm2020/lib/field.directive.mjs +77 -0
  11. package/esm2020/lib/form/form.component.mjs +54 -0
  12. package/esm2020/lib/form-group-list/form-group-list.component.mjs +51 -0
  13. package/esm2020/lib/form-group-list/form-group-list.module.mjs +54 -0
  14. package/esm2020/lib/form-group-list/index.mjs +3 -0
  15. package/esm2020/lib/form.helpers.mjs +185 -0
  16. package/esm2020/lib/form.operators.mjs +24 -0
  17. package/esm2020/lib/material/autocomplete-chiplist-field/autocomplete-chiplist-field.component.mjs +111 -0
  18. package/esm2020/lib/material/autocomplete-field/autocomplete-field.component.mjs +70 -0
  19. package/esm2020/lib/material/button/button.component.mjs +35 -0
  20. package/esm2020/lib/material/checkbox-field/checkbox-field.component.mjs +31 -0
  21. package/esm2020/lib/material/datepicker-field/datepicker-field.component.mjs +45 -0
  22. package/esm2020/lib/material/divider/divider.component.mjs +22 -0
  23. package/esm2020/lib/material/file-upload/file-dropzone.directive.mjs +39 -0
  24. package/esm2020/lib/material/file-upload/file-upload.component.mjs +145 -0
  25. package/esm2020/lib/material/file-upload/index.mjs +3 -0
  26. package/esm2020/lib/material/heading/heading.component.mjs +54 -0
  27. package/esm2020/lib/material/image-upload-field/image-compression.helpers.mjs +4 -0
  28. package/esm2020/lib/material/image-upload-field/image-upload-field.component.mjs +213 -0
  29. package/esm2020/lib/material/image-upload-field/index.mjs +2 -0
  30. package/esm2020/lib/material/index.mjs +18 -0
  31. package/esm2020/lib/material/info/info.component.mjs +46 -0
  32. package/esm2020/lib/material/input-field/input-field.component.mjs +27 -0
  33. package/esm2020/lib/material/material.module.mjs +200 -0
  34. package/esm2020/lib/material/option/index.mjs +2 -0
  35. package/esm2020/lib/material/option/option.component.mjs +14 -0
  36. package/esm2020/lib/material/radio-field/radio-field.component.mjs +29 -0
  37. package/esm2020/lib/material/select-field/select-field.component.mjs +58 -0
  38. package/esm2020/lib/material/selected-file/selected-file.component.mjs +47 -0
  39. package/esm2020/lib/material/slider-field/slider-field.component.mjs +30 -0
  40. package/esm2020/lib/material/textarea-field/textarea-field.component.mjs +28 -0
  41. package/esm2020/lib/material/unit-conversion-field/unit-conversion-field.component.mjs +69 -0
  42. package/esm2020/lib/models/autocomplete-chiplist-field.config.mjs +2 -0
  43. package/esm2020/lib/models/autocomplete-field.config.mjs +2 -0
  44. package/esm2020/lib/models/button.config.mjs +2 -0
  45. package/esm2020/lib/models/checkbox-field.config.mjs +2 -0
  46. package/esm2020/lib/models/crispr-field.config.mjs +23 -0
  47. package/esm2020/lib/models/datepicker-field.config.mjs +2 -0
  48. package/esm2020/lib/models/divider.config.mjs +2 -0
  49. package/esm2020/lib/models/file-upload-field.config.mjs +2 -0
  50. package/esm2020/lib/models/form-group-list.config.mjs +2 -0
  51. package/esm2020/lib/models/heading.config.mjs +3 -0
  52. package/esm2020/lib/models/image-upload-field.config.mjs +2 -0
  53. package/esm2020/lib/models/index.mjs +18 -0
  54. package/esm2020/lib/models/input-field.config.mjs +2 -0
  55. package/esm2020/lib/models/radio-field.config.mjs +2 -0
  56. package/esm2020/lib/models/select-field.config.mjs +2 -0
  57. package/esm2020/lib/models/slider-field.config.mjs +2 -0
  58. package/esm2020/lib/models/textarea-field.config.mjs +2 -0
  59. package/esm2020/lib/models/unit-conversion-field.config.mjs +2 -0
  60. package/esm2020/lib/pipes/crispr-pipes.module.mjs +26 -0
  61. package/esm2020/lib/pipes/initial-control-value.pipe.mjs +20 -0
  62. package/esm2020/lib/public_api.mjs +10 -0
  63. package/esm2020/lib/sub-group/index.mjs +3 -0
  64. package/esm2020/lib/sub-group/sub-group.component.mjs +20 -0
  65. package/esm2020/lib/sub-group/sub-group.module.mjs +45 -0
  66. package/esm2020/tft-crispr-forms.mjs +5 -0
  67. package/fesm2015/tft-crispr-forms.mjs +1883 -0
  68. package/fesm2015/tft-crispr-forms.mjs.map +1 -0
  69. package/fesm2020/tft-crispr-forms.mjs +1875 -0
  70. package/fesm2020/tft-crispr-forms.mjs.map +1 -0
  71. package/lib/abstracts/autocomplete-field.abstract.d.ts +4 -1
  72. package/lib/abstracts/crispr-control.mixin.d.ts +1 -1
  73. package/lib/abstracts/crispr-field.abstract.d.ts +4 -1
  74. package/lib/crispr-forms.module.d.ts +14 -0
  75. package/lib/field-component-map.const.d.ts +21 -20
  76. package/lib/field-container/field-container.component.d.ts +11 -1
  77. package/lib/field-container/index.d.ts +1 -0
  78. package/lib/field.directive.d.ts +14 -5
  79. package/lib/form/form.component.d.ts +6 -1
  80. package/lib/form-group-list/form-group-list.component.d.ts +4 -1
  81. package/lib/form-group-list/form-group-list.module.d.ts +15 -0
  82. package/lib/form-group-list/index.d.ts +2 -0
  83. package/lib/form.helpers.d.ts +1 -1
  84. package/lib/material/autocomplete-chiplist-field/autocomplete-chiplist-field.component.d.ts +3 -0
  85. package/lib/material/autocomplete-field/autocomplete-field.component.d.ts +3 -0
  86. package/lib/material/button/button.component.d.ts +3 -0
  87. package/lib/material/checkbox-field/checkbox-field.component.d.ts +3 -0
  88. package/lib/material/datepicker-field/datepicker-field.component.d.ts +3 -0
  89. package/lib/material/divider/divider.component.d.ts +3 -0
  90. package/lib/material/file-upload/file-dropzone.directive.d.ts +3 -0
  91. package/lib/material/file-upload/file-upload.component.d.ts +20 -2
  92. package/lib/material/file-upload/index.d.ts +2 -0
  93. package/lib/material/heading/heading.component.d.ts +12 -1
  94. package/lib/material/image-upload-field/image-compression.helpers.d.ts +1 -0
  95. package/lib/material/image-upload-field/image-upload-field.component.d.ts +63 -0
  96. package/lib/material/image-upload-field/index.d.ts +1 -0
  97. package/lib/material/index.d.ts +4 -1
  98. package/lib/material/info/info.component.d.ts +12 -1
  99. package/lib/material/input-field/input-field.component.d.ts +3 -0
  100. package/lib/material/material.module.d.ts +42 -0
  101. package/lib/material/option/index.d.ts +1 -0
  102. package/lib/material/option/option.component.d.ts +3 -0
  103. package/lib/material/radio-field/radio-field.component.d.ts +3 -0
  104. package/lib/material/select-field/select-field.component.d.ts +3 -0
  105. package/lib/material/selected-file/selected-file.component.d.ts +10 -0
  106. package/lib/material/slider-field/slider-field.component.d.ts +3 -0
  107. package/lib/material/textarea-field/textarea-field.component.d.ts +3 -0
  108. package/lib/material/unit-conversion-field/unit-conversion-field.component.d.ts +3 -0
  109. package/lib/models/button.config.d.ts +3 -2
  110. package/lib/models/crispr-field.config.d.ts +5 -6
  111. package/lib/models/file-upload-field.config.d.ts +3 -2
  112. package/lib/models/image-upload-field.config.d.ts +47 -0
  113. package/lib/models/index.d.ts +2 -0
  114. package/lib/models/radio-field.config.d.ts +1 -1
  115. package/lib/pipes/crispr-pipes.module.d.ts +8 -0
  116. package/lib/pipes/initial-control-value.pipe.d.ts +3 -0
  117. package/lib/public_api.d.ts +1 -0
  118. package/lib/sub-group/index.d.ts +2 -0
  119. package/lib/sub-group/sub-group.component.d.ts +3 -0
  120. package/lib/sub-group/sub-group.module.d.ts +12 -0
  121. package/package.json +31 -15
  122. package/tft-crispr-forms-13.0.0.tgz +0 -0
  123. package/tft-crispr-forms.d.ts +1 -25
  124. package/bundles/tft-crispr-forms.umd.js +0 -1722
  125. package/bundles/tft-crispr-forms.umd.js.map +0 -1
  126. package/esm2015/index.js +0 -2
  127. package/esm2015/index.js.map +0 -1
  128. package/esm2015/index.metadata.json +0 -1
  129. package/esm2015/lib/abstracts/autocomplete-field.abstract.js +0 -27
  130. package/esm2015/lib/abstracts/autocomplete-field.abstract.js.map +0 -1
  131. package/esm2015/lib/abstracts/autocomplete-field.abstract.metadata.json +0 -1
  132. package/esm2015/lib/abstracts/crispr-control.mixin.js +0 -27
  133. package/esm2015/lib/abstracts/crispr-control.mixin.js.map +0 -1
  134. package/esm2015/lib/abstracts/crispr-control.mixin.metadata.json +0 -1
  135. package/esm2015/lib/abstracts/crispr-field.abstract.js +0 -14
  136. package/esm2015/lib/abstracts/crispr-field.abstract.js.map +0 -1
  137. package/esm2015/lib/abstracts/crispr-field.abstract.metadata.json +0 -1
  138. package/esm2015/lib/abstracts/index.js +0 -4
  139. package/esm2015/lib/abstracts/index.js.map +0 -1
  140. package/esm2015/lib/abstracts/index.metadata.json +0 -1
  141. package/esm2015/lib/crispr-forms.module.js +0 -41
  142. package/esm2015/lib/crispr-forms.module.js.map +0 -1
  143. package/esm2015/lib/crispr-forms.module.metadata.json +0 -1
  144. package/esm2015/lib/crispr-forms.module.ngfactory.js.map +0 -1
  145. package/esm2015/lib/field-component-map.const.js +0 -28
  146. package/esm2015/lib/field-component-map.const.js.map +0 -1
  147. package/esm2015/lib/field-component-map.const.metadata.json +0 -1
  148. package/esm2015/lib/field-container/field-container.component.js +0 -57
  149. package/esm2015/lib/field-container/field-container.component.js.map +0 -1
  150. package/esm2015/lib/field-container/field-container.component.metadata.json +0 -1
  151. package/esm2015/lib/field-container/field-container.component.ngfactory.js.map +0 -1
  152. package/esm2015/lib/field-container/field-container.component.scss.shim.ngstyle.js.map +0 -1
  153. package/esm2015/lib/field.directive.js +0 -55
  154. package/esm2015/lib/field.directive.js.map +0 -1
  155. package/esm2015/lib/field.directive.metadata.json +0 -1
  156. package/esm2015/lib/field.directive.ngfactory.js.map +0 -1
  157. package/esm2015/lib/form/form.component.js +0 -40
  158. package/esm2015/lib/form/form.component.js.map +0 -1
  159. package/esm2015/lib/form/form.component.metadata.json +0 -1
  160. package/esm2015/lib/form/form.component.ngfactory.js.map +0 -1
  161. package/esm2015/lib/form/form.component.scss.shim.ngstyle.js.map +0 -1
  162. package/esm2015/lib/form-group-list/form-group-list.component.js +0 -44
  163. package/esm2015/lib/form-group-list/form-group-list.component.js.map +0 -1
  164. package/esm2015/lib/form-group-list/form-group-list.component.metadata.json +0 -1
  165. package/esm2015/lib/form-group-list/form-group-list.component.ngfactory.js.map +0 -1
  166. package/esm2015/lib/form-group-list/form-group-list.component.scss.shim.ngstyle.js.map +0 -1
  167. package/esm2015/lib/form.helpers.js +0 -186
  168. package/esm2015/lib/form.helpers.js.map +0 -1
  169. package/esm2015/lib/form.helpers.metadata.json +0 -1
  170. package/esm2015/lib/form.operators.js +0 -24
  171. package/esm2015/lib/form.operators.js.map +0 -1
  172. package/esm2015/lib/form.operators.metadata.json +0 -1
  173. package/esm2015/lib/material/autocomplete-chiplist-field/autocomplete-chiplist-field.component.js +0 -101
  174. package/esm2015/lib/material/autocomplete-chiplist-field/autocomplete-chiplist-field.component.js.map +0 -1
  175. package/esm2015/lib/material/autocomplete-chiplist-field/autocomplete-chiplist-field.component.metadata.json +0 -1
  176. package/esm2015/lib/material/autocomplete-chiplist-field/autocomplete-chiplist-field.component.ngfactory.js.map +0 -1
  177. package/esm2015/lib/material/autocomplete-chiplist-field/autocomplete-chiplist-field.component.scss.shim.ngstyle.js.map +0 -1
  178. package/esm2015/lib/material/autocomplete-field/autocomplete-field.component.js +0 -60
  179. package/esm2015/lib/material/autocomplete-field/autocomplete-field.component.js.map +0 -1
  180. package/esm2015/lib/material/autocomplete-field/autocomplete-field.component.metadata.json +0 -1
  181. package/esm2015/lib/material/autocomplete-field/autocomplete-field.component.ngfactory.js.map +0 -1
  182. package/esm2015/lib/material/autocomplete-field/autocomplete-field.component.scss.shim.ngstyle.js.map +0 -1
  183. package/esm2015/lib/material/button/button.component.js +0 -30
  184. package/esm2015/lib/material/button/button.component.js.map +0 -1
  185. package/esm2015/lib/material/button/button.component.metadata.json +0 -1
  186. package/esm2015/lib/material/button/button.component.ngfactory.js.map +0 -1
  187. package/esm2015/lib/material/button/button.component.scss.shim.ngstyle.js.map +0 -1
  188. package/esm2015/lib/material/checkbox-field/checkbox-field.component.js +0 -25
  189. package/esm2015/lib/material/checkbox-field/checkbox-field.component.js.map +0 -1
  190. package/esm2015/lib/material/checkbox-field/checkbox-field.component.metadata.json +0 -1
  191. package/esm2015/lib/material/checkbox-field/checkbox-field.component.ngfactory.js.map +0 -1
  192. package/esm2015/lib/material/checkbox-field/checkbox-field.component.scss.shim.ngstyle.js.map +0 -1
  193. package/esm2015/lib/material/datepicker-field/datepicker-field.component.js +0 -45
  194. package/esm2015/lib/material/datepicker-field/datepicker-field.component.js.map +0 -1
  195. package/esm2015/lib/material/datepicker-field/datepicker-field.component.metadata.json +0 -1
  196. package/esm2015/lib/material/datepicker-field/datepicker-field.component.ngfactory.js.map +0 -1
  197. package/esm2015/lib/material/datepicker-field/datepicker-field.component.scss.shim.ngstyle.js.map +0 -1
  198. package/esm2015/lib/material/divider/divider.component.js +0 -20
  199. package/esm2015/lib/material/divider/divider.component.js.map +0 -1
  200. package/esm2015/lib/material/divider/divider.component.metadata.json +0 -1
  201. package/esm2015/lib/material/divider/divider.component.ngfactory.js.map +0 -1
  202. package/esm2015/lib/material/divider/divider.component.scss.shim.ngstyle.js.map +0 -1
  203. package/esm2015/lib/material/file-upload/file-dropzone.directive.js +0 -31
  204. package/esm2015/lib/material/file-upload/file-dropzone.directive.js.map +0 -1
  205. package/esm2015/lib/material/file-upload/file-dropzone.directive.metadata.json +0 -1
  206. package/esm2015/lib/material/file-upload/file-dropzone.directive.ngfactory.js.map +0 -1
  207. package/esm2015/lib/material/file-upload/file-upload.component.js +0 -80
  208. package/esm2015/lib/material/file-upload/file-upload.component.js.map +0 -1
  209. package/esm2015/lib/material/file-upload/file-upload.component.metadata.json +0 -1
  210. package/esm2015/lib/material/file-upload/file-upload.component.ngfactory.js.map +0 -1
  211. package/esm2015/lib/material/file-upload/file-upload.component.scss.shim.ngstyle.js.map +0 -1
  212. package/esm2015/lib/material/heading/heading.component.js +0 -23
  213. package/esm2015/lib/material/heading/heading.component.js.map +0 -1
  214. package/esm2015/lib/material/heading/heading.component.metadata.json +0 -1
  215. package/esm2015/lib/material/heading/heading.component.ngfactory.js.map +0 -1
  216. package/esm2015/lib/material/heading/heading.component.scss.shim.ngstyle.js.map +0 -1
  217. package/esm2015/lib/material/index.js +0 -15
  218. package/esm2015/lib/material/index.js.map +0 -1
  219. package/esm2015/lib/material/index.metadata.json +0 -1
  220. package/esm2015/lib/material/info/info.component.js +0 -15
  221. package/esm2015/lib/material/info/info.component.js.map +0 -1
  222. package/esm2015/lib/material/info/info.component.metadata.json +0 -1
  223. package/esm2015/lib/material/info/info.component.ngfactory.js.map +0 -1
  224. package/esm2015/lib/material/info/info.component.scss.shim.ngstyle.js.map +0 -1
  225. package/esm2015/lib/material/input-field/input-field.component.js +0 -22
  226. package/esm2015/lib/material/input-field/input-field.component.js.map +0 -1
  227. package/esm2015/lib/material/input-field/input-field.component.metadata.json +0 -1
  228. package/esm2015/lib/material/input-field/input-field.component.ngfactory.js.map +0 -1
  229. package/esm2015/lib/material/input-field/input-field.component.scss.shim.ngstyle.js.map +0 -1
  230. package/esm2015/lib/material/material.module.js +0 -107
  231. package/esm2015/lib/material/material.module.js.map +0 -1
  232. package/esm2015/lib/material/material.module.metadata.json +0 -1
  233. package/esm2015/lib/material/material.module.ngfactory.js.map +0 -1
  234. package/esm2015/lib/material/option/option.component.js +0 -15
  235. package/esm2015/lib/material/option/option.component.js.map +0 -1
  236. package/esm2015/lib/material/option/option.component.metadata.json +0 -1
  237. package/esm2015/lib/material/option/option.component.ngfactory.js.map +0 -1
  238. package/esm2015/lib/material/option/option.component.scss.shim.ngstyle.js.map +0 -1
  239. package/esm2015/lib/material/radio-field/radio-field.component.js +0 -25
  240. package/esm2015/lib/material/radio-field/radio-field.component.js.map +0 -1
  241. package/esm2015/lib/material/radio-field/radio-field.component.metadata.json +0 -1
  242. package/esm2015/lib/material/radio-field/radio-field.component.ngfactory.js.map +0 -1
  243. package/esm2015/lib/material/radio-field/radio-field.component.scss.shim.ngstyle.js.map +0 -1
  244. package/esm2015/lib/material/select-field/select-field.component.js +0 -50
  245. package/esm2015/lib/material/select-field/select-field.component.js.map +0 -1
  246. package/esm2015/lib/material/select-field/select-field.component.metadata.json +0 -1
  247. package/esm2015/lib/material/select-field/select-field.component.ngfactory.js.map +0 -1
  248. package/esm2015/lib/material/select-field/select-field.component.scss.shim.ngstyle.js.map +0 -1
  249. package/esm2015/lib/material/selected-file/selected-file.component.js +0 -17
  250. package/esm2015/lib/material/selected-file/selected-file.component.js.map +0 -1
  251. package/esm2015/lib/material/selected-file/selected-file.component.metadata.json +0 -1
  252. package/esm2015/lib/material/selected-file/selected-file.component.ngfactory.js.map +0 -1
  253. package/esm2015/lib/material/selected-file/selected-file.component.scss.shim.ngstyle.js.map +0 -1
  254. package/esm2015/lib/material/slider-field/slider-field.component.js +0 -26
  255. package/esm2015/lib/material/slider-field/slider-field.component.js.map +0 -1
  256. package/esm2015/lib/material/slider-field/slider-field.component.metadata.json +0 -1
  257. package/esm2015/lib/material/slider-field/slider-field.component.ngfactory.js.map +0 -1
  258. package/esm2015/lib/material/slider-field/slider-field.component.scss.shim.ngstyle.js.map +0 -1
  259. package/esm2015/lib/material/textarea-field/textarea-field.component.js +0 -22
  260. package/esm2015/lib/material/textarea-field/textarea-field.component.js.map +0 -1
  261. package/esm2015/lib/material/textarea-field/textarea-field.component.metadata.json +0 -1
  262. package/esm2015/lib/material/textarea-field/textarea-field.component.ngfactory.js.map +0 -1
  263. package/esm2015/lib/material/textarea-field/textarea-field.component.scss.shim.ngstyle.js.map +0 -1
  264. package/esm2015/lib/material/unit-conversion-field/unit-conversion-field.component.js +0 -63
  265. package/esm2015/lib/material/unit-conversion-field/unit-conversion-field.component.js.map +0 -1
  266. package/esm2015/lib/material/unit-conversion-field/unit-conversion-field.component.metadata.json +0 -1
  267. package/esm2015/lib/material/unit-conversion-field/unit-conversion-field.component.ngfactory.js.map +0 -1
  268. package/esm2015/lib/material/unit-conversion-field/unit-conversion-field.component.scss.shim.ngstyle.js.map +0 -1
  269. package/esm2015/lib/models/autocomplete-chiplist-field.config.js +0 -2
  270. package/esm2015/lib/models/autocomplete-chiplist-field.config.js.map +0 -1
  271. package/esm2015/lib/models/autocomplete-chiplist-field.config.metadata.json +0 -1
  272. package/esm2015/lib/models/autocomplete-field.config.js +0 -2
  273. package/esm2015/lib/models/autocomplete-field.config.js.map +0 -1
  274. package/esm2015/lib/models/autocomplete-field.config.metadata.json +0 -1
  275. package/esm2015/lib/models/button.config.js +0 -2
  276. package/esm2015/lib/models/button.config.js.map +0 -1
  277. package/esm2015/lib/models/button.config.metadata.json +0 -1
  278. package/esm2015/lib/models/checkbox-field.config.js +0 -2
  279. package/esm2015/lib/models/checkbox-field.config.js.map +0 -1
  280. package/esm2015/lib/models/checkbox-field.config.metadata.json +0 -1
  281. package/esm2015/lib/models/crispr-field.config.js +0 -22
  282. package/esm2015/lib/models/crispr-field.config.js.map +0 -1
  283. package/esm2015/lib/models/crispr-field.config.metadata.json +0 -1
  284. package/esm2015/lib/models/datepicker-field.config.js +0 -2
  285. package/esm2015/lib/models/datepicker-field.config.js.map +0 -1
  286. package/esm2015/lib/models/datepicker-field.config.metadata.json +0 -1
  287. package/esm2015/lib/models/divider.config.js +0 -2
  288. package/esm2015/lib/models/divider.config.js.map +0 -1
  289. package/esm2015/lib/models/divider.config.metadata.json +0 -1
  290. package/esm2015/lib/models/file-upload-field.config.js +0 -2
  291. package/esm2015/lib/models/file-upload-field.config.js.map +0 -1
  292. package/esm2015/lib/models/file-upload-field.config.metadata.json +0 -1
  293. package/esm2015/lib/models/form-group-list.config.js +0 -2
  294. package/esm2015/lib/models/form-group-list.config.js.map +0 -1
  295. package/esm2015/lib/models/form-group-list.config.metadata.json +0 -1
  296. package/esm2015/lib/models/heading.config.js +0 -3
  297. package/esm2015/lib/models/heading.config.js.map +0 -1
  298. package/esm2015/lib/models/heading.config.metadata.json +0 -1
  299. package/esm2015/lib/models/index.js +0 -16
  300. package/esm2015/lib/models/index.js.map +0 -1
  301. package/esm2015/lib/models/index.metadata.json +0 -1
  302. package/esm2015/lib/models/input-field.config.js +0 -2
  303. package/esm2015/lib/models/input-field.config.js.map +0 -1
  304. package/esm2015/lib/models/input-field.config.metadata.json +0 -1
  305. package/esm2015/lib/models/radio-field.config.js +0 -2
  306. package/esm2015/lib/models/radio-field.config.js.map +0 -1
  307. package/esm2015/lib/models/radio-field.config.metadata.json +0 -1
  308. package/esm2015/lib/models/select-field.config.js +0 -2
  309. package/esm2015/lib/models/select-field.config.js.map +0 -1
  310. package/esm2015/lib/models/select-field.config.metadata.json +0 -1
  311. package/esm2015/lib/models/slider-field.config.js +0 -2
  312. package/esm2015/lib/models/slider-field.config.js.map +0 -1
  313. package/esm2015/lib/models/slider-field.config.metadata.json +0 -1
  314. package/esm2015/lib/models/textarea-field.config.js +0 -2
  315. package/esm2015/lib/models/textarea-field.config.js.map +0 -1
  316. package/esm2015/lib/models/textarea-field.config.metadata.json +0 -1
  317. package/esm2015/lib/models/unit-conversion-field.config.js +0 -2
  318. package/esm2015/lib/models/unit-conversion-field.config.js.map +0 -1
  319. package/esm2015/lib/models/unit-conversion-field.config.metadata.json +0 -1
  320. package/esm2015/lib/pipes/initial-control-value.pipe.js +0 -16
  321. package/esm2015/lib/pipes/initial-control-value.pipe.js.map +0 -1
  322. package/esm2015/lib/pipes/initial-control-value.pipe.metadata.json +0 -1
  323. package/esm2015/lib/pipes/initial-control-value.pipe.ngfactory.js.map +0 -1
  324. package/esm2015/lib/public_api.js +0 -9
  325. package/esm2015/lib/public_api.js.map +0 -1
  326. package/esm2015/lib/public_api.metadata.json +0 -1
  327. package/esm2015/lib/sub-group/sub-group.component.js +0 -17
  328. package/esm2015/lib/sub-group/sub-group.component.js.map +0 -1
  329. package/esm2015/lib/sub-group/sub-group.component.metadata.json +0 -1
  330. package/esm2015/lib/sub-group/sub-group.component.ngfactory.js.map +0 -1
  331. package/esm2015/lib/sub-group/sub-group.component.scss.shim.ngstyle.js.map +0 -1
  332. package/esm2015/tft-crispr-forms.js +0 -30
  333. package/esm2015/tft-crispr-forms.js.map +0 -1
  334. package/esm2015/tft-crispr-forms.metadata.json +0 -1
  335. package/fesm2015/tft-crispr-forms.js +0 -1266
  336. package/fesm2015/tft-crispr-forms.js.map +0 -1
  337. package/tft-crispr-forms-12.2.22.tgz +0 -0
  338. package/tft-crispr-forms.metadata.json +0 -1
@@ -0,0 +1,1875 @@
1
+ import { of, combineLatest, from, isObservable, BehaviorSubject, Subject } from 'rxjs';
2
+ import * as i4$1 from '@angular/forms';
3
+ import { FormGroup, FormArray, FormControl, ReactiveFormsModule } from '@angular/forms';
4
+ import { map, startWith, debounceTime, distinctUntilChanged, switchMap, tap, shareReplay } from 'rxjs/operators';
5
+ import * as i0 from '@angular/core';
6
+ import { Directive, Component, ChangeDetectionStrategy, Input, NgModule, ViewChild, EventEmitter, Output, HostListener, Optional, Self, Pipe } from '@angular/core';
7
+ import * as i2 from '@angular/common';
8
+ import { CommonModule } from '@angular/common';
9
+ import * as i2$1 from '@angular/material/form-field';
10
+ import { MatFormFieldModule } from '@angular/material/form-field';
11
+ import * as i4 from '@angular/material/icon';
12
+ import { MatIconModule } from '@angular/material/icon';
13
+ import * as i3 from '@angular/material/tooltip';
14
+ import { MatTooltipModule } from '@angular/material/tooltip';
15
+ import * as i5 from '@tft/form-validation-handler';
16
+ import { FormValidationHandlerModule } from '@tft/form-validation-handler';
17
+ import * as i7 from '@angular/material/input';
18
+ import { MatInputModule } from '@angular/material/input';
19
+ import * as i3$1 from '@angular/material/select';
20
+ import { MatSelectModule } from '@angular/material/select';
21
+ import * as i4$2 from '@angular/material/checkbox';
22
+ import { MatCheckboxModule } from '@angular/material/checkbox';
23
+ import * as i5$1 from '@angular/material/core';
24
+ import * as i4$3 from '@angular/material/autocomplete';
25
+ import { MatAutocompleteTrigger, MatAutocompleteModule } from '@angular/material/autocomplete';
26
+ import { ENTER } from '@angular/cdk/keycodes';
27
+ import * as i3$2 from '@angular/material/chips';
28
+ import { MatChipsModule } from '@angular/material/chips';
29
+ import * as i3$3 from '@angular/material/slider';
30
+ import { MatSliderModule } from '@angular/material/slider';
31
+ import * as i1 from '@angular/material/button';
32
+ import { MatButtonModule } from '@angular/material/button';
33
+ import * as i8 from '@angular/cdk/portal';
34
+ import { ComponentPortal, PortalModule } from '@angular/cdk/portal';
35
+ import * as i3$4 from '@angular/material/datepicker';
36
+ import { MatDatepickerModule } from '@angular/material/datepicker';
37
+ import * as i1$1 from '@angular/material/divider';
38
+ import { MatDividerModule } from '@angular/material/divider';
39
+ import * as i2$2 from '@angular/material/radio';
40
+ import { MatRadioModule } from '@angular/material/radio';
41
+ import * as i2$3 from '@angular/platform-browser';
42
+ import imageCompression from 'browser-image-compression';
43
+ import * as i1$2 from '@angular/material/progress-bar';
44
+ import { MatProgressBarModule } from '@angular/material/progress-bar';
45
+ import { MatButtonToggleModule } from '@angular/material/button-toggle';
46
+ import { MatSlideToggleModule } from '@angular/material/slide-toggle';
47
+ import { MatMomentDateModule } from '@angular/material-moment-adapter';
48
+
49
+ const DEFAULT_EMPTY_OPTIONS_MESSAGE = 'No Items';
50
+
51
+ // export type ControlType = keyof typeof FIELD_COMPONENTS;
52
+ var ControlType;
53
+ (function (ControlType) {
54
+ ControlType["AUTOCOMPLETE"] = "autocomplete";
55
+ ControlType["AUTOCOMPLETE_CHIPLIST"] = "autocompleteChiplist";
56
+ ControlType["BUTTON"] = "button";
57
+ ControlType["CHECKBOX"] = "checkbox";
58
+ ControlType["CUSTOM"] = "custom";
59
+ ControlType["DATEPICKER"] = "datepicker";
60
+ ControlType["DIVIDER"] = "divider";
61
+ ControlType["FILE_UPLOAD"] = "fileUpload";
62
+ ControlType["HEADING"] = "heading";
63
+ ControlType["INPUT"] = "input";
64
+ ControlType["IMAGE_UPLOAD"] = "imageUpload";
65
+ ControlType["GROUP_LIST"] = "groupList";
66
+ ControlType["RADIO"] = "radio";
67
+ ControlType["SELECT"] = "select";
68
+ ControlType["SLIDER"] = "slider";
69
+ ControlType["SUB_GROUP"] = "subGroup";
70
+ ControlType["TEXTAREA"] = "textarea";
71
+ ControlType["UNIT_CONVERSION"] = "unitConversion";
72
+ })(ControlType || (ControlType = {}));
73
+
74
+ ;
75
+
76
+ function valueIn(values) {
77
+ return map((value) => {
78
+ if (value) {
79
+ return values.some(v => {
80
+ if (isRegex(v)) {
81
+ const trimmedStringForRegex = v.substr(1, v.length - 2);
82
+ const regex = new RegExp(trimmedStringForRegex);
83
+ return regex.test(value);
84
+ }
85
+ else {
86
+ return v === value;
87
+ }
88
+ });
89
+ }
90
+ else {
91
+ return false;
92
+ }
93
+ });
94
+ }
95
+ function isRegex(string) {
96
+ return string.startsWith('/') && string.endsWith('/');
97
+ }
98
+
99
+ /**
100
+ * Watches a single control for a list of values, returns true when field value matches any value in list
101
+ * unless an evaluate method is found on config, in which case that method is run on the returned boolean value
102
+ * @param group the direct parent of the field we want to watch
103
+ * @param config
104
+ */
105
+ function checkControlForValues(group, config) {
106
+ // check that all the pieces we need are available
107
+ if (config && config.controlName && Array.isArray(config.values)) {
108
+ return getValueChanges(group, config.controlName).pipe(
109
+ // return a boolean, true if value is in the values being watch for, otherwise false
110
+ valueIn(config.values), map((isValueInValues) => {
111
+ // since we can only check if the value is in the list of watched values, the evaluate function gives us
112
+ // a chance to make other decisions based on if the boolean returned, e.g. return true if value not in watched values
113
+ if (config.evaluate && config.evaluate instanceof Function) {
114
+ return config.evaluate(isValueInValues);
115
+ }
116
+ else {
117
+ return isValueInValues;
118
+ }
119
+ }));
120
+ }
121
+ else {
122
+ //
123
+ return of(true);
124
+ }
125
+ }
126
+ /**
127
+ * Watches a list of fields for individual lists of values returning true when any field contains one
128
+ * of the values being watched for, or optionally running a function on the array of resolved booleans
129
+ * from the listed fields and returning a boolean
130
+ * @param group the form group that has the fields to watch as direct descendants
131
+ * @param config the configuration to use when calling the function
132
+ */
133
+ function checkControlsForValues(group, config) {
134
+ // if no config is passed we just want to show the field, so we return an observable of true
135
+ if (!config || !config.watchConfigs) {
136
+ return of(true);
137
+ }
138
+ // we run checkControlForValues on every control in the list of WatchConfigs creating
139
+ // an array of Observable watching fields for values
140
+ const fieldTriggers = config.watchConfigs.map(watchConfig => {
141
+ // resolves a boolean, true when field value matches a watched value, otherwise false
142
+ return checkControlForValues(group, watchConfig);
143
+ });
144
+ return combineLatest(fieldTriggers).pipe(startWith([true]), map((booleans) => {
145
+ // if the user passed an evaluate function use it
146
+ if (config.evaluate && config.evaluate instanceof Function) {
147
+ return config.evaluate(booleans);
148
+ }
149
+ else { // otherwise we return true if any of the watched fields resolve to true
150
+ return booleans.some(bool => bool);
151
+ }
152
+ }));
153
+ }
154
+ /**
155
+ * Watches values on an array of fields, computing their values as they change
156
+ * @param group the group to get the fields from, for now it can only be the parent of the computed field
157
+ * @param computeFieldsConfig the configuration that drives the computation, holds the names to watch and the
158
+ * computation function that get called against the array of values
159
+ */
160
+ function computeValueFromFields(group, computeFieldsConfig) {
161
+ // TODO: better checking
162
+ const { controlNamesToWatch } = computeFieldsConfig;
163
+ //creates an observable listener for each control in the controlNamesToWatch array
164
+ return combineLatest(controlNamesToWatch.map(controlNameToWatch => getValueChanges(group, controlNameToWatch))).pipe(
165
+ // each time a watched field values changes a new array of the latest field values is pipe through to the
166
+ // compute callback. Which runs the users logic on the values to compute this fields value
167
+ map(valuesArray => computeFieldsConfig.computeCallback(valuesArray)));
168
+ }
169
+ /**
170
+ * A simple wrapper for doing error checking around getting the valueChanges observable from a control on a form group
171
+ * @param group the form group we want to pull the observable from
172
+ * @param controlName the name of the control who's value we want to subscribe to
173
+ */
174
+ function getValueChanges(group, controlName) {
175
+ const control = group.get(controlName);
176
+ if (!control) {
177
+ throw new Error(`No control with controlName ${controlName}`);
178
+ }
179
+ return control.valueChanges;
180
+ }
181
+ /**
182
+ * TODO: move to utils library after library is built
183
+ * Allows developer to pass an array of operators into the pipe of an Observable.
184
+ * Useful for creating function with a variable amount of operators to be run
185
+ * @param observable the observable to pass the operators to
186
+ * @param operators array of operators to pipe
187
+ */
188
+ function pipeOperatorsIntoObservable(observable, operators) {
189
+ try {
190
+ return operators.reduce((obs, op) => {
191
+ return obs.pipe(op);
192
+ }, observable);
193
+ }
194
+ catch {
195
+ console.error('Unable to pipe operators into observable');
196
+ return of(null);
197
+ }
198
+ }
199
+ function callOptionsIfFunction(options, parentGroup, searchString) {
200
+ return options instanceof Function ? options(parentGroup, searchString) : options;
201
+ }
202
+ /**
203
+ * The user can give us select options as an array, a function that resolves to a promise,
204
+ * or an observable. This functions consumes any of those and returns an observable that
205
+ * resolves an array of options
206
+ *
207
+ * @param options the options passed in from the config
208
+ * @param emptyMessageOption the message to display when the array is empty
209
+ */
210
+ function observablifyOptions(options, parentGroup, searchString) {
211
+ const calledOptions = callOptionsIfFunction(options, parentGroup, searchString);
212
+ // if options are a promise
213
+ return calledOptions instanceof Promise
214
+ // convert to observable
215
+ ? from(calledOptions)
216
+ // if array that isn't empty
217
+ : Array.isArray(calledOptions) && calledOptions.length
218
+ // convert to observable
219
+ ? of(calledOptions)
220
+ // if observable
221
+ : isObservable(calledOptions)
222
+ // return it
223
+ ? calledOptions
224
+ // else an empty array
225
+ : of([]);
226
+ }
227
+ /**
228
+ * Determines if the field config is for a form control (not a divider, heading or other non-control field)
229
+ * */
230
+ function isControlConfig(fieldConfig) {
231
+ return 'controlName' in fieldConfig;
232
+ }
233
+ /**
234
+ * builds out form group based on config
235
+ * @param config a configuration for a form group
236
+ * @param value an object of initial values to pass in
237
+ * @param group the form group to modify and build out
238
+ */
239
+ function buildFormGroupFromConfig(config, value = null, group = new FormGroup({})) {
240
+ config.fields.forEach((controlConfig) => {
241
+ if (isControlConfig(controlConfig)) {
242
+ // then add a control to the group using the controlName from configuration
243
+ const { controlName } = controlConfig;
244
+ // if there's a value object and it has a non-null/undefined value for this field use it.
245
+ // Otherwise, default to null
246
+ const controlValue = (value && value[controlName]) ?? null;
247
+ group.addControl(controlName, createControlForType(controlConfig, controlValue));
248
+ }
249
+ });
250
+ group.setValidators(config.validators);
251
+ return group;
252
+ }
253
+ /**
254
+ * Analyze the config and build a form control to spec. Notice we don't use FormBuilder here
255
+ * as we want to keep this function pure.
256
+ * @param controlConfig the configuration object for the control to build
257
+ * @param value an initial value to use if passed in
258
+ */
259
+ function createControlForType(controlConfig, value = null) {
260
+ // build form control out based on the control type
261
+ const control = controlConfig.controlType === ControlType.SUB_GROUP
262
+ ? buildFormGroupFromConfig(controlConfig, value)
263
+ : controlConfig.controlType === ControlType.GROUP_LIST
264
+ ? new FormArray([], controlConfig.validators)
265
+ : new FormControl(value || null, controlConfig.validators);
266
+ return control;
267
+ }
268
+ /**
269
+ * A basic filter function that filters the search string against the label of the options object
270
+ * @param options the array of options to filter
271
+ * @param searchString the string from the input
272
+ */
273
+ function filterOptionsByLabel(options, searchString) {
274
+ return options.filter(option => {
275
+ return option.label && option.label.toLowerCase().includes(searchString.toLowerCase());
276
+ });
277
+ }
278
+
279
+ function crisprControlMixin(BaseClass) {
280
+ return class extends BaseClass {
281
+ set value(value) {
282
+ this.setControlValue(value);
283
+ this._value = value;
284
+ }
285
+ get value() {
286
+ return this._value;
287
+ }
288
+ ngOnInit() {
289
+ super.ngOnInit();
290
+ this.control = this.group.get(this.config.controlName);
291
+ this.setControlValue(this.value);
292
+ // setTimeouts are ugly but this seems to be the only way to get the computed field to compute initial values
293
+ setTimeout(() => {
294
+ this.control.updateValueAndValidity();
295
+ });
296
+ }
297
+ setControlValue(value) {
298
+ if (value && this.control && this.config.controlType !== ControlType.SUB_GROUP) {
299
+ this.control.setValue(value);
300
+ }
301
+ }
302
+ };
303
+ }
304
+
305
+ // eslint-disable-next-line @angular-eslint/directive-class-suffix
306
+ class CrisprFieldComponent {
307
+ ngOnInit() {
308
+ this.applyDefaultConfig();
309
+ }
310
+ applyDefaultConfig() {
311
+ this.config = this.defaultConfig ? { ...this.defaultConfig, ...this.config } : this.config;
312
+ }
313
+ }
314
+ CrisprFieldComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: CrisprFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Directive });
315
+ CrisprFieldComponent.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "13.2.1", type: CrisprFieldComponent, ngImport: i0 });
316
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: CrisprFieldComponent, decorators: [{
317
+ type: Directive
318
+ }] });
319
+
320
+ const AbstractAutocompleteFieldMixin = crisprControlMixin(CrisprFieldComponent);
321
+ // eslint-disable-next-line @angular-eslint/directive-class-suffix
322
+ class AbstractAutocompleteComponent extends AbstractAutocompleteFieldMixin {
323
+ constructor() {
324
+ super(...arguments);
325
+ // we need a separate control for the UI because of the way the material autocomplete chiplist works
326
+ this.autocompleteInputControl = new FormControl('');
327
+ }
328
+ ngOnInit() {
329
+ super.ngOnInit();
330
+ this.group.addControl(this.config.controlName, new FormControl());
331
+ // filter options by the search string using either the default filter function or one passed in through config
332
+ this.options$ = this.autocompleteInputControl.valueChanges.pipe(
333
+ // this is needed to have the options panel to open on focus
334
+ startWith(''), debounceTime(this.config.typeDebounceTime), distinctUntilChanged(), map(searchText => searchText || ''), switchMap((searchText) => observablifyOptions(this.config.options, this.group, searchText)));
335
+ }
336
+ }
337
+ AbstractAutocompleteComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: AbstractAutocompleteComponent, deps: null, target: i0.ɵɵFactoryTarget.Directive });
338
+ AbstractAutocompleteComponent.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "13.2.1", type: AbstractAutocompleteComponent, usesInheritance: true, ngImport: i0 });
339
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: AbstractAutocompleteComponent, decorators: [{
340
+ type: Directive
341
+ }] });
342
+
343
+ class InfoComponent {
344
+ }
345
+ InfoComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: InfoComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
346
+ InfoComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.2.1", type: InfoComponent, selector: "crispr-info", inputs: { info: "info" }, ngImport: i0, template: "<mat-icon\n *ngIf=\"info\"\n [matTooltip]=\"info.content\"\n [matTooltipPosition]=\"info.tooltipPosition || 'below'\"\n matSuffix>\n info\n</mat-icon>\n", styles: ["mat-icon{font-size:1.2em;width:1em;height:1em;opacity:.8}\n"], components: [{ type: i4.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }], directives: [{ type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.MatTooltip, selector: "[matTooltip]", exportAs: ["matTooltip"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, preserveWhitespaces: true });
347
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: InfoComponent, decorators: [{
348
+ type: Component,
349
+ args: [{ selector: 'crispr-info', changeDetection: ChangeDetectionStrategy.OnPush, template: "<mat-icon\n *ngIf=\"info\"\n [matTooltip]=\"info.content\"\n [matTooltipPosition]=\"info.tooltipPosition || 'below'\"\n matSuffix>\n info\n</mat-icon>\n", styles: ["mat-icon{font-size:1.2em;width:1em;height:1em;opacity:.8}\n"] }]
350
+ }], propDecorators: { info: [{
351
+ type: Input
352
+ }] } });
353
+ class InfoModule {
354
+ }
355
+ InfoModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: InfoModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
356
+ InfoModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: InfoModule, declarations: [InfoComponent], imports: [CommonModule,
357
+ MatIconModule,
358
+ MatTooltipModule], exports: [InfoComponent] });
359
+ InfoModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: InfoModule, imports: [[
360
+ CommonModule,
361
+ MatIconModule,
362
+ MatTooltipModule
363
+ ]] });
364
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: InfoModule, decorators: [{
365
+ type: NgModule,
366
+ args: [{
367
+ imports: [
368
+ CommonModule,
369
+ MatIconModule,
370
+ MatTooltipModule
371
+ ],
372
+ exports: [
373
+ InfoComponent
374
+ ],
375
+ declarations: [
376
+ InfoComponent
377
+ ]
378
+ }]
379
+ }] });
380
+
381
+ const defaultConfig$8 = {
382
+ typographyClass: 'mat-h3'
383
+ };
384
+ class HeadingComponent extends CrisprFieldComponent {
385
+ constructor() {
386
+ super(...arguments);
387
+ this.defaultConfig = defaultConfig$8;
388
+ }
389
+ }
390
+ HeadingComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: HeadingComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
391
+ HeadingComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.2.1", type: HeadingComponent, selector: "crispr-heading", inputs: { config: "config" }, usesInheritance: true, ngImport: i0, template: " <label\n *ngIf=\"!!config?.label\"\n [ngClass]=\"config.typographyClass\">\n {{ config.label }}\n <crispr-info\n *ngIf=\"config.info\"\n matSuffix\n [info]=\"config.info\">\n </crispr-info>\n </label>\n", styles: [":host{display:block}\n"], components: [{ type: InfoComponent, selector: "crispr-info", inputs: ["info"] }], directives: [{ type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { type: i2$1.MatSuffix, selector: "[matSuffix]" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, preserveWhitespaces: true });
392
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: HeadingComponent, decorators: [{
393
+ type: Component,
394
+ args: [{ selector: 'crispr-heading', changeDetection: ChangeDetectionStrategy.OnPush, template: " <label\n *ngIf=\"!!config?.label\"\n [ngClass]=\"config.typographyClass\">\n {{ config.label }}\n <crispr-info\n *ngIf=\"config.info\"\n matSuffix\n [info]=\"config.info\">\n </crispr-info>\n </label>\n", styles: [":host{display:block}\n"] }]
395
+ }], propDecorators: { config: [{
396
+ type: Input
397
+ }] } });
398
+ class HeadingModule {
399
+ }
400
+ HeadingModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: HeadingModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
401
+ HeadingModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: HeadingModule, declarations: [HeadingComponent], imports: [CommonModule,
402
+ MatFormFieldModule,
403
+ InfoModule], exports: [HeadingComponent] });
404
+ HeadingModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: HeadingModule, imports: [[
405
+ CommonModule,
406
+ MatFormFieldModule,
407
+ InfoModule
408
+ ]] });
409
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: HeadingModule, decorators: [{
410
+ type: NgModule,
411
+ args: [{
412
+ imports: [
413
+ CommonModule,
414
+ MatFormFieldModule,
415
+ InfoModule
416
+ ],
417
+ exports: [
418
+ HeadingComponent
419
+ ],
420
+ declarations: [
421
+ HeadingComponent
422
+ ]
423
+ }]
424
+ }] });
425
+
426
+ class FieldContainerComponent {
427
+ constructor() {
428
+ // boolean whether field-container is inline
429
+ this.inlineField = false;
430
+ this.subs = [];
431
+ }
432
+ ngOnInit() {
433
+ this.disabled$ = this.connectDisabledCallback(this.group, this.config);
434
+ // we tried moving this into afterViewChecked and afterContentChecked lifecycle hooks without any luck
435
+ if (this.config.computeValue) {
436
+ this.subs.push(this.config.computeValue(this.group).pipe(distinctUntilChanged(), tap(computedValue => this.group.get(this.config.controlName).setValue(computedValue))).subscribe());
437
+ }
438
+ else if (this.config.computeFieldConfig) {
439
+ console.warn(`computeFieldConfig property is deprecated, please use computeValue. Example here: https://stackblitz.com/github/nayfin/tft-documentation?file=src%2Fapp%2Fcrispr-forms-demo%2Ffeatures%2Fcomputed-field%2Fcomputed-field.component.ts`);
440
+ this.subs.push(computeValueFromFields(this.group, this.config.computeFieldConfig).pipe(distinctUntilChanged(), tap(computedValue => this.group.get(this.config.controlName).setValue(computedValue))).subscribe());
441
+ }
442
+ }
443
+ ngOnDestroy() {
444
+ this.subs.forEach(sub => sub.unsubscribe);
445
+ }
446
+ /**
447
+ * Connects user defined disabledCallback function to the the view, so that the control is enabled/disabled
448
+ * appropriately. It also keeps the form will hide disabled fields in the UI unless `hideDisabled` is set to
449
+ * false in the controls config
450
+ * @param group used to get valueChanges from control
451
+ * @param config configuration object used to
452
+ */
453
+ connectDisabledCallback(group, config = null) {
454
+ const control = group.get(config.controlName);
455
+ // If the disabled$ function exists on the field config then call it with the disabledCallbackConfig
456
+ // as a parameter otherwise return an observable of true.
457
+ return config?.disabledCallback && config.disabledCallback instanceof Function
458
+ ? config.disabledCallback(group, config.disabledCallbackConfig || null).pipe(
459
+ // This enables/disables when callback conditions are met
460
+ tap((shouldDisable) => shouldDisable ? control.disable() : control.enable()))
461
+ : of(false);
462
+ }
463
+ }
464
+ FieldContainerComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: FieldContainerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
465
+ FieldContainerComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.2.1", type: FieldContainerComponent, selector: "crispr-field-container", inputs: { config: "config", group: "group", inlineField: "inlineField" }, ngImport: i0, template: "<div\n *ngIf=\"(disabled$ | async) ? !config.hideDisabled : true\"\n [ngClass]=\"config.classes\"\n [class.inline-field]=\"inlineField\"\n class=\"field-container\">\n\n <crispr-heading\n *ngIf=\"config.heading\"\n [config]=\"config.heading\">\n </crispr-heading>\n\n <ng-content>\n </ng-content>\n\n</div>\n", styles: ["::ng-deep mat-form-field.mat-form-field{display:block}.inline-field{display:inline-block}\n"], components: [{ type: HeadingComponent, selector: "crispr-heading", inputs: ["config"] }], directives: [{ type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }], pipes: { "async": i2.AsyncPipe }, changeDetection: i0.ChangeDetectionStrategy.OnPush, preserveWhitespaces: true });
466
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: FieldContainerComponent, decorators: [{
467
+ type: Component,
468
+ args: [{ selector: 'crispr-field-container', changeDetection: ChangeDetectionStrategy.OnPush, template: "<div\n *ngIf=\"(disabled$ | async) ? !config.hideDisabled : true\"\n [ngClass]=\"config.classes\"\n [class.inline-field]=\"inlineField\"\n class=\"field-container\">\n\n <crispr-heading\n *ngIf=\"config.heading\"\n [config]=\"config.heading\">\n </crispr-heading>\n\n <ng-content>\n </ng-content>\n\n</div>\n", styles: ["::ng-deep mat-form-field.mat-form-field{display:block}.inline-field{display:inline-block}\n"] }]
469
+ }], propDecorators: { config: [{
470
+ type: Input
471
+ }], group: [{
472
+ type: Input
473
+ }], inlineField: [{
474
+ type: Input
475
+ }] } });
476
+ class FieldContainerModule {
477
+ }
478
+ FieldContainerModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: FieldContainerModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
479
+ FieldContainerModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: FieldContainerModule, declarations: [FieldContainerComponent], imports: [CommonModule,
480
+ HeadingModule], exports: [FieldContainerComponent] });
481
+ FieldContainerModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: FieldContainerModule, imports: [[
482
+ CommonModule,
483
+ HeadingModule,
484
+ ]] });
485
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: FieldContainerModule, decorators: [{
486
+ type: NgModule,
487
+ args: [{
488
+ imports: [
489
+ CommonModule,
490
+ HeadingModule,
491
+ ],
492
+ exports: [
493
+ FieldContainerComponent
494
+ ],
495
+ declarations: [
496
+ FieldContainerComponent
497
+ ]
498
+ }]
499
+ }] });
500
+
501
+ const InputFieldMixin = crisprControlMixin(CrisprFieldComponent);
502
+ class InputFieldComponent extends InputFieldMixin {
503
+ constructor() {
504
+ super();
505
+ this.defaultConfig = { inputType: 'text' };
506
+ }
507
+ ngOnInit() {
508
+ super.ngOnInit();
509
+ }
510
+ }
511
+ InputFieldComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: InputFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
512
+ InputFieldComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.2.1", type: InputFieldComponent, selector: "crispr-input-field", usesInheritance: true, ngImport: i0, template: "<crispr-field-container\n [config]=\"config\"\n [group]=\"group\">\n <mat-form-field\n [color]=\"config.color\"\n [appearance]=\"config.appearance\"\n [formGroup]=\"group\">\n <mat-label>\n {{config.label}}\n </mat-label>\n <input\n [type]=\"config.inputType\"\n matInput\n [placeholder]=\"config.placeholder\"\n [formControlName]=\"config.controlName\"\n [min]=\"config.min\"\n [max]=\"config.max\"\n [maxlength]=\"config.maxLength\"\n [step]=\"config.step\"\n [autofocus]=\"config.autofocus\"\n [pattern]=\"config.pattern\"\n [spellcheck]=\"config.spellcheck\"\n [autocomplete]=\"config.autoComplete\"\n [autocapitalize]=\"config.autoCapitalize\">\n <span *ngIf=\"config.fieldSuffix\" matSuffix>{{config.fieldSuffix}}</span>\n <crispr-info\n matSuffix\n *ngIf=\"config.info\"\n [info]=\"config.info\">\n </crispr-info>\n\n </mat-form-field>\n\n\n</crispr-field-container>\n", styles: [""], components: [{ type: FieldContainerComponent, selector: "crispr-field-container", inputs: ["config", "group", "inlineField"] }, { type: i2$1.MatFormField, selector: "mat-form-field", inputs: ["color", "appearance", "hideRequiredMarker", "hintLabel", "floatLabel"], exportAs: ["matFormField"] }, { type: InfoComponent, selector: "crispr-info", inputs: ["info"] }], directives: [{ type: i4$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i4$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i5.ControlErrorContainerDirective, selector: "[controlErrorContainer], [formGroup]" }, { type: i2$1.MatLabel, selector: "mat-label" }, { type: i7.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly"], exportAs: ["matInput"] }, { type: i4$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i4$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i4$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { type: i5.ControlErrorsDirective, selector: "[formControl], [formControlName]" }, { type: i4$1.MaxLengthValidator, selector: "[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]", inputs: ["maxlength"] }, { type: i4$1.PatternValidator, selector: "[pattern][formControlName],[pattern][formControl],[pattern][ngModel]", inputs: ["pattern"] }, { type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i2$1.MatSuffix, selector: "[matSuffix]" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, preserveWhitespaces: true });
513
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: InputFieldComponent, decorators: [{
514
+ type: Component,
515
+ args: [{ selector: 'crispr-input-field', changeDetection: ChangeDetectionStrategy.OnPush, template: "<crispr-field-container\n [config]=\"config\"\n [group]=\"group\">\n <mat-form-field\n [color]=\"config.color\"\n [appearance]=\"config.appearance\"\n [formGroup]=\"group\">\n <mat-label>\n {{config.label}}\n </mat-label>\n <input\n [type]=\"config.inputType\"\n matInput\n [placeholder]=\"config.placeholder\"\n [formControlName]=\"config.controlName\"\n [min]=\"config.min\"\n [max]=\"config.max\"\n [maxlength]=\"config.maxLength\"\n [step]=\"config.step\"\n [autofocus]=\"config.autofocus\"\n [pattern]=\"config.pattern\"\n [spellcheck]=\"config.spellcheck\"\n [autocomplete]=\"config.autoComplete\"\n [autocapitalize]=\"config.autoCapitalize\">\n <span *ngIf=\"config.fieldSuffix\" matSuffix>{{config.fieldSuffix}}</span>\n <crispr-info\n matSuffix\n *ngIf=\"config.info\"\n [info]=\"config.info\">\n </crispr-info>\n\n </mat-form-field>\n\n\n</crispr-field-container>\n", styles: [""] }]
516
+ }], ctorParameters: function () { return []; } });
517
+
518
+ class OptionComponent {
519
+ }
520
+ OptionComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: OptionComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
521
+ OptionComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.2.1", type: OptionComponent, selector: "crispr-option", inputs: { option: "option" }, ngImport: i0, template: "<img\n *ngIf=\"option.imageUrl\"\n [src]=\"option.imageUrl\"\n alt=\"image of {{option.label}}\"\n style=\"vertical-align:middle;\"\n aria-hidden\n height=\"25\"/>\n{{ option.label }}\n", styles: [""], directives: [{ type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, preserveWhitespaces: true });
522
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: OptionComponent, decorators: [{
523
+ type: Component,
524
+ args: [{ selector: 'crispr-option', changeDetection: ChangeDetectionStrategy.OnPush, template: "<img\n *ngIf=\"option.imageUrl\"\n [src]=\"option.imageUrl\"\n alt=\"image of {{option.label}}\"\n style=\"vertical-align:middle;\"\n aria-hidden\n height=\"25\"/>\n{{ option.label }}\n", styles: [""] }]
525
+ }], propDecorators: { option: [{
526
+ type: Input
527
+ }] } });
528
+
529
+ const SelectFieldMixin = crisprControlMixin(CrisprFieldComponent);
530
+ class SelectFieldComponent extends SelectFieldMixin {
531
+ constructor() {
532
+ super(...arguments);
533
+ this.defaultConfig = {
534
+ enableToggleAll: false,
535
+ color: 'primary'
536
+ };
537
+ this.allSelected = false;
538
+ }
539
+ ngOnInit() {
540
+ super.ngOnInit();
541
+ // options$ can be passed as an array, promise that resolves array, or observable that resolves array
542
+ // this functions accounts for all possibilities and converts to observable that resolves array
543
+ this.options$ = observablifyOptions(this.config.options, this.group);
544
+ }
545
+ ngAfterViewInit() {
546
+ if (this.config.multiple
547
+ && this.config.enableToggleAll
548
+ && this.selectField.options?.length === this.value?.length) {
549
+ this.allSelected = true;
550
+ }
551
+ }
552
+ toggleAll(isSelected) {
553
+ if (isSelected) {
554
+ this.selectField.options.forEach(option => option.deselect());
555
+ }
556
+ else {
557
+ this.selectField.options.forEach(option => option.select());
558
+ }
559
+ this.allSelected = !this.allSelected;
560
+ }
561
+ }
562
+ SelectFieldComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: SelectFieldComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
563
+ SelectFieldComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.2.1", type: SelectFieldComponent, selector: "crispr-select-field", viewQueries: [{ propertyName: "selectField", first: true, predicate: ["selectField"], descendants: true }], usesInheritance: true, ngImport: i0, template: "<crispr-field-container\n [config]=\"config\"\n [group]=\"group\">\n\n <mat-form-field\n [color]=\"config.color\"\n [appearance]=\"config.appearance\"\n [formGroup]=\"group\">\n <mat-label *ngIf=\"config.label\">\n {{config.label}}\n </mat-label>\n <mat-select\n #selectField\n [formControlName]=\"config.controlName\"\n [placeholder]=\"config.placeholder\"\n [multiple]=\"config.multiple\">\n\n <mat-checkbox\n [color]=\"config.color\"\n [checked]=\"allSelected\"\n *ngIf=\"config?.multiple && config.enableToggleAll\"\n (click)=\"toggleAll(allSelected)\">\n Select All\n </mat-checkbox>\n <mat-option\n *ngFor=\"let option of options$ | async\"\n [value]=\"option.value\">\n <crispr-option [option]=\"option\">\n </crispr-option>\n </mat-option>\n\n </mat-select>\n\n <span *ngIf=\"config.fieldSuffix\" matSuffix>{{config.fieldSuffix}}</span>\n <crispr-info\n *ngIf=\"config.info\"\n matSuffix\n [info]=\"config.info\">\n </crispr-info>\n </mat-form-field>\n\n</crispr-field-container>\n", styles: ["mat-checkbox{display:block;padding:16px}\n"], components: [{ type: FieldContainerComponent, selector: "crispr-field-container", inputs: ["config", "group", "inlineField"] }, { type: i2$1.MatFormField, selector: "mat-form-field", inputs: ["color", "appearance", "hideRequiredMarker", "hintLabel", "floatLabel"], exportAs: ["matFormField"] }, { type: i3$1.MatSelect, selector: "mat-select", inputs: ["disabled", "disableRipple", "tabIndex"], exportAs: ["matSelect"] }, { type: i4$2.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex", "aria-label", "aria-labelledby", "aria-describedby", "id", "required", "labelPosition", "name", "value", "checked", "disabled", "indeterminate"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { type: i5$1.MatOption, selector: "mat-option", exportAs: ["matOption"] }, { type: OptionComponent, selector: "crispr-option", inputs: ["option"] }, { type: InfoComponent, selector: "crispr-info", inputs: ["info"] }], directives: [{ type: i4$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i4$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i5.ControlErrorContainerDirective, selector: "[controlErrorContainer], [formGroup]" }, { type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i2$1.MatLabel, selector: "mat-label" }, { type: i4$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i4$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { type: i5.ControlErrorsDirective, selector: "[formControl], [formControlName]" }, { type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i2$1.MatSuffix, selector: "[matSuffix]" }], pipes: { "async": i2.AsyncPipe }, changeDetection: i0.ChangeDetectionStrategy.OnPush, preserveWhitespaces: true });
564
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: SelectFieldComponent, decorators: [{
565
+ type: Component,
566
+ args: [{ selector: 'crispr-select-field', changeDetection: ChangeDetectionStrategy.OnPush, template: "<crispr-field-container\n [config]=\"config\"\n [group]=\"group\">\n\n <mat-form-field\n [color]=\"config.color\"\n [appearance]=\"config.appearance\"\n [formGroup]=\"group\">\n <mat-label *ngIf=\"config.label\">\n {{config.label}}\n </mat-label>\n <mat-select\n #selectField\n [formControlName]=\"config.controlName\"\n [placeholder]=\"config.placeholder\"\n [multiple]=\"config.multiple\">\n\n <mat-checkbox\n [color]=\"config.color\"\n [checked]=\"allSelected\"\n *ngIf=\"config?.multiple && config.enableToggleAll\"\n (click)=\"toggleAll(allSelected)\">\n Select All\n </mat-checkbox>\n <mat-option\n *ngFor=\"let option of options$ | async\"\n [value]=\"option.value\">\n <crispr-option [option]=\"option\">\n </crispr-option>\n </mat-option>\n\n </mat-select>\n\n <span *ngIf=\"config.fieldSuffix\" matSuffix>{{config.fieldSuffix}}</span>\n <crispr-info\n *ngIf=\"config.info\"\n matSuffix\n [info]=\"config.info\">\n </crispr-info>\n </mat-form-field>\n\n</crispr-field-container>\n", styles: ["mat-checkbox{display:block;padding:16px}\n"] }]
567
+ }], propDecorators: { selectField: [{
568
+ type: ViewChild,
569
+ args: ['selectField']
570
+ }] } });
571
+
572
+ const defaultConfig$7 = {
573
+ autoActiveFirstOption: true,
574
+ typeDebounceTime: 500,
575
+ emptyOptionsMessage: DEFAULT_EMPTY_OPTIONS_MESSAGE
576
+ };
577
+ class AutocompleteFieldComponent extends AbstractAutocompleteComponent {
578
+ constructor() {
579
+ super(...arguments);
580
+ this.defaultConfig = defaultConfig$7;
581
+ }
582
+ ngOnInit() {
583
+ super.ngOnInit();
584
+ }
585
+ setControlValue(value) {
586
+ if (this.control && value) {
587
+ // sets the initial value on the control if one is passed
588
+ this.control.setValue(value.value || '');
589
+ this.autocompleteInputControl.setValue(value.label || '');
590
+ }
591
+ }
592
+ /**
593
+ * The material autocomplete defaults to displaying the options value instead of its label.
594
+ * We only have the value from the selected option to work with, so we have to pass the options
595
+ * through a function called in the template and return the function that the material displayWith
596
+ * input is expecting.
597
+ * @param options the array of options to search for option with corresponding value
598
+ */
599
+ displayLabel(options) {
600
+ if (this.config.displayWith) {
601
+ return this.config.displayWith(options);
602
+ }
603
+ return (value) => {
604
+ const label = !!options && Array.isArray(options)
605
+ ? options.find((option) => JSON.stringify(option.value) === JSON.stringify(value))?.label : value;
606
+ return label;
607
+ };
608
+ }
609
+ handleSelect(event) {
610
+ this.control.setValue(event.option.value);
611
+ this.autoInputRef.nativeElement.blur();
612
+ }
613
+ }
614
+ AutocompleteFieldComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: AutocompleteFieldComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
615
+ AutocompleteFieldComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.2.1", type: AutocompleteFieldComponent, selector: "crispr-autocomplete-field", viewQueries: [{ propertyName: "autoInput", first: true, predicate: ["autoInput"], descendants: true, read: MatAutocompleteTrigger }, { propertyName: "autoInputRef", first: true, predicate: ["autoInput"], descendants: true }], usesInheritance: true, ngImport: i0, template: "\n<crispr-field-container\n [config]=\"config\"\n [group]=\"group\">\n\n <mat-form-field\n [color]=\"config.color\"\n [appearance]=\"config.appearance\">\n <mat-label *ngIf=\"config.label\">\n {{config.label}}\n </mat-label>\n <input\n matInput\n [formControl]=\"autocompleteInputControl\"\n [placeholder]=\"config.placeholder\"\n [matAutocomplete]=\"auto\"\n role=\"textbox\"\n type=\"textbox\"\n autocapitalize=\"off\"\n autocorrect=\"off\"\n spellcheck=\"false\"\n #autoInput>\n\n <span *ngIf=\"config.fieldSuffix\" matSuffix>{{config.fieldSuffix}}</span>\n <crispr-info\n *ngIf=\"config.info\"\n matSuffix\n [info]=\"config.info \">\n </crispr-info>\n\n <mat-autocomplete\n #auto=\"matAutocomplete\"\n [autoActiveFirstOption]=\"config.autoActiveFirstOption\"\n (optionSelected)=\"handleSelect($event)\"\n [displayWith]=\"displayLabel(options$ | async)\">\n\n <ng-container *ngIf=\"options$ | async as options; else emptyOption\">\n <ng-container *ngIf=\"options.length > 0; else emptyOption\">\n <mat-option\n *ngFor=\"let option of options$ | async\"\n [value]=\"option.value\">\n <crispr-option [option]=\"option\"></crispr-option>\n </mat-option>\n </ng-container>\n\n </ng-container>\n <ng-template #emptyOption>\n <mat-option disabled=\"true\">\n {{config.emptyOptionsMessage}}\n </mat-option>\n </ng-template>\n\n </mat-autocomplete>\n </mat-form-field>\n</crispr-field-container>\n", styles: [""], components: [{ type: FieldContainerComponent, selector: "crispr-field-container", inputs: ["config", "group", "inlineField"] }, { type: i2$1.MatFormField, selector: "mat-form-field", inputs: ["color", "appearance", "hideRequiredMarker", "hintLabel", "floatLabel"], exportAs: ["matFormField"] }, { type: InfoComponent, selector: "crispr-info", inputs: ["info"] }, { type: i4$3.MatAutocomplete, selector: "mat-autocomplete", inputs: ["disableRipple"], exportAs: ["matAutocomplete"] }, { type: i5$1.MatOption, selector: "mat-option", exportAs: ["matOption"] }, { type: OptionComponent, selector: "crispr-option", inputs: ["option"] }], directives: [{ type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i2$1.MatLabel, selector: "mat-label" }, { type: i7.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly"], exportAs: ["matInput"] }, { type: i4$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i4$3.MatAutocompleteTrigger, selector: "input[matAutocomplete], textarea[matAutocomplete]", exportAs: ["matAutocompleteTrigger"] }, { type: i4$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i4$1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { type: i5.ControlErrorsDirective, selector: "[formControl], [formControlName]" }, { type: i2$1.MatSuffix, selector: "[matSuffix]" }, { type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }], pipes: { "async": i2.AsyncPipe }, changeDetection: i0.ChangeDetectionStrategy.OnPush, preserveWhitespaces: true });
616
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: AutocompleteFieldComponent, decorators: [{
617
+ type: Component,
618
+ args: [{ selector: 'crispr-autocomplete-field', changeDetection: ChangeDetectionStrategy.OnPush, template: "\n<crispr-field-container\n [config]=\"config\"\n [group]=\"group\">\n\n <mat-form-field\n [color]=\"config.color\"\n [appearance]=\"config.appearance\">\n <mat-label *ngIf=\"config.label\">\n {{config.label}}\n </mat-label>\n <input\n matInput\n [formControl]=\"autocompleteInputControl\"\n [placeholder]=\"config.placeholder\"\n [matAutocomplete]=\"auto\"\n role=\"textbox\"\n type=\"textbox\"\n autocapitalize=\"off\"\n autocorrect=\"off\"\n spellcheck=\"false\"\n #autoInput>\n\n <span *ngIf=\"config.fieldSuffix\" matSuffix>{{config.fieldSuffix}}</span>\n <crispr-info\n *ngIf=\"config.info\"\n matSuffix\n [info]=\"config.info \">\n </crispr-info>\n\n <mat-autocomplete\n #auto=\"matAutocomplete\"\n [autoActiveFirstOption]=\"config.autoActiveFirstOption\"\n (optionSelected)=\"handleSelect($event)\"\n [displayWith]=\"displayLabel(options$ | async)\">\n\n <ng-container *ngIf=\"options$ | async as options; else emptyOption\">\n <ng-container *ngIf=\"options.length > 0; else emptyOption\">\n <mat-option\n *ngFor=\"let option of options$ | async\"\n [value]=\"option.value\">\n <crispr-option [option]=\"option\"></crispr-option>\n </mat-option>\n </ng-container>\n\n </ng-container>\n <ng-template #emptyOption>\n <mat-option disabled=\"true\">\n {{config.emptyOptionsMessage}}\n </mat-option>\n </ng-template>\n\n </mat-autocomplete>\n </mat-form-field>\n</crispr-field-container>\n", styles: [""] }]
619
+ }], propDecorators: { autoInput: [{
620
+ type: ViewChild,
621
+ args: ['autoInput', { read: MatAutocompleteTrigger }]
622
+ }], autoInputRef: [{
623
+ type: ViewChild,
624
+ args: ['autoInput']
625
+ }] } });
626
+
627
+ const defaultConfig$6 = {
628
+ chipsSelectable: true,
629
+ areChipsRemovable: true,
630
+ tabToSelect: true,
631
+ autoActiveFirstOption: true,
632
+ imageUrlParam: 'image',
633
+ typeDebounceTime: 500,
634
+ allowDuplicates: false,
635
+ duplicateCompareFunction: (chip, option) => chip.value === option.value,
636
+ separatorKeyCodes: [ENTER],
637
+ emptyOptionsMessage: DEFAULT_EMPTY_OPTIONS_MESSAGE,
638
+ };
639
+ class AutocompleteChiplistFieldComponent extends AbstractAutocompleteComponent {
640
+ constructor() {
641
+ super(...arguments);
642
+ this.defaultConfig = defaultConfig$6;
643
+ this.chips$ = new BehaviorSubject([]);
644
+ this.controlValue$ = this.chips$.pipe(tap(chips => {
645
+ this.control.setValue(chips.map(chip => chip.value));
646
+ }));
647
+ }
648
+ ngOnInit() {
649
+ super.ngOnInit();
650
+ this.remainingOptions$ = combineLatest([
651
+ this.chips$,
652
+ this.options$
653
+ ]).pipe(map(([chips, options]) => {
654
+ return this.config.allowDuplicates
655
+ ? options
656
+ : options?.filter(option => {
657
+ return !chips.some(chip => this.config.duplicateCompareFunction(chip, option));
658
+ });
659
+ }));
660
+ }
661
+ setControlValue(value) {
662
+ if (value) {
663
+ this.chips$.next(value);
664
+ }
665
+ }
666
+ // handles mat selecting
667
+ handleSelect(event) {
668
+ const selectedOption = event.option.value;
669
+ this.chips$.next([...this.chips$.value, selectedOption]);
670
+ this.chipInputRef.nativeElement.value = '';
671
+ this.autocompleteInputControl.setValue('');
672
+ // setTimeout needed because the panel thinks it's still open at this point
673
+ setTimeout(() => this.chipInput.openPanel());
674
+ }
675
+ /**
676
+ * To follow ARIA standards we want to select the active option on blur.
677
+ * matChipInputAddOnBlur should do this but it causes buggy behaviour
678
+ * @param event blur event that triggers the handle blur
679
+ */
680
+ handleTab(_event) {
681
+ if (this.chipInput.activeOption && (this.config.tabToSelect || this.config.addChipOnBlur)) {
682
+ const chip = this.chipInput.activeOption.value;
683
+ this.chips$.next([...this.chips$.value, chip]);
684
+ }
685
+ }
686
+ /**
687
+ * Handles selection via key tokens passed through separatorKeyCodes propert
688
+ * NOTE: If TAB is used focus does not move on to next component
689
+ * @param event
690
+ */
691
+ handleTokenEnd(event) {
692
+ if (this.chipInput.activeOption) {
693
+ this.chipInput.activeOption.select();
694
+ }
695
+ event.chipInput?.clear();
696
+ }
697
+ mapToLabel(option) {
698
+ return option ? option.label : '';
699
+ }
700
+ removeChip(removedChip) {
701
+ const remainingChips = this.chips$.value.filter(chip => chip !== removedChip);
702
+ this.chips$.next(remainingChips);
703
+ }
704
+ }
705
+ AutocompleteChiplistFieldComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: AutocompleteChiplistFieldComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
706
+ AutocompleteChiplistFieldComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.2.1", type: AutocompleteChiplistFieldComponent, selector: "crispr-autocomplete-chiplist-field", viewQueries: [{ propertyName: "chipInput", first: true, predicate: ["autoInput"], descendants: true, read: MatAutocompleteTrigger }, { propertyName: "chipInputRef", first: true, predicate: ["autoInput"], descendants: true }], usesInheritance: true, ngImport: i0, template: "<crispr-field-container\n [config]=\"config\"\n [group]=\"group\">\n\n <mat-form-field\n [color]=\"config.color\"\n [appearance]=\"config.appearance\">\n <mat-label *ngIf=\"config.label\">\n {{config.label}}\n </mat-label>\n\n <mat-chip-list\n #chipList>\n <mat-chip\n class=\"refinement-chip\"\n *ngFor=\"let chip of controlValue$ | async\"\n [selectable]=\"config.chipsSelectable\"\n [removable]=\"config.areChipsRemovable\"\n (removed)=\"removeChip(chip)\">\n <span *ngIf=\"chip.imageUrl as imageUrl\" class=\"image-container\">\n <img [src]=\"imageUrl\" alt=\"image of {{chip.label}}\">\n </span>\n {{chip.label}}\n <mat-icon\n matChipRemove\n *ngIf=\"config.areChipsRemovable\">\n cancel\n </mat-icon>\n </mat-chip>\n\n <input\n matInput\n [formControl]=\"autocompleteInputControl\"\n [placeholder]=\"config.placeholder\"\n [matChipInputFor]=\"chipList\"\n [matAutocomplete]=\"auto\"\n (keydown.tab)=\"handleTab($event)\"\n [matChipInputSeparatorKeyCodes]=\"config.separatorKeyCodes\"\n (matChipInputTokenEnd)=\"handleTokenEnd($event)\"\n role=\"searchbox\"\n type=\"text\"\n autocapitalize=\"off\"\n autocorrect=\"off\"\n spellcheck=\"false\"\n #autoInput/>\n <span *ngIf=\"config.fieldSuffix\" matSuffix>{{config.fieldSuffix}}</span>\n <crispr-info\n *ngIf=\"config.info\"\n matSuffix\n [info]=\"config.info \">\n </crispr-info>\n\n </mat-chip-list>\n <mat-autocomplete\n #auto=\"matAutocomplete\"\n [autoActiveFirstOption]=\"this.config.autoActiveFirstOption\"\n (optionSelected)=\"handleSelect($event)\"\n [displayWith]=\"mapToLabel\">\n <ng-container *ngIf=\"remainingOptions$ | async as remainingOptions; else emptyOption\">\n <ng-container *ngIf=\"remainingOptions.length > 0; else emptyOption\">\n <mat-option\n *ngFor=\"let option of remainingOptions$ | async\"\n [value]=\"option\">\n <crispr-option [option]=\"option\"></crispr-option>\n </mat-option>\n </ng-container>\n\n </ng-container>\n <ng-template #emptyOption>\n <mat-option disabled=\"true\">\n {{config.emptyOptionsMessage}}\n </mat-option>\n </ng-template>\n </mat-autocomplete>\n\n\n </mat-form-field>\n</crispr-field-container>\n", styles: [".refinement-chip .image-container{width:26px;height:26px;border-radius:50%;overflow:hidden;margin:-2px 4px -2px -8px}.refinement-chip .image-container img{width:100%;height:100%;object-fit:cover}\n"], components: [{ type: FieldContainerComponent, selector: "crispr-field-container", inputs: ["config", "group", "inlineField"] }, { type: i2$1.MatFormField, selector: "mat-form-field", inputs: ["color", "appearance", "hideRequiredMarker", "hintLabel", "floatLabel"], exportAs: ["matFormField"] }, { type: i3$2.MatChipList, selector: "mat-chip-list", inputs: ["errorStateMatcher", "multiple", "compareWith", "value", "required", "placeholder", "disabled", "aria-orientation", "selectable", "tabIndex"], outputs: ["change", "valueChange"], exportAs: ["matChipList"] }, { type: i4.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { type: InfoComponent, selector: "crispr-info", inputs: ["info"] }, { type: i4$3.MatAutocomplete, selector: "mat-autocomplete", inputs: ["disableRipple"], exportAs: ["matAutocomplete"] }, { type: i5$1.MatOption, selector: "mat-option", exportAs: ["matOption"] }, { type: OptionComponent, selector: "crispr-option", inputs: ["option"] }], directives: [{ type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i2$1.MatLabel, selector: "mat-label" }, { type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i3$2.MatChip, selector: "mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]", inputs: ["color", "disableRipple", "tabIndex", "selected", "value", "selectable", "disabled", "removable"], outputs: ["selectionChange", "destroyed", "removed"], exportAs: ["matChip"] }, { type: i3$2.MatChipRemove, selector: "[matChipRemove]" }, { type: i7.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly"], exportAs: ["matInput"] }, { type: i4$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i3$2.MatChipInput, selector: "input[matChipInputFor]", inputs: ["matChipInputFor", "matChipInputAddOnBlur", "matChipInputSeparatorKeyCodes", "placeholder", "id", "disabled"], outputs: ["matChipInputTokenEnd"], exportAs: ["matChipInput", "matChipInputFor"] }, { type: i4$3.MatAutocompleteTrigger, selector: "input[matAutocomplete], textarea[matAutocomplete]", exportAs: ["matAutocompleteTrigger"] }, { type: i4$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i4$1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { type: i5.ControlErrorsDirective, selector: "[formControl], [formControlName]" }, { type: i2$1.MatSuffix, selector: "[matSuffix]" }], pipes: { "async": i2.AsyncPipe }, changeDetection: i0.ChangeDetectionStrategy.OnPush, preserveWhitespaces: true });
707
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: AutocompleteChiplistFieldComponent, decorators: [{
708
+ type: Component,
709
+ args: [{ selector: 'crispr-autocomplete-chiplist-field', changeDetection: ChangeDetectionStrategy.OnPush, template: "<crispr-field-container\n [config]=\"config\"\n [group]=\"group\">\n\n <mat-form-field\n [color]=\"config.color\"\n [appearance]=\"config.appearance\">\n <mat-label *ngIf=\"config.label\">\n {{config.label}}\n </mat-label>\n\n <mat-chip-list\n #chipList>\n <mat-chip\n class=\"refinement-chip\"\n *ngFor=\"let chip of controlValue$ | async\"\n [selectable]=\"config.chipsSelectable\"\n [removable]=\"config.areChipsRemovable\"\n (removed)=\"removeChip(chip)\">\n <span *ngIf=\"chip.imageUrl as imageUrl\" class=\"image-container\">\n <img [src]=\"imageUrl\" alt=\"image of {{chip.label}}\">\n </span>\n {{chip.label}}\n <mat-icon\n matChipRemove\n *ngIf=\"config.areChipsRemovable\">\n cancel\n </mat-icon>\n </mat-chip>\n\n <input\n matInput\n [formControl]=\"autocompleteInputControl\"\n [placeholder]=\"config.placeholder\"\n [matChipInputFor]=\"chipList\"\n [matAutocomplete]=\"auto\"\n (keydown.tab)=\"handleTab($event)\"\n [matChipInputSeparatorKeyCodes]=\"config.separatorKeyCodes\"\n (matChipInputTokenEnd)=\"handleTokenEnd($event)\"\n role=\"searchbox\"\n type=\"text\"\n autocapitalize=\"off\"\n autocorrect=\"off\"\n spellcheck=\"false\"\n #autoInput/>\n <span *ngIf=\"config.fieldSuffix\" matSuffix>{{config.fieldSuffix}}</span>\n <crispr-info\n *ngIf=\"config.info\"\n matSuffix\n [info]=\"config.info \">\n </crispr-info>\n\n </mat-chip-list>\n <mat-autocomplete\n #auto=\"matAutocomplete\"\n [autoActiveFirstOption]=\"this.config.autoActiveFirstOption\"\n (optionSelected)=\"handleSelect($event)\"\n [displayWith]=\"mapToLabel\">\n <ng-container *ngIf=\"remainingOptions$ | async as remainingOptions; else emptyOption\">\n <ng-container *ngIf=\"remainingOptions.length > 0; else emptyOption\">\n <mat-option\n *ngFor=\"let option of remainingOptions$ | async\"\n [value]=\"option\">\n <crispr-option [option]=\"option\"></crispr-option>\n </mat-option>\n </ng-container>\n\n </ng-container>\n <ng-template #emptyOption>\n <mat-option disabled=\"true\">\n {{config.emptyOptionsMessage}}\n </mat-option>\n </ng-template>\n </mat-autocomplete>\n\n\n </mat-form-field>\n</crispr-field-container>\n", styles: [".refinement-chip .image-container{width:26px;height:26px;border-radius:50%;overflow:hidden;margin:-2px 4px -2px -8px}.refinement-chip .image-container img{width:100%;height:100%;object-fit:cover}\n"] }]
710
+ }], propDecorators: { chipInput: [{
711
+ type: ViewChild,
712
+ args: ['autoInput', { read: MatAutocompleteTrigger }]
713
+ }], chipInputRef: [{
714
+ type: ViewChild,
715
+ args: ['autoInput']
716
+ }] } });
717
+
718
+ const defaultConfig$5 = {
719
+ labelPosition: 'after',
720
+ inline: false
721
+ };
722
+ const CheckboxFieldMixin = crisprControlMixin(CrisprFieldComponent);
723
+ class CheckboxFieldComponent extends CheckboxFieldMixin {
724
+ constructor() {
725
+ super(...arguments);
726
+ this.defaultConfig = defaultConfig$5;
727
+ }
728
+ ngOnInit() {
729
+ super.ngOnInit();
730
+ }
731
+ }
732
+ CheckboxFieldComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: CheckboxFieldComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
733
+ CheckboxFieldComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.2.1", type: CheckboxFieldComponent, selector: "crispr-checkbox-field", usesInheritance: true, ngImport: i0, template: "<crispr-field-container\n [config]=\"config\"\n [group]=\"group\"\n [inlineField]=\"config.inline\">\n <div\n [formGroup]=\"group\">\n <mat-checkbox\n [color]=\"config.color\"\n [labelPosition]=\"config.labelPosition\"\n [formControlName]=\"config.controlName\">\n {{config.label}}\n <crispr-info\n matSuffix *ngIf=\"config.info\"\n [info]=\"config.info\">\n </crispr-info>\n </mat-checkbox>\n </div>\n</crispr-field-container>\n", styles: [""], components: [{ type: FieldContainerComponent, selector: "crispr-field-container", inputs: ["config", "group", "inlineField"] }, { type: i4$2.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex", "aria-label", "aria-labelledby", "aria-describedby", "id", "required", "labelPosition", "name", "value", "checked", "disabled", "indeterminate"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { type: InfoComponent, selector: "crispr-info", inputs: ["info"] }], directives: [{ type: i4$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i4$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i5.ControlErrorContainerDirective, selector: "[controlErrorContainer], [formGroup]" }, { type: i4$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i4$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { type: i5.ControlErrorsDirective, selector: "[formControl], [formControlName]" }, { type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i2$1.MatSuffix, selector: "[matSuffix]" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, preserveWhitespaces: true });
734
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: CheckboxFieldComponent, decorators: [{
735
+ type: Component,
736
+ args: [{ selector: 'crispr-checkbox-field', changeDetection: ChangeDetectionStrategy.OnPush, template: "<crispr-field-container\n [config]=\"config\"\n [group]=\"group\"\n [inlineField]=\"config.inline\">\n <div\n [formGroup]=\"group\">\n <mat-checkbox\n [color]=\"config.color\"\n [labelPosition]=\"config.labelPosition\"\n [formControlName]=\"config.controlName\">\n {{config.label}}\n <crispr-info\n matSuffix *ngIf=\"config.info\"\n [info]=\"config.info\">\n </crispr-info>\n </mat-checkbox>\n </div>\n</crispr-field-container>\n", styles: [""] }]
737
+ }] });
738
+
739
+ const defaultConfig$4 = { rows: 5 };
740
+ const TextareaFieldMixin = crisprControlMixin(CrisprFieldComponent);
741
+ class TextareaFieldComponent extends TextareaFieldMixin {
742
+ constructor() {
743
+ super(...arguments);
744
+ this.defaultConfig = defaultConfig$4;
745
+ }
746
+ ngOnInit() {
747
+ super.ngOnInit();
748
+ }
749
+ }
750
+ TextareaFieldComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: TextareaFieldComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
751
+ TextareaFieldComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.2.1", type: TextareaFieldComponent, selector: "crispr-textarea-field", usesInheritance: true, ngImport: i0, template: "<crispr-field-container\n [config]=\"config\"\n [group]=\"group\">\n <mat-form-field\n [color]=\"config.color\"\n [appearance]=\"config.appearance\"\n [formGroup]=\"group\">\n <mat-label *ngIf=\"config.label\">\n {{config.label}}\n </mat-label>\n <textarea\n [rows]=\"config.rows\"\n matInput\n [placeholder]=\"config.placeholder\"\n [formControlName]=\"config.controlName\">\n </textarea>\n <span *ngIf=\"config.fieldSuffix\" matSuffix>{{config.fieldSuffix}}</span>\n <crispr-info\n *ngIf=\"config.info\"\n matSuffix\n [info]=\"config.info\">\n </crispr-info>\n </mat-form-field>\n\n</crispr-field-container>\n", styles: [""], components: [{ type: FieldContainerComponent, selector: "crispr-field-container", inputs: ["config", "group", "inlineField"] }, { type: i2$1.MatFormField, selector: "mat-form-field", inputs: ["color", "appearance", "hideRequiredMarker", "hintLabel", "floatLabel"], exportAs: ["matFormField"] }, { type: InfoComponent, selector: "crispr-info", inputs: ["info"] }], directives: [{ type: i4$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i4$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i5.ControlErrorContainerDirective, selector: "[controlErrorContainer], [formGroup]" }, { type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i2$1.MatLabel, selector: "mat-label" }, { type: i7.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly"], exportAs: ["matInput"] }, { type: i4$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i4$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i4$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { type: i5.ControlErrorsDirective, selector: "[formControl], [formControlName]" }, { type: i2$1.MatSuffix, selector: "[matSuffix]" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, preserveWhitespaces: true });
752
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: TextareaFieldComponent, decorators: [{
753
+ type: Component,
754
+ args: [{ selector: 'crispr-textarea-field', changeDetection: ChangeDetectionStrategy.OnPush, template: "<crispr-field-container\n [config]=\"config\"\n [group]=\"group\">\n <mat-form-field\n [color]=\"config.color\"\n [appearance]=\"config.appearance\"\n [formGroup]=\"group\">\n <mat-label *ngIf=\"config.label\">\n {{config.label}}\n </mat-label>\n <textarea\n [rows]=\"config.rows\"\n matInput\n [placeholder]=\"config.placeholder\"\n [formControlName]=\"config.controlName\">\n </textarea>\n <span *ngIf=\"config.fieldSuffix\" matSuffix>{{config.fieldSuffix}}</span>\n <crispr-info\n *ngIf=\"config.info\"\n matSuffix\n [info]=\"config.info\">\n </crispr-info>\n </mat-form-field>\n\n</crispr-field-container>\n", styles: [""] }]
755
+ }] });
756
+
757
+ const defaultConfig$3 = { displayLimits: true };
758
+ const SliderFieldMixin = crisprControlMixin(CrisprFieldComponent);
759
+ class SliderFieldComponent extends SliderFieldMixin {
760
+ constructor() {
761
+ super();
762
+ this.defaultConfig = defaultConfig$3;
763
+ }
764
+ get flexDirection() {
765
+ return this.config.vertical ? 'column' : 'row';
766
+ }
767
+ ngOnInit() {
768
+ super.ngOnInit();
769
+ }
770
+ }
771
+ SliderFieldComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: SliderFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
772
+ SliderFieldComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.2.1", type: SliderFieldComponent, selector: "crispr-slider-field", usesInheritance: true, ngImport: i0, template: "<crispr-field-container\n [config]=\"config\"\n [group]=\"group\">\n <div\n [formGroup]=\"group\">\n <label *ngIf=\"config.label\">\n {{config.label}}\n <crispr-info\n *ngIf=\"config.info\"\n [info]=\"config.info\">\n </crispr-info>\n </label>\n <div class=\"slider-container\"\n [ngStyle]=\"{'flex-direction': flexDirection}\">\n <span *ngIf=\"config.displayLimits\">\n {{config.min}}\n </span>\n <mat-slider\n class=\"example-margin\"\n [formControlName]=\"config.controlName\"\n [invert]=\"config.invert\"\n [max]=\"config.max\"\n [min]=\"config.min\"\n [step]=\"config.step\"\n [thumbLabel]=\"config.thumbLabel\"\n [tickInterval]=\"config.tickInterval\"\n [vertical]=\"config.vertical\">\n </mat-slider>\n <span *ngIf=\"config.displayLimits\">\n {{config.max}}\n </span>\n </div>\n\n </div>\n</crispr-field-container>\n\n", styles: [".slider-container{display:flex;align-items:center}.slider-container .mat-slider-horizontal{width:100%}\n"], components: [{ type: FieldContainerComponent, selector: "crispr-field-container", inputs: ["config", "group", "inlineField"] }, { type: InfoComponent, selector: "crispr-info", inputs: ["info"] }, { type: i3$3.MatSlider, selector: "mat-slider", inputs: ["disabled", "color", "tabIndex", "invert", "max", "min", "step", "thumbLabel", "tickInterval", "value", "displayWith", "valueText", "vertical"], outputs: ["change", "input", "valueChange"], exportAs: ["matSlider"] }], directives: [{ type: i4$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i4$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i5.ControlErrorContainerDirective, selector: "[controlErrorContainer], [formGroup]" }, { type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i2.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { type: i4$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i4$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { type: i5.ControlErrorsDirective, selector: "[formControl], [formControlName]" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, preserveWhitespaces: true });
773
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: SliderFieldComponent, decorators: [{
774
+ type: Component,
775
+ args: [{ selector: 'crispr-slider-field', changeDetection: ChangeDetectionStrategy.OnPush, template: "<crispr-field-container\n [config]=\"config\"\n [group]=\"group\">\n <div\n [formGroup]=\"group\">\n <label *ngIf=\"config.label\">\n {{config.label}}\n <crispr-info\n *ngIf=\"config.info\"\n [info]=\"config.info\">\n </crispr-info>\n </label>\n <div class=\"slider-container\"\n [ngStyle]=\"{'flex-direction': flexDirection}\">\n <span *ngIf=\"config.displayLimits\">\n {{config.min}}\n </span>\n <mat-slider\n class=\"example-margin\"\n [formControlName]=\"config.controlName\"\n [invert]=\"config.invert\"\n [max]=\"config.max\"\n [min]=\"config.min\"\n [step]=\"config.step\"\n [thumbLabel]=\"config.thumbLabel\"\n [tickInterval]=\"config.tickInterval\"\n [vertical]=\"config.vertical\">\n </mat-slider>\n <span *ngIf=\"config.displayLimits\">\n {{config.max}}\n </span>\n </div>\n\n </div>\n</crispr-field-container>\n\n", styles: [".slider-container{display:flex;align-items:center}.slider-container .mat-slider-horizontal{width:100%}\n"] }]
776
+ }], ctorParameters: function () { return []; } });
777
+
778
+ class ButtonComponent extends CrisprFieldComponent {
779
+ constructor() {
780
+ super(...arguments);
781
+ this.defaultConfig = { buttonType: 'raised', type: 'submit' };
782
+ }
783
+ get matButtonClass() {
784
+ return this.config.buttonType ? `mat-${this.config.buttonType}-button` : '';
785
+ }
786
+ ngOnInit() {
787
+ super.ngOnInit();
788
+ this.formValid$ = this.group.statusChanges.pipe(map(status => status === 'VALID'), startWith(this.group.valid));
789
+ }
790
+ handleClick(group, event) {
791
+ if (this.config.callback) {
792
+ this.config.callback(group, event);
793
+ }
794
+ }
795
+ }
796
+ ButtonComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: ButtonComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
797
+ ButtonComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.2.1", type: ButtonComponent, selector: "crispr-button", usesInheritance: true, ngImport: i0, template: "<button\n [formGroup]=\"group\"\n mat-button\n [ngClass]=\"matButtonClass\"\n [color]=\"config.color\"\n [disabled]=\"config.disabledOnInvalidForm && !(formValid$ | async)\"\n [type]=\"config.type\"\n (click)=\"handleClick(group, $event)\"\n [matTooltip]=\"config.info?.content\"\n [matTooltipPosition]=\"config.info?.tooltipPosition || 'below'\">\n {{ config.label }}\n <mat-icon *ngIf=\"config.icon\">\n {{ config.icon}}\n </mat-icon>\n</button>\n\n", styles: [""], components: [{ type: i1.MatButton, selector: "button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }, { type: i4.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }], directives: [{ type: i4$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i4$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i5.ControlErrorContainerDirective, selector: "[controlErrorContainer], [formGroup]" }, { type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { type: i3.MatTooltip, selector: "[matTooltip]", exportAs: ["matTooltip"] }, { type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], pipes: { "async": i2.AsyncPipe }, changeDetection: i0.ChangeDetectionStrategy.OnPush, preserveWhitespaces: true });
798
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: ButtonComponent, decorators: [{
799
+ type: Component,
800
+ args: [{ selector: 'crispr-button', changeDetection: ChangeDetectionStrategy.OnPush, template: "<button\n [formGroup]=\"group\"\n mat-button\n [ngClass]=\"matButtonClass\"\n [color]=\"config.color\"\n [disabled]=\"config.disabledOnInvalidForm && !(formValid$ | async)\"\n [type]=\"config.type\"\n (click)=\"handleClick(group, $event)\"\n [matTooltip]=\"config.info?.content\"\n [matTooltipPosition]=\"config.info?.tooltipPosition || 'below'\">\n {{ config.label }}\n <mat-icon *ngIf=\"config.icon\">\n {{ config.icon}}\n </mat-icon>\n</button>\n\n", styles: [""] }]
801
+ }] });
802
+
803
+ const defaultConfig$2 = {
804
+ startView: 'month',
805
+ };
806
+ const DatepickerFieldMixin = crisprControlMixin(CrisprFieldComponent);
807
+ class DatepickerFieldComponent extends DatepickerFieldMixin {
808
+ constructor() {
809
+ super(...arguments);
810
+ this.defaultConfig = defaultConfig$2;
811
+ }
812
+ ngOnInit() {
813
+ super.ngOnInit();
814
+ this.startAt$ = this.config.startAt instanceof Date
815
+ ? of(this.config.startAt)
816
+ : this.config.startAt instanceof Function
817
+ ? this.config.startAt(this.group)
818
+ : of(null);
819
+ this.dateClass = this.config?.cellClassFunction || null;
820
+ this.dateClass$ = this.config.dateClass ? this.config?.dateClass(this.group) : of(() => '');
821
+ }
822
+ ngAfterContentInit() {
823
+ if (this.config.datepickerActions) {
824
+ this.calendarFooterPortal = new ComponentPortal(this.config.datepickerActions);
825
+ }
826
+ }
827
+ }
828
+ DatepickerFieldComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: DatepickerFieldComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
829
+ DatepickerFieldComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.2.1", type: DatepickerFieldComponent, selector: "crispr-datepicker-field", usesInheritance: true, ngImport: i0, template: "<crispr-field-container\n [config]=\"config\"\n [group]=\"group\">\n <mat-form-field\n [color]=\"config.color\"\n [appearance]=\"config.appearance\"\n [formGroup]=\"group\">\n <mat-label *ngIf=\"config.label\">\n {{config.label}}\n </mat-label>\n <input\n matInput\n [formControlName]=\"config.controlName\"\n [min]=\"config.min\"\n [max]=\"config.max\"\n [matDatepicker]=\"picker\"\n [matDatepickerFilter]=\"config.datepickerFilter\">\n <mat-datepicker-toggle matSuffix [for]=\"picker\"></mat-datepicker-toggle>\n <mat-datepicker\n [touchUi]=\"config.touchUi\"\n [startView]=\"config.startView\"\n [startAt]=\"startAt$ | async\"\n [dateClass]=\"dateClass || (dateClass$ | async)\"\n #picker>\n <mat-datepicker-actions *ngIf=\"calendarFooterPortal\">\n <ng-template [cdkPortalOutlet]=\"calendarFooterPortal\"></ng-template>\n </mat-datepicker-actions>\n </mat-datepicker>\n\n </mat-form-field>\n</crispr-field-container>\n\n", styles: [""], components: [{ type: FieldContainerComponent, selector: "crispr-field-container", inputs: ["config", "group", "inlineField"] }, { type: i2$1.MatFormField, selector: "mat-form-field", inputs: ["color", "appearance", "hideRequiredMarker", "hintLabel", "floatLabel"], exportAs: ["matFormField"] }, { type: i3$4.MatDatepickerToggle, selector: "mat-datepicker-toggle", inputs: ["for", "tabIndex", "aria-label", "disabled", "disableRipple"], exportAs: ["matDatepickerToggle"] }, { type: i3$4.MatDatepicker, selector: "mat-datepicker", exportAs: ["matDatepicker"] }, { type: i3$4.MatDatepickerActions, selector: "mat-datepicker-actions, mat-date-range-picker-actions" }], directives: [{ type: i4$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i4$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i5.ControlErrorContainerDirective, selector: "[controlErrorContainer], [formGroup]" }, { type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i2$1.MatLabel, selector: "mat-label" }, { type: i7.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly"], exportAs: ["matInput"] }, { type: i4$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i3$4.MatDatepickerInput, selector: "input[matDatepicker]", inputs: ["matDatepicker", "min", "max", "matDatepickerFilter"], exportAs: ["matDatepickerInput"] }, { type: i4$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i4$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { type: i5.ControlErrorsDirective, selector: "[formControl], [formControlName]" }, { type: i2$1.MatSuffix, selector: "[matSuffix]" }, { type: i8.CdkPortalOutlet, selector: "[cdkPortalOutlet]", inputs: ["cdkPortalOutlet"], outputs: ["attached"], exportAs: ["cdkPortalOutlet"] }], pipes: { "async": i2.AsyncPipe }, changeDetection: i0.ChangeDetectionStrategy.OnPush, preserveWhitespaces: true });
830
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: DatepickerFieldComponent, decorators: [{
831
+ type: Component,
832
+ args: [{ selector: 'crispr-datepicker-field', changeDetection: ChangeDetectionStrategy.OnPush, template: "<crispr-field-container\n [config]=\"config\"\n [group]=\"group\">\n <mat-form-field\n [color]=\"config.color\"\n [appearance]=\"config.appearance\"\n [formGroup]=\"group\">\n <mat-label *ngIf=\"config.label\">\n {{config.label}}\n </mat-label>\n <input\n matInput\n [formControlName]=\"config.controlName\"\n [min]=\"config.min\"\n [max]=\"config.max\"\n [matDatepicker]=\"picker\"\n [matDatepickerFilter]=\"config.datepickerFilter\">\n <mat-datepicker-toggle matSuffix [for]=\"picker\"></mat-datepicker-toggle>\n <mat-datepicker\n [touchUi]=\"config.touchUi\"\n [startView]=\"config.startView\"\n [startAt]=\"startAt$ | async\"\n [dateClass]=\"dateClass || (dateClass$ | async)\"\n #picker>\n <mat-datepicker-actions *ngIf=\"calendarFooterPortal\">\n <ng-template [cdkPortalOutlet]=\"calendarFooterPortal\"></ng-template>\n </mat-datepicker-actions>\n </mat-datepicker>\n\n </mat-form-field>\n</crispr-field-container>\n\n", styles: [""] }]
833
+ }] });
834
+
835
+ class DividerComponent extends CrisprFieldComponent {
836
+ constructor() {
837
+ super(...arguments);
838
+ // TODO: pull in type after configs are better organized
839
+ this.defaultConfig = {};
840
+ }
841
+ ngOnInit() {
842
+ super.ngOnInit();
843
+ }
844
+ }
845
+ DividerComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: DividerComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
846
+ DividerComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.2.1", type: DividerComponent, selector: "crispr-divider", usesInheritance: true, ngImport: i0, template: "<mat-divider [ngClass]=\"config.classes\"></mat-divider>", styles: [":host{display:block;padding:1em 0}::ng-deep .mat-divider.mat-divider-horizontal{position:relative}\n"], components: [{ type: i1$1.MatDivider, selector: "mat-divider", inputs: ["vertical", "inset"] }], directives: [{ type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }], preserveWhitespaces: true });
847
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: DividerComponent, decorators: [{
848
+ type: Component,
849
+ args: [{ selector: 'crispr-divider', template: "<mat-divider [ngClass]=\"config.classes\"></mat-divider>", styles: [":host{display:block;padding:1em 0}::ng-deep .mat-divider.mat-divider-horizontal{position:relative}\n"] }]
850
+ }] });
851
+
852
+ const RadioFieldMixin = crisprControlMixin(CrisprFieldComponent);
853
+ class RadioFieldComponent extends RadioFieldMixin {
854
+ constructor() {
855
+ super(...arguments);
856
+ this.defaultConfig = {};
857
+ }
858
+ ngOnInit() {
859
+ super.ngOnInit();
860
+ // options$ can be passed as an array, promise that resolves array, or observable that resolves array
861
+ // this functions accounts for all possibilities and converts to observable that resolves array
862
+ this.options$ = observablifyOptions(this.config.options, this.group);
863
+ }
864
+ }
865
+ RadioFieldComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: RadioFieldComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
866
+ RadioFieldComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.2.1", type: RadioFieldComponent, selector: "crispr-radio-field", usesInheritance: true, ngImport: i0, template: "<crispr-field-container\n [config]=\"config\"\n [group]=\"group\">\n\n <mat-radio-group\n [formControl]=\"control\"\n [color]=\"config.color\">\n <mat-radio-button class=\"example-radio-button\" *ngFor=\"let option of options$ | async\" [value]=\"option.value\">\n {{option.label}}\n </mat-radio-button>\n </mat-radio-group>\n</crispr-field-container>\n", styles: ["mat-radio-button{padding:12px}\n"], components: [{ type: FieldContainerComponent, selector: "crispr-field-container", inputs: ["config", "group", "inlineField"] }, { type: i2$2.MatRadioButton, selector: "mat-radio-button", inputs: ["disableRipple", "tabIndex"], exportAs: ["matRadioButton"] }], directives: [{ type: i2$2.MatRadioGroup, selector: "mat-radio-group", exportAs: ["matRadioGroup"] }, { type: i4$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i4$1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { type: i5.ControlErrorsDirective, selector: "[formControl], [formControlName]" }, { type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }], pipes: { "async": i2.AsyncPipe }, changeDetection: i0.ChangeDetectionStrategy.OnPush, preserveWhitespaces: true });
867
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: RadioFieldComponent, decorators: [{
868
+ type: Component,
869
+ args: [{ selector: 'crispr-radio-field', changeDetection: ChangeDetectionStrategy.OnPush, template: "<crispr-field-container\n [config]=\"config\"\n [group]=\"group\">\n\n <mat-radio-group\n [formControl]=\"control\"\n [color]=\"config.color\">\n <mat-radio-button class=\"example-radio-button\" *ngFor=\"let option of options$ | async\" [value]=\"option.value\">\n {{option.label}}\n </mat-radio-button>\n </mat-radio-group>\n</crispr-field-container>\n", styles: ["mat-radio-button{padding:12px}\n"] }]
870
+ }] });
871
+
872
+ const defaultConfig$1 = {};
873
+ const UnitConversionFieldMixin = crisprControlMixin(CrisprFieldComponent);
874
+ class UnitConversionFieldComponent extends UnitConversionFieldMixin {
875
+ constructor() {
876
+ super(...arguments);
877
+ this.defaultConfig = defaultConfig$1;
878
+ this.displayValueControl = new FormControl();
879
+ this.unitSelectControl = new FormControl();
880
+ }
881
+ ngOnInit() {
882
+ super.ngOnInit();
883
+ // TODO: Validators need work. validation is tricky because the input needs to be validated against but the validator will compare against the controls value
884
+ // this.displayValueControl.setValidators(this.config.validators);
885
+ const controlValuePipeline = [
886
+ this.displayValueControl.valueChanges.pipe(startWith(this.displayValueControl.value))
887
+ ];
888
+ // setup all required pieces when showing a field for selecting units
889
+ if (this.config.showUnitSelect) {
890
+ this.unitOptions$ = observablifyOptions(this.config.selectableUnits, this.group);
891
+ controlValuePipeline.push(this.unitSelectControl.valueChanges.pipe(startWith(this.config?.initialDisplayUnit || null)));
892
+ this.unitSelectControl.setValue(this.config?.initialDisplayUnit || null);
893
+ }
894
+ this.transformationSubscription = combineLatest(controlValuePipeline).subscribe(([displayValue, unitValue]) => {
895
+ const computedValue = this.config.storedValueConversion(displayValue, unitValue);
896
+ this.control.setValue(computedValue);
897
+ });
898
+ }
899
+ ngOnDestroy() {
900
+ this.transformationSubscription.unsubscribe();
901
+ }
902
+ setInitialDisplayValue(storedValue, unit) {
903
+ const initialDisplayValue = this.config.initialDisplayValueConversion(storedValue || null, unit);
904
+ this.displayValueControl.setValue(initialDisplayValue);
905
+ }
906
+ /**
907
+ * We override the 'setControlValue' we inherited from crisprControlMixin and add our custom logic,
908
+ * This function gets called onInit because were object oriented. it's so great, so great that I'm
909
+ * typing a paragraph to explain what the hell is going on...
910
+ * @param value the initial value for the control passed down from the form components input
911
+ */
912
+ setControlValue(value) {
913
+ const initialUnitValue = this.config.showUnitSelect ? this.config?.initialDisplayUnit : null;
914
+ this.setInitialDisplayValue(value, initialUnitValue);
915
+ }
916
+ }
917
+ UnitConversionFieldComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: UnitConversionFieldComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
918
+ UnitConversionFieldComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.2.1", type: UnitConversionFieldComponent, selector: "crispr-unit-conversion-field", usesInheritance: true, ngImport: i0, template: "<crispr-field-container\n [config]=\"config\"\n [group]=\"group\">\n <mat-form-field\n [style.width.%]=\"config.showUnitSelect ? 60 : 100\"\n class=\"number-field\"\n [color]=\"config.color\"\n [appearance]=\"config.appearance\">\n <mat-label *ngIf=\"config.label\">\n {{config.label}}\n </mat-label>\n <input\n type=\"number\"\n matInput\n [formControl]=\"displayValueControl\"\n [placeholder]=\"config.placeholder\"\n [min]=\"config.min\"\n [max]=\"config.max\"\n [step]=\"config.step\"\n [autofocus]=\"config.autofocus\">\n <span *ngIf=\"config.fieldSuffix\" matSuffix>{{config.fieldSuffix}}</span>\n <crispr-info\n matSuffix\n *ngIf=\"config.info\"\n [info]=\"config.info\">\n </crispr-info>\n </mat-form-field>\n\n <mat-form-field\n *ngIf=\"config.showUnitSelect\"\n [color]=\"config.color\"\n [appearance]=\"config.appearance\"\n [formGroup]=\"group\"\n class=\"unit-field\">\n <mat-label *ngIf=\"config.label\">\n {{config.label}}\n </mat-label>\n <mat-select\n #selectField\n [formControl]=\"unitSelectControl\">\n\n <mat-option\n *ngFor=\"let option of unitOptions$ | async\"\n [value]=\"option.value\">\n <crispr-option [option]=\"option\">\n </crispr-option>\n </mat-option>\n\n </mat-select>\n\n <!-- <span *ngIf=\"config.fieldSuffix\" matSuffix>{{config.fieldSuffix}}</span> -->\n <!-- <crispr-info\n *ngIf=\"config.info\"\n matSuffix\n [info]=\"config.info\">\n </crispr-info> -->\n </mat-form-field>\n\n\n</crispr-field-container>\n", styles: [".unit-field{width:40%;margin-left:16px}:host ::ng-deep .field-container{display:flex}\n"], components: [{ type: FieldContainerComponent, selector: "crispr-field-container", inputs: ["config", "group", "inlineField"] }, { type: i2$1.MatFormField, selector: "mat-form-field", inputs: ["color", "appearance", "hideRequiredMarker", "hintLabel", "floatLabel"], exportAs: ["matFormField"] }, { type: InfoComponent, selector: "crispr-info", inputs: ["info"] }, { type: i3$1.MatSelect, selector: "mat-select", inputs: ["disabled", "disableRipple", "tabIndex"], exportAs: ["matSelect"] }, { type: i5$1.MatOption, selector: "mat-option", exportAs: ["matOption"] }, { type: OptionComponent, selector: "crispr-option", inputs: ["option"] }], directives: [{ type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i2$1.MatLabel, selector: "mat-label" }, { type: i4$1.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { type: i4$1.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { type: i4$1.MaxValidator, selector: "input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]", inputs: ["max"] }, { type: i7.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly"], exportAs: ["matInput"] }, { type: i4$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i4$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i4$1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { type: i5.ControlErrorsDirective, selector: "[formControl], [formControlName]" }, { type: i2$1.MatSuffix, selector: "[matSuffix]" }, { type: i4$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i4$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i5.ControlErrorContainerDirective, selector: "[controlErrorContainer], [formGroup]" }, { type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }], pipes: { "async": i2.AsyncPipe }, changeDetection: i0.ChangeDetectionStrategy.OnPush, preserveWhitespaces: true });
919
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: UnitConversionFieldComponent, decorators: [{
920
+ type: Component,
921
+ args: [{ selector: 'crispr-unit-conversion-field', changeDetection: ChangeDetectionStrategy.OnPush, template: "<crispr-field-container\n [config]=\"config\"\n [group]=\"group\">\n <mat-form-field\n [style.width.%]=\"config.showUnitSelect ? 60 : 100\"\n class=\"number-field\"\n [color]=\"config.color\"\n [appearance]=\"config.appearance\">\n <mat-label *ngIf=\"config.label\">\n {{config.label}}\n </mat-label>\n <input\n type=\"number\"\n matInput\n [formControl]=\"displayValueControl\"\n [placeholder]=\"config.placeholder\"\n [min]=\"config.min\"\n [max]=\"config.max\"\n [step]=\"config.step\"\n [autofocus]=\"config.autofocus\">\n <span *ngIf=\"config.fieldSuffix\" matSuffix>{{config.fieldSuffix}}</span>\n <crispr-info\n matSuffix\n *ngIf=\"config.info\"\n [info]=\"config.info\">\n </crispr-info>\n </mat-form-field>\n\n <mat-form-field\n *ngIf=\"config.showUnitSelect\"\n [color]=\"config.color\"\n [appearance]=\"config.appearance\"\n [formGroup]=\"group\"\n class=\"unit-field\">\n <mat-label *ngIf=\"config.label\">\n {{config.label}}\n </mat-label>\n <mat-select\n #selectField\n [formControl]=\"unitSelectControl\">\n\n <mat-option\n *ngFor=\"let option of unitOptions$ | async\"\n [value]=\"option.value\">\n <crispr-option [option]=\"option\">\n </crispr-option>\n </mat-option>\n\n </mat-select>\n\n <!-- <span *ngIf=\"config.fieldSuffix\" matSuffix>{{config.fieldSuffix}}</span> -->\n <!-- <crispr-info\n *ngIf=\"config.info\"\n matSuffix\n [info]=\"config.info\">\n </crispr-info> -->\n </mat-form-field>\n\n\n</crispr-field-container>\n", styles: [".unit-field{width:40%;margin-left:16px}:host ::ng-deep .field-container{display:flex}\n"] }]
922
+ }] });
923
+
924
+ class FileDropzoneDirective {
925
+ constructor() {
926
+ this.fileDrop = new EventEmitter();
927
+ this.crisprFileDropzone = true;
928
+ }
929
+ onDrop($event) {
930
+ if (this.crisprFileDropzone) {
931
+ $event.preventDefault();
932
+ this.fileDrop.emit($event.dataTransfer.files);
933
+ }
934
+ }
935
+ // Prevents DOM from trying to open file in browser
936
+ onDragOver($event) {
937
+ if (this.crisprFileDropzone) {
938
+ $event.preventDefault();
939
+ }
940
+ }
941
+ }
942
+ FileDropzoneDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: FileDropzoneDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
943
+ FileDropzoneDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "13.2.1", type: FileDropzoneDirective, selector: "[crisprFileDropzone]", inputs: { crisprFileDropzone: "crisprFileDropzone" }, outputs: { fileDrop: "fileDrop" }, host: { listeners: { "drop": "onDrop($event)", "dragover": "onDragOver($event)" } }, ngImport: i0 });
944
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: FileDropzoneDirective, decorators: [{
945
+ type: Directive,
946
+ args: [{
947
+ selector: '[crisprFileDropzone]'
948
+ }]
949
+ }], propDecorators: { fileDrop: [{
950
+ type: Output
951
+ }], crisprFileDropzone: [{
952
+ type: Input
953
+ }], onDrop: [{
954
+ type: HostListener,
955
+ args: ['drop', ['$event']]
956
+ }], onDragOver: [{
957
+ type: HostListener,
958
+ args: ['dragover', ['$event']]
959
+ }] } });
960
+
961
+ class SelectedFileComponent {
962
+ }
963
+ SelectedFileComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: SelectedFileComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
964
+ SelectedFileComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.2.1", type: SelectedFileComponent, selector: "crispr-selected-file", inputs: { fileName: "fileName", progress: "progress", showProgress: "showProgress", color: "color" }, ngImport: i0, template: "<h3 class=\"mat-h3\">{{ fileName }}</h3>\n<mat-progress-bar\n *ngIf=\"showProgress\"\n mode=\"determinate\"\n [color]=\"color\"\n [value]=\"progress\">\n</mat-progress-bar>\n", styles: ["mat-progress-bar{margin-bottom:8px}\n"], components: [{ type: i1$2.MatProgressBar, selector: "mat-progress-bar", inputs: ["color", "value", "bufferValue", "mode"], outputs: ["animationEnd"], exportAs: ["matProgressBar"] }], directives: [{ type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], preserveWhitespaces: true });
965
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: SelectedFileComponent, decorators: [{
966
+ type: Component,
967
+ args: [{ selector: 'crispr-selected-file', template: "<h3 class=\"mat-h3\">{{ fileName }}</h3>\n<mat-progress-bar\n *ngIf=\"showProgress\"\n mode=\"determinate\"\n [color]=\"color\"\n [value]=\"progress\">\n</mat-progress-bar>\n", styles: ["mat-progress-bar{margin-bottom:8px}\n"] }]
968
+ }], propDecorators: { fileName: [{
969
+ type: Input
970
+ }], progress: [{
971
+ type: Input
972
+ }], showProgress: [{
973
+ type: Input
974
+ }], color: [{
975
+ type: Input
976
+ }] } });
977
+ class SelectedFileModule {
978
+ }
979
+ SelectedFileModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: SelectedFileModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
980
+ SelectedFileModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: SelectedFileModule, declarations: [SelectedFileComponent], imports: [CommonModule,
981
+ MatProgressBarModule], exports: [SelectedFileComponent] });
982
+ SelectedFileModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: SelectedFileModule, imports: [[
983
+ CommonModule,
984
+ MatProgressBarModule
985
+ ]] });
986
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: SelectedFileModule, decorators: [{
987
+ type: NgModule,
988
+ args: [{
989
+ imports: [
990
+ CommonModule,
991
+ MatProgressBarModule
992
+ ],
993
+ exports: [
994
+ SelectedFileComponent
995
+ ],
996
+ declarations: [
997
+ SelectedFileComponent
998
+ ]
999
+ }]
1000
+ }] });
1001
+
1002
+ const FileUploadFieldMixin = crisprControlMixin(CrisprFieldComponent);
1003
+ class FileUploadFieldComponent extends FileUploadFieldMixin {
1004
+ // ngControl: NgControl = null;
1005
+ constructor(ngControl) {
1006
+ super();
1007
+ this.ngControl = ngControl;
1008
+ this.defaultConfig = {
1009
+ allowMultipleFiles: false,
1010
+ acceptedTypes: '*.*',
1011
+ dropZoneText: 'DROP FILE HERE',
1012
+ selectFilesButtonType: 'button',
1013
+ selectButtonText: 'SELECT',
1014
+ showClearFilesButton: true,
1015
+ clearFilesButtonText: 'CLEAR',
1016
+ uploadButtonText: 'UPLOAD',
1017
+ uploadButtonType: 'button',
1018
+ showUploadProgress: false,
1019
+ disableOnUpload: true
1020
+ };
1021
+ this.isUploaded = false;
1022
+ this.fileProgress = [];
1023
+ if (this.ngControl != null) {
1024
+ // Setting the value accessor directly (instead of using
1025
+ // the providers) to avoid running into a circular import.
1026
+ ngControl.valueAccessor = this;
1027
+ }
1028
+ }
1029
+ ngOnInit() {
1030
+ super.ngOnInit();
1031
+ this.disabled$ = this.config.disabledCallback
1032
+ ? this.config.disabledCallback(this.group, this.config)
1033
+ : of(false);
1034
+ }
1035
+ filesChanged(files) {
1036
+ if (files && files.length > 0) {
1037
+ this.selectedFiles = files;
1038
+ this.control.patchValue(files);
1039
+ }
1040
+ }
1041
+ uploadFiles() {
1042
+ if (this.selectedFiles && this.config.uploadFiles) {
1043
+ this.isUploaded = true;
1044
+ this.config.uploadFiles(this.group, this.selectedFiles, this);
1045
+ }
1046
+ }
1047
+ resetFileInput() {
1048
+ this.fileInputRef.nativeElement.value = '';
1049
+ this.control.patchValue(null);
1050
+ this.isUploaded = false;
1051
+ }
1052
+ writeValue(value) {
1053
+ // clear file input
1054
+ // this.host.nativeElement.value = '';
1055
+ // this.file = null;
1056
+ }
1057
+ registerOnChange(fn) {
1058
+ this.onChange = fn;
1059
+ }
1060
+ registerOnTouched(fn) {
1061
+ }
1062
+ }
1063
+ FileUploadFieldComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: FileUploadFieldComponent, deps: [{ token: i4$1.NgControl, optional: true, self: true }], target: i0.ɵɵFactoryTarget.Component });
1064
+ FileUploadFieldComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.2.1", type: FileUploadFieldComponent, selector: "crispr-file-upload-field", viewQueries: [{ propertyName: "fileInputRef", first: true, predicate: ["fileInput"], descendants: true }], usesInheritance: true, ngImport: i0, template: "<crispr-field-container\n [config]=\"config\"\n [group]=\"group\">\n <mat-form-field floatLabel=\"always\"\n [color]=\"config.color\"\n appearance=\"outline\"\n [crisprFileDropzone]=\"!(disabled$ | async) && !(config.disableOnUpload && isUploaded)\"\n [formGroup]=\"group\"\n (fileDrop)=\"filesChanged($event)\">\n\n <input [formControlName]=\"config.controlName\" matInput type=\"text\"/>\n <input\n #fileInput\n type=\"file\"\n style=\"display: none\"\n [accept]=\"config.acceptedTypes\"\n [multiple]=\"config.allowMultipleFiles\"\n (change)=\"filesChanged($event.target.files)\"/>\n <mat-label>{{config.label}}</mat-label>\n\n <div *ngIf=\"!(selectedFiles?.length > 0); else selectedFileList\" class=\"drop-info\">\n <mat-icon class=\"drop-icon\" inline=\"true\">cloud_upload</mat-icon>\n <h2 class=\"mat-h2\">{{config.dropZoneText}}</h2>\n or\n <button\n mat-raised-button\n type=\"button\"\n color=\"primary\"\n [disabled]=\"(disabled$ | async) || config.disableOnUpload && isUploaded\"\n (click)=\"fileInput.click()\"\n [attr.aria-label]=\"config.controlName\">\n {{config.selectButtonText}}\n </button>\n </div>\n <ng-template #selectedFileList>\n <div class=\"selected-files-container\">\n <div class=\"selected-files-list\">\n <crispr-selected-file\n *ngFor=\"let file of selectedFiles; let i = index;\"\n [color]=\"config.color === 'primary' ? 'accent' : 'primary'\"\n [fileName]=\"file.name\"\n [showProgress]=\"config.showUploadProgress\"\n [progress]=\"fileProgress && (fileProgress[i] | async)\">\n </crispr-selected-file>\n </div>\n\n </div>\n </ng-template>\n\n </mat-form-field>\n <div class=\"button-container\" *ngIf=\"selectedFiles?.length > 0\">\n\n <button\n mat-button\n (click)=\"resetFileInput()\"\n type=\"button\"\n [disabled]=\"(disabled$ | async) || (config.disableOnUpload && isUploaded)\"\n aria-label=\"Remove Selected File(s)\">\n {{config.clearFilesButtonText}}\n <mat-icon>delete</mat-icon>\n </button>\n\n <button\n *ngIf=\"!!config.uploadFiles\"\n mat-raised-button\n type=\"button\"\n color=\"accent\"\n class=\"file-input-button\"\n [disabled]=\"(disabled$ | async) || (config.disableOnUpload && isUploaded)\"\n (click)=\"uploadFiles()\"\n [attr.aria-label]=\"config.uploadButtonText\">\n {{ config.uploadButtonText }}\n </button>\n\n </div>\n</crispr-field-container>\n", styles: [":host ::ng-deep .mat-form-field .mat-form-field-infix{padding-top:0;display:flex;justify-content:center}:host .drop-info{display:flex;flex-direction:column;align-items:center}:host .drop-info .drop-icon{font-size:36px}:host .drop-info .mat-h2{margin:0}:host .button-container{display:flex;justify-content:flex-end;margin-top:-16px}:host .button-container button{margin-left:8px}:host .selected-files-container{width:100%}:host [matInput]{position:absolute;max-height:0;visibility:hidden}\n"], components: [{ type: i0.forwardRef(function () { return FieldContainerComponent; }), selector: "crispr-field-container", inputs: ["config", "group", "inlineField"] }, { type: i0.forwardRef(function () { return i2$1.MatFormField; }), selector: "mat-form-field", inputs: ["color", "appearance", "hideRequiredMarker", "hintLabel", "floatLabel"], exportAs: ["matFormField"] }, { type: i0.forwardRef(function () { return i4.MatIcon; }), selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { type: i0.forwardRef(function () { return i1.MatButton; }), selector: "button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }, { type: i0.forwardRef(function () { return SelectedFileComponent; }), selector: "crispr-selected-file", inputs: ["fileName", "progress", "showProgress", "color"] }], directives: [{ type: i0.forwardRef(function () { return FileDropzoneDirective; }), selector: "[crisprFileDropzone]", inputs: ["crisprFileDropzone"], outputs: ["fileDrop"] }, { type: i0.forwardRef(function () { return i4$1.NgControlStatusGroup; }), selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i0.forwardRef(function () { return i4$1.FormGroupDirective; }), selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i0.forwardRef(function () { return i5.ControlErrorContainerDirective; }), selector: "[controlErrorContainer], [formGroup]" }, { type: i0.forwardRef(function () { return i7.MatInput; }), selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly"], exportAs: ["matInput"] }, { type: i0.forwardRef(function () { return i4$1.DefaultValueAccessor; }), selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i0.forwardRef(function () { return i4$1.NgControlStatus; }), selector: "[formControlName],[ngModel],[formControl]" }, { type: i0.forwardRef(function () { return i4$1.FormControlName; }), selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { type: i0.forwardRef(function () { return i5.ControlErrorsDirective; }), selector: "[formControl], [formControlName]" }, { type: i0.forwardRef(function () { return i2$1.MatLabel; }), selector: "mat-label" }, { type: i0.forwardRef(function () { return i2.NgIf; }), selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i0.forwardRef(function () { return i2.NgForOf; }), selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }], pipes: { "async": i0.forwardRef(function () { return i2.AsyncPipe; }) }, changeDetection: i0.ChangeDetectionStrategy.OnPush, preserveWhitespaces: true });
1065
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: FileUploadFieldComponent, decorators: [{
1066
+ type: Component,
1067
+ args: [{ selector: 'crispr-file-upload-field', changeDetection: ChangeDetectionStrategy.OnPush, template: "<crispr-field-container\n [config]=\"config\"\n [group]=\"group\">\n <mat-form-field floatLabel=\"always\"\n [color]=\"config.color\"\n appearance=\"outline\"\n [crisprFileDropzone]=\"!(disabled$ | async) && !(config.disableOnUpload && isUploaded)\"\n [formGroup]=\"group\"\n (fileDrop)=\"filesChanged($event)\">\n\n <input [formControlName]=\"config.controlName\" matInput type=\"text\"/>\n <input\n #fileInput\n type=\"file\"\n style=\"display: none\"\n [accept]=\"config.acceptedTypes\"\n [multiple]=\"config.allowMultipleFiles\"\n (change)=\"filesChanged($event.target.files)\"/>\n <mat-label>{{config.label}}</mat-label>\n\n <div *ngIf=\"!(selectedFiles?.length > 0); else selectedFileList\" class=\"drop-info\">\n <mat-icon class=\"drop-icon\" inline=\"true\">cloud_upload</mat-icon>\n <h2 class=\"mat-h2\">{{config.dropZoneText}}</h2>\n or\n <button\n mat-raised-button\n type=\"button\"\n color=\"primary\"\n [disabled]=\"(disabled$ | async) || config.disableOnUpload && isUploaded\"\n (click)=\"fileInput.click()\"\n [attr.aria-label]=\"config.controlName\">\n {{config.selectButtonText}}\n </button>\n </div>\n <ng-template #selectedFileList>\n <div class=\"selected-files-container\">\n <div class=\"selected-files-list\">\n <crispr-selected-file\n *ngFor=\"let file of selectedFiles; let i = index;\"\n [color]=\"config.color === 'primary' ? 'accent' : 'primary'\"\n [fileName]=\"file.name\"\n [showProgress]=\"config.showUploadProgress\"\n [progress]=\"fileProgress && (fileProgress[i] | async)\">\n </crispr-selected-file>\n </div>\n\n </div>\n </ng-template>\n\n </mat-form-field>\n <div class=\"button-container\" *ngIf=\"selectedFiles?.length > 0\">\n\n <button\n mat-button\n (click)=\"resetFileInput()\"\n type=\"button\"\n [disabled]=\"(disabled$ | async) || (config.disableOnUpload && isUploaded)\"\n aria-label=\"Remove Selected File(s)\">\n {{config.clearFilesButtonText}}\n <mat-icon>delete</mat-icon>\n </button>\n\n <button\n *ngIf=\"!!config.uploadFiles\"\n mat-raised-button\n type=\"button\"\n color=\"accent\"\n class=\"file-input-button\"\n [disabled]=\"(disabled$ | async) || (config.disableOnUpload && isUploaded)\"\n (click)=\"uploadFiles()\"\n [attr.aria-label]=\"config.uploadButtonText\">\n {{ config.uploadButtonText }}\n </button>\n\n </div>\n</crispr-field-container>\n", styles: [":host ::ng-deep .mat-form-field .mat-form-field-infix{padding-top:0;display:flex;justify-content:center}:host .drop-info{display:flex;flex-direction:column;align-items:center}:host .drop-info .drop-icon{font-size:36px}:host .drop-info .mat-h2{margin:0}:host .button-container{display:flex;justify-content:flex-end;margin-top:-16px}:host .button-container button{margin-left:8px}:host .selected-files-container{width:100%}:host [matInput]{position:absolute;max-height:0;visibility:hidden}\n"] }]
1068
+ }], ctorParameters: function () { return [{ type: i4$1.NgControl, decorators: [{
1069
+ type: Optional
1070
+ }, {
1071
+ type: Self
1072
+ }] }]; }, propDecorators: { fileInputRef: [{
1073
+ type: ViewChild,
1074
+ args: ['fileInput']
1075
+ }] } });
1076
+ class FileUploadFieldModule {
1077
+ }
1078
+ FileUploadFieldModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: FileUploadFieldModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
1079
+ FileUploadFieldModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: FileUploadFieldModule, declarations: [FileUploadFieldComponent, FileDropzoneDirective], imports: [CommonModule,
1080
+ FieldContainerModule,
1081
+ ReactiveFormsModule,
1082
+ MatIconModule,
1083
+ MatButtonModule,
1084
+ MatFormFieldModule,
1085
+ MatInputModule,
1086
+ SelectedFileModule,
1087
+ FormValidationHandlerModule], exports: [FileUploadFieldComponent, FileDropzoneDirective] });
1088
+ FileUploadFieldModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: FileUploadFieldModule, imports: [[
1089
+ CommonModule,
1090
+ FieldContainerModule,
1091
+ ReactiveFormsModule,
1092
+ MatIconModule,
1093
+ MatButtonModule,
1094
+ MatFormFieldModule,
1095
+ MatInputModule,
1096
+ SelectedFileModule,
1097
+ FormValidationHandlerModule,
1098
+ ]] });
1099
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: FileUploadFieldModule, decorators: [{
1100
+ type: NgModule,
1101
+ args: [{
1102
+ imports: [
1103
+ CommonModule,
1104
+ FieldContainerModule,
1105
+ ReactiveFormsModule,
1106
+ MatIconModule,
1107
+ MatButtonModule,
1108
+ MatFormFieldModule,
1109
+ MatInputModule,
1110
+ SelectedFileModule,
1111
+ FormValidationHandlerModule,
1112
+ ],
1113
+ exports: [
1114
+ FileUploadFieldComponent,
1115
+ FileDropzoneDirective
1116
+ ],
1117
+ declarations: [
1118
+ FileUploadFieldComponent,
1119
+ FileDropzoneDirective
1120
+ ]
1121
+ }]
1122
+ }] });
1123
+
1124
+ function convertBytesToMb(bytes) {
1125
+ return bytes / 1048576;
1126
+ }
1127
+
1128
+ const ImageUploadFieldMixin = crisprControlMixin(CrisprFieldComponent);
1129
+ class ImageUploadFieldComponent extends ImageUploadFieldMixin {
1130
+ // ngControl: NgControl = null;
1131
+ constructor(ngControl, domSanitizer, cdr) {
1132
+ super();
1133
+ this.ngControl = ngControl;
1134
+ this.domSanitizer = domSanitizer;
1135
+ this.cdr = cdr;
1136
+ this.defaultConfig = {
1137
+ // allowMultipleFiles: false,
1138
+ acceptedTypes: 'image/*',
1139
+ dropZoneText: 'DROP FILE HERE',
1140
+ selectFilesButtonType: 'button',
1141
+ selectButtonText: 'SELECT',
1142
+ showClearFilesButton: true,
1143
+ clearFilesButtonText: 'CLEAR',
1144
+ resetFilesButtonText: 'RESET',
1145
+ imagePreviewHeight: '250px',
1146
+ compressImage: false,
1147
+ targetCompressedImageFileSizeMb: .4,
1148
+ minCompressionThresholdMb: .6,
1149
+ useWebWorker: true,
1150
+ };
1151
+ this.inputImageFileSubject = new Subject();
1152
+ this.inputImageFile$ = this.inputImageFileSubject.asObservable().pipe(shareReplay(1));
1153
+ this.compressedFile$ = this.inputImageFile$.pipe(switchMap(async (file) => {
1154
+ if (!file)
1155
+ return null;
1156
+ if (typeof file === 'string')
1157
+ return file;
1158
+ const { compressImage, targetCompressedImageFileSizeMb, minCompressionThresholdMb, maxWidthOrHeight, useWebWorker } = this.config;
1159
+ const fileSizeMb = convertBytesToMb(file.size);
1160
+ const shouldCompress = compressImage && targetCompressedImageFileSizeMb < fileSizeMb && minCompressionThresholdMb < fileSizeMb;
1161
+ if (shouldCompress) {
1162
+ const options = {
1163
+ // Use maxWidthOrHeight if it was provided, else use target compressed size
1164
+ ...(maxWidthOrHeight ? { maxWidthOrHeight } : { maxSizeMB: targetCompressedImageFileSizeMb }),
1165
+ useWebWorker,
1166
+ maxIterations: 30,
1167
+ onProgress: (p) => {
1168
+ this.progress = p;
1169
+ this.cdr.detectChanges();
1170
+ }
1171
+ };
1172
+ const compressedFile = await imageCompression(file, options);
1173
+ return compressedFile;
1174
+ }
1175
+ else
1176
+ return file;
1177
+ }), tap(file => {
1178
+ this.control.setValue(file);
1179
+ if (file || this.value) {
1180
+ this.control.markAsTouched();
1181
+ setTimeout(() => {
1182
+ this.cdr.detectChanges();
1183
+ }, 100);
1184
+ }
1185
+ }), map(file => typeof file === 'string' ? null : file), shareReplay(1));
1186
+ this.compressedImageUrlString$ = this.compressedFile$.pipe(switchMap(async (file) => {
1187
+ if (!file)
1188
+ return null;
1189
+ const compressedStringImage = await imageCompression.getDataUrlFromFile(file);
1190
+ return file.type.includes('svg')
1191
+ ? this.domSanitizer.bypassSecurityTrustResourceUrl(compressedStringImage)
1192
+ : compressedStringImage;
1193
+ }), shareReplay(1));
1194
+ this.isUploaded = false;
1195
+ if (this.ngControl != null) {
1196
+ // Setting the value accessor directly (instead of using
1197
+ // the providers) to avoid running into a circular import.
1198
+ ngControl.valueAccessor = this;
1199
+ }
1200
+ }
1201
+ ngOnInit() {
1202
+ super.ngOnInit();
1203
+ this.imageSrcUrl$ = combineLatest([
1204
+ this.compressedImageUrlString$.pipe(startWith(null)),
1205
+ this.control.valueChanges.pipe(startWith(this.value))
1206
+ ]).pipe(map(([compressedImageUrlString, controlUrl]) => {
1207
+ return compressedImageUrlString || typeof controlUrl === 'string' && controlUrl || null;
1208
+ }));
1209
+ this.disabled$ = this.config.disabledCallback
1210
+ ? this.config.disabledCallback(this.group, this.config)
1211
+ : of(false);
1212
+ }
1213
+ filesChanged(files) {
1214
+ if (files && files.length > 0) {
1215
+ const imageFile = files[0];
1216
+ this.control.markAsTouched();
1217
+ this.inputImageFileSubject.next(imageFile);
1218
+ }
1219
+ }
1220
+ clearFileInput() {
1221
+ this.inputImageFileSubject.next(null);
1222
+ this.fileInputRef.nativeElement.value = '';
1223
+ this.control.patchValue(null);
1224
+ this.control.markAsTouched();
1225
+ this.isUploaded = false;
1226
+ }
1227
+ resetToInitialValue(initialValue) {
1228
+ this.inputImageFileSubject.next(initialValue);
1229
+ // this.fileInputRef.nativeElement.value = initialValue
1230
+ this.isUploaded = false;
1231
+ }
1232
+ writeValue(value) { }
1233
+ registerOnChange(fn) {
1234
+ this.onChange = fn;
1235
+ }
1236
+ registerOnTouched(fn) { }
1237
+ }
1238
+ ImageUploadFieldComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: ImageUploadFieldComponent, deps: [{ token: i4$1.NgControl, optional: true, self: true }, { token: i2$3.DomSanitizer }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
1239
+ ImageUploadFieldComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.2.1", type: ImageUploadFieldComponent, selector: "crispr-image-upload-field", viewQueries: [{ propertyName: "fileInputRef", first: true, predicate: ["fileInput"], descendants: true }], usesInheritance: true, ngImport: i0, template: "<crispr-field-container\n [config]=\"config\"\n [group]=\"group\">\n\n <mat-form-field floatLabel=\"always\"\n [color]=\"config.color\"\n [appearance]=\"config.appearance\"\n [formGroup]=\"group\">\n <mat-label>{{config.label}}</mat-label>\n <input [formControlName]=\"config.controlName\" matInput type=\"text\"/>\n <input\n #fileInput\n type=\"file\"\n [accept]=\"config.acceptedTypes\"\n (change)=\"filesChanged($event.target.files)\"/>\n <div class=\"ui-container\">\n\n <div class=\"image-preview\" [style.height]=\"config.imagePreviewHeight\">\n <crispr-selected-file\n *ngIf=\"(progress < 100) && inputImageFile$ | async as file; else dropzoneOrPreview\"\n [color]=\"config.color === 'primary' ? 'accent' : 'primary'\"\n [fileName]=\"'Compressing: ' + file.name\"\n [showProgress]=\"true\"\n [progress]=\"progress\">\n </crispr-selected-file>\n\n <ng-template #dropzoneOrPreview>\n <!-- <img *ngIf=\"(initialUrlString$ | async) as initialUrlString;\" [src]=\"initialUrlString\" alt=\"\"> -->\n <img *ngIf=\"imageSrcUrl$ | async as srcUrl; else noImage\" [src]=\"srcUrl\" alt=\"\">\n <ng-template #noImage>\n <div class=\"drop-container\"\n [crisprFileDropzone]=\"!(disabled$ | async)\"\n (fileDrop)=\"filesChanged($event)\">\n <mat-icon class=\"drop-icon\" inline=\"true\">cloud_upload</mat-icon>\n <h2 class=\"mat-h2\">{{config.dropZoneText}}</h2>\n </div>\n </ng-template>\n\n </ng-template>\n </div>\n\n\n\n <!-- </ng-template> -->\n <div class=\"button-container\" *ngIf=\"true\">\n\n <button\n mat-button\n (click)=\"clearFileInput()\"\n type=\"button\"\n [disabled]=\"(disabled$ | async)\"\n aria-label=\"Remove Selected File(s)\">\n <mat-icon>delete</mat-icon>\n {{config.clearFilesButtonText}}\n </button>\n\n <button\n *ngIf=\"value\"\n mat-button\n (click)=\"resetToInitialValue(value)\"\n type=\"button\"\n [disabled]=\"(disabled$ | async)\"\n aria-label=\"Remove Selected File(s)\">\n <mat-icon>replay</mat-icon>\n {{config.resetFilesButtonText}}\n </button>\n\n <button\n mat-button\n type=\"button\"\n color=\"primary\"\n [disabled]=\"(disabled$ | async)\"\n (click)=\"fileInput.click()\"\n [attr.aria-label]=\"config.controlName\">\n <mat-icon>\n camera\n </mat-icon>\n SELECT\n </button>\n </div>\n </div>\n\n </mat-form-field>\n\n</crispr-field-container>\n", styles: [":host ::ng-deep .mat-form-field .mat-form-field-infix{padding-top:0}:host ::ng-deep .mat-form-field .mat-button-wrapper{display:flex;flex-direction:column;align-items:center;padding-top:8px}:host .ui-container{display:flex;flex-direction:column}:host .ui-container .image-preview{display:flex;flex-direction:column;align-content:space-between;justify-content:center;align-items:center;margin:8px 0;flex-grow:1}:host .ui-container .image-preview crispr-selected-file{width:100%}:host .ui-container .image-preview .drop-container{display:flex;flex-direction:column;align-items:center;border:3px dashed gray;height:100%;width:100%;align-content:center;justify-content:center;border-radius:8px}:host .ui-container .image-preview .drop-container .drop-icon{height:32px;width:32px;font-size:36px}:host .ui-container .image-preview .drop-container .mat-h2{margin:0}:host .ui-container .image-preview img{height:inherit;max-width:100%}:host .ui-container .button-container{display:flex;flex-direction:var(--image-upload-button-container-direction);justify-content:flex-end}:host .ui-container .button-container button{margin-left:8px}:host input{position:absolute;max-height:0;visibility:hidden}\n"], components: [{ type: FieldContainerComponent, selector: "crispr-field-container", inputs: ["config", "group", "inlineField"] }, { type: i2$1.MatFormField, selector: "mat-form-field", inputs: ["color", "appearance", "hideRequiredMarker", "hintLabel", "floatLabel"], exportAs: ["matFormField"] }, { type: SelectedFileComponent, selector: "crispr-selected-file", inputs: ["fileName", "progress", "showProgress", "color"] }, { type: i4.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { type: i1.MatButton, selector: "button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }], directives: [{ type: i4$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i4$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i5.ControlErrorContainerDirective, selector: "[controlErrorContainer], [formGroup]" }, { type: i2$1.MatLabel, selector: "mat-label" }, { type: i7.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly"], exportAs: ["matInput"] }, { type: i4$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i4$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i4$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { type: i5.ControlErrorsDirective, selector: "[formControl], [formControlName]" }, { type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: FileDropzoneDirective, selector: "[crisprFileDropzone]", inputs: ["crisprFileDropzone"], outputs: ["fileDrop"] }], pipes: { "async": i2.AsyncPipe }, changeDetection: i0.ChangeDetectionStrategy.OnPush, preserveWhitespaces: true });
1240
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: ImageUploadFieldComponent, decorators: [{
1241
+ type: Component,
1242
+ args: [{ selector: 'crispr-image-upload-field', changeDetection: ChangeDetectionStrategy.OnPush, template: "<crispr-field-container\n [config]=\"config\"\n [group]=\"group\">\n\n <mat-form-field floatLabel=\"always\"\n [color]=\"config.color\"\n [appearance]=\"config.appearance\"\n [formGroup]=\"group\">\n <mat-label>{{config.label}}</mat-label>\n <input [formControlName]=\"config.controlName\" matInput type=\"text\"/>\n <input\n #fileInput\n type=\"file\"\n [accept]=\"config.acceptedTypes\"\n (change)=\"filesChanged($event.target.files)\"/>\n <div class=\"ui-container\">\n\n <div class=\"image-preview\" [style.height]=\"config.imagePreviewHeight\">\n <crispr-selected-file\n *ngIf=\"(progress < 100) && inputImageFile$ | async as file; else dropzoneOrPreview\"\n [color]=\"config.color === 'primary' ? 'accent' : 'primary'\"\n [fileName]=\"'Compressing: ' + file.name\"\n [showProgress]=\"true\"\n [progress]=\"progress\">\n </crispr-selected-file>\n\n <ng-template #dropzoneOrPreview>\n <!-- <img *ngIf=\"(initialUrlString$ | async) as initialUrlString;\" [src]=\"initialUrlString\" alt=\"\"> -->\n <img *ngIf=\"imageSrcUrl$ | async as srcUrl; else noImage\" [src]=\"srcUrl\" alt=\"\">\n <ng-template #noImage>\n <div class=\"drop-container\"\n [crisprFileDropzone]=\"!(disabled$ | async)\"\n (fileDrop)=\"filesChanged($event)\">\n <mat-icon class=\"drop-icon\" inline=\"true\">cloud_upload</mat-icon>\n <h2 class=\"mat-h2\">{{config.dropZoneText}}</h2>\n </div>\n </ng-template>\n\n </ng-template>\n </div>\n\n\n\n <!-- </ng-template> -->\n <div class=\"button-container\" *ngIf=\"true\">\n\n <button\n mat-button\n (click)=\"clearFileInput()\"\n type=\"button\"\n [disabled]=\"(disabled$ | async)\"\n aria-label=\"Remove Selected File(s)\">\n <mat-icon>delete</mat-icon>\n {{config.clearFilesButtonText}}\n </button>\n\n <button\n *ngIf=\"value\"\n mat-button\n (click)=\"resetToInitialValue(value)\"\n type=\"button\"\n [disabled]=\"(disabled$ | async)\"\n aria-label=\"Remove Selected File(s)\">\n <mat-icon>replay</mat-icon>\n {{config.resetFilesButtonText}}\n </button>\n\n <button\n mat-button\n type=\"button\"\n color=\"primary\"\n [disabled]=\"(disabled$ | async)\"\n (click)=\"fileInput.click()\"\n [attr.aria-label]=\"config.controlName\">\n <mat-icon>\n camera\n </mat-icon>\n SELECT\n </button>\n </div>\n </div>\n\n </mat-form-field>\n\n</crispr-field-container>\n", styles: [":host ::ng-deep .mat-form-field .mat-form-field-infix{padding-top:0}:host ::ng-deep .mat-form-field .mat-button-wrapper{display:flex;flex-direction:column;align-items:center;padding-top:8px}:host .ui-container{display:flex;flex-direction:column}:host .ui-container .image-preview{display:flex;flex-direction:column;align-content:space-between;justify-content:center;align-items:center;margin:8px 0;flex-grow:1}:host .ui-container .image-preview crispr-selected-file{width:100%}:host .ui-container .image-preview .drop-container{display:flex;flex-direction:column;align-items:center;border:3px dashed gray;height:100%;width:100%;align-content:center;justify-content:center;border-radius:8px}:host .ui-container .image-preview .drop-container .drop-icon{height:32px;width:32px;font-size:36px}:host .ui-container .image-preview .drop-container .mat-h2{margin:0}:host .ui-container .image-preview img{height:inherit;max-width:100%}:host .ui-container .button-container{display:flex;flex-direction:var(--image-upload-button-container-direction);justify-content:flex-end}:host .ui-container .button-container button{margin-left:8px}:host input{position:absolute;max-height:0;visibility:hidden}\n"] }]
1243
+ }], ctorParameters: function () { return [{ type: i4$1.NgControl, decorators: [{
1244
+ type: Optional
1245
+ }, {
1246
+ type: Self
1247
+ }] }, { type: i2$3.DomSanitizer }, { type: i0.ChangeDetectorRef }]; }, propDecorators: { fileInputRef: [{
1248
+ type: ViewChild,
1249
+ args: ['fileInput']
1250
+ }] } });
1251
+ class ImageUploadFieldModule {
1252
+ }
1253
+ ImageUploadFieldModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: ImageUploadFieldModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
1254
+ ImageUploadFieldModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: ImageUploadFieldModule, declarations: [ImageUploadFieldComponent], imports: [CommonModule,
1255
+ FieldContainerModule,
1256
+ ReactiveFormsModule,
1257
+ MatIconModule,
1258
+ MatButtonModule,
1259
+ MatFormFieldModule,
1260
+ MatInputModule,
1261
+ SelectedFileModule,
1262
+ FileUploadFieldModule,
1263
+ FormValidationHandlerModule], exports: [ImageUploadFieldComponent] });
1264
+ ImageUploadFieldModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: ImageUploadFieldModule, imports: [[
1265
+ CommonModule,
1266
+ FieldContainerModule,
1267
+ ReactiveFormsModule,
1268
+ MatIconModule,
1269
+ MatButtonModule,
1270
+ MatFormFieldModule,
1271
+ MatInputModule,
1272
+ SelectedFileModule,
1273
+ FileUploadFieldModule,
1274
+ FormValidationHandlerModule
1275
+ ]] });
1276
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: ImageUploadFieldModule, decorators: [{
1277
+ type: NgModule,
1278
+ args: [{
1279
+ imports: [
1280
+ CommonModule,
1281
+ FieldContainerModule,
1282
+ ReactiveFormsModule,
1283
+ MatIconModule,
1284
+ MatButtonModule,
1285
+ MatFormFieldModule,
1286
+ MatInputModule,
1287
+ SelectedFileModule,
1288
+ FileUploadFieldModule,
1289
+ FormValidationHandlerModule
1290
+ ],
1291
+ exports: [
1292
+ ImageUploadFieldComponent
1293
+ ],
1294
+ declarations: [
1295
+ ImageUploadFieldComponent
1296
+ ]
1297
+ }]
1298
+ }] });
1299
+ function maxFileSizeValidator(maxFileSize) {
1300
+ return (control) => {
1301
+ const controlValue = control.value;
1302
+ if (!(controlValue instanceof Blob))
1303
+ return null;
1304
+ const actualFileSize = +convertBytesToMb(controlValue.size).toPrecision(3);
1305
+ if (maxFileSize > actualFileSize)
1306
+ return null;
1307
+ control.setErrors({ maxFileSize: { maxFileSize, actualFileSize } });
1308
+ return { maxFileSize: { maxFileSize, actualFileSize } };
1309
+ };
1310
+ }
1311
+
1312
+ // TODO: Should we import UI library?
1313
+ // Will the tree shaker shake the unused modules?
1314
+ const MAT_DESIGN_MODULES = [
1315
+ MatIconModule,
1316
+ MatAutocompleteModule,
1317
+ MatDatepickerModule,
1318
+ MatInputModule,
1319
+ MatRadioModule,
1320
+ MatSelectModule,
1321
+ MatCheckboxModule,
1322
+ MatChipsModule,
1323
+ MatSliderModule,
1324
+ MatSlideToggleModule,
1325
+ MatButtonModule,
1326
+ MatButtonToggleModule,
1327
+ MatChipsModule,
1328
+ MatTooltipModule,
1329
+ MatFormFieldModule,
1330
+ MatMomentDateModule,
1331
+ MatDividerModule,
1332
+ MatProgressBarModule,
1333
+ PortalModule
1334
+ ];
1335
+ const CRISPR_FIELDS = [
1336
+ InputFieldComponent,
1337
+ SelectFieldComponent,
1338
+ RadioFieldComponent,
1339
+ AutocompleteFieldComponent,
1340
+ AutocompleteChiplistFieldComponent,
1341
+ CheckboxFieldComponent,
1342
+ TextareaFieldComponent,
1343
+ DatepickerFieldComponent,
1344
+ SliderFieldComponent,
1345
+ ButtonComponent,
1346
+ DividerComponent,
1347
+ UnitConversionFieldComponent,
1348
+ OptionComponent,
1349
+ ];
1350
+ class MaterialModule {
1351
+ }
1352
+ MaterialModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: MaterialModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
1353
+ MaterialModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: MaterialModule, declarations: [InputFieldComponent,
1354
+ SelectFieldComponent,
1355
+ RadioFieldComponent,
1356
+ AutocompleteFieldComponent,
1357
+ AutocompleteChiplistFieldComponent,
1358
+ CheckboxFieldComponent,
1359
+ TextareaFieldComponent,
1360
+ DatepickerFieldComponent,
1361
+ SliderFieldComponent,
1362
+ ButtonComponent,
1363
+ DividerComponent,
1364
+ UnitConversionFieldComponent,
1365
+ OptionComponent], imports: [CommonModule,
1366
+ ReactiveFormsModule,
1367
+ FormValidationHandlerModule,
1368
+ InfoModule,
1369
+ FileUploadFieldModule,
1370
+ HeadingModule,
1371
+ FieldContainerModule, MatIconModule,
1372
+ MatAutocompleteModule,
1373
+ MatDatepickerModule,
1374
+ MatInputModule,
1375
+ MatRadioModule,
1376
+ MatSelectModule,
1377
+ MatCheckboxModule,
1378
+ MatChipsModule,
1379
+ MatSliderModule,
1380
+ MatSlideToggleModule,
1381
+ MatButtonModule,
1382
+ MatButtonToggleModule,
1383
+ MatChipsModule,
1384
+ MatTooltipModule,
1385
+ MatFormFieldModule,
1386
+ MatMomentDateModule,
1387
+ MatDividerModule,
1388
+ MatProgressBarModule,
1389
+ PortalModule], exports: [MatIconModule,
1390
+ MatAutocompleteModule,
1391
+ MatDatepickerModule,
1392
+ MatInputModule,
1393
+ MatRadioModule,
1394
+ MatSelectModule,
1395
+ MatCheckboxModule,
1396
+ MatChipsModule,
1397
+ MatSliderModule,
1398
+ MatSlideToggleModule,
1399
+ MatButtonModule,
1400
+ MatButtonToggleModule,
1401
+ MatChipsModule,
1402
+ MatTooltipModule,
1403
+ MatFormFieldModule,
1404
+ MatMomentDateModule,
1405
+ MatDividerModule,
1406
+ MatProgressBarModule,
1407
+ PortalModule, InputFieldComponent,
1408
+ SelectFieldComponent,
1409
+ RadioFieldComponent,
1410
+ AutocompleteFieldComponent,
1411
+ AutocompleteChiplistFieldComponent,
1412
+ CheckboxFieldComponent,
1413
+ TextareaFieldComponent,
1414
+ DatepickerFieldComponent,
1415
+ SliderFieldComponent,
1416
+ ButtonComponent,
1417
+ DividerComponent,
1418
+ UnitConversionFieldComponent,
1419
+ OptionComponent] });
1420
+ MaterialModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: MaterialModule, imports: [[
1421
+ CommonModule,
1422
+ ReactiveFormsModule,
1423
+ FormValidationHandlerModule,
1424
+ InfoModule,
1425
+ FileUploadFieldModule,
1426
+ HeadingModule,
1427
+ FieldContainerModule,
1428
+ ...MAT_DESIGN_MODULES,
1429
+ ], MatIconModule,
1430
+ MatAutocompleteModule,
1431
+ MatDatepickerModule,
1432
+ MatInputModule,
1433
+ MatRadioModule,
1434
+ MatSelectModule,
1435
+ MatCheckboxModule,
1436
+ MatChipsModule,
1437
+ MatSliderModule,
1438
+ MatSlideToggleModule,
1439
+ MatButtonModule,
1440
+ MatButtonToggleModule,
1441
+ MatChipsModule,
1442
+ MatTooltipModule,
1443
+ MatFormFieldModule,
1444
+ MatMomentDateModule,
1445
+ MatDividerModule,
1446
+ MatProgressBarModule,
1447
+ PortalModule] });
1448
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: MaterialModule, decorators: [{
1449
+ type: NgModule,
1450
+ args: [{
1451
+ imports: [
1452
+ CommonModule,
1453
+ ReactiveFormsModule,
1454
+ FormValidationHandlerModule,
1455
+ InfoModule,
1456
+ FileUploadFieldModule,
1457
+ HeadingModule,
1458
+ FieldContainerModule,
1459
+ ...MAT_DESIGN_MODULES,
1460
+ ],
1461
+ exports: [
1462
+ ...MAT_DESIGN_MODULES,
1463
+ ...CRISPR_FIELDS
1464
+ ],
1465
+ declarations: [
1466
+ ...CRISPR_FIELDS,
1467
+ ]
1468
+ }]
1469
+ }] });
1470
+
1471
+ var index$2 = /*#__PURE__*/Object.freeze({
1472
+ __proto__: null,
1473
+ InputFieldComponent: InputFieldComponent,
1474
+ SelectFieldComponent: SelectFieldComponent,
1475
+ AutocompleteFieldComponent: AutocompleteFieldComponent,
1476
+ AutocompleteChiplistFieldComponent: AutocompleteChiplistFieldComponent,
1477
+ CheckboxFieldComponent: CheckboxFieldComponent,
1478
+ TextareaFieldComponent: TextareaFieldComponent,
1479
+ SliderFieldComponent: SliderFieldComponent,
1480
+ ButtonComponent: ButtonComponent,
1481
+ DatepickerFieldComponent: DatepickerFieldComponent,
1482
+ HeadingComponent: HeadingComponent,
1483
+ HeadingModule: HeadingModule,
1484
+ DividerComponent: DividerComponent,
1485
+ RadioFieldComponent: RadioFieldComponent,
1486
+ UnitConversionFieldComponent: UnitConversionFieldComponent,
1487
+ ImageUploadFieldComponent: ImageUploadFieldComponent,
1488
+ ImageUploadFieldModule: ImageUploadFieldModule,
1489
+ maxFileSizeValidator: maxFileSizeValidator,
1490
+ FileDropzoneDirective: FileDropzoneDirective,
1491
+ FileUploadFieldComponent: FileUploadFieldComponent,
1492
+ FileUploadFieldModule: FileUploadFieldModule,
1493
+ MaterialModule: MaterialModule,
1494
+ OptionComponent: OptionComponent
1495
+ });
1496
+
1497
+ const FIELD_COMPONENTS = {
1498
+ groupList: Promise.resolve().then(function () { return index$1; }).then(({ FormGroupListComponent }) => FormGroupListComponent),
1499
+ subGroup: Promise.resolve().then(function () { return index; }).then(({ SubGroupComponent }) => SubGroupComponent),
1500
+ button: Promise.resolve().then(function () { return index$2; }).then(({ ButtonComponent }) => ButtonComponent),
1501
+ input: Promise.resolve().then(function () { return index$2; }).then(({ InputFieldComponent }) => InputFieldComponent),
1502
+ select: Promise.resolve().then(function () { return index$2; }).then(({ SelectFieldComponent }) => SelectFieldComponent),
1503
+ radio: Promise.resolve().then(function () { return index$2; }).then(({ RadioFieldComponent }) => RadioFieldComponent),
1504
+ autocomplete: Promise.resolve().then(function () { return index$2; }).then(({ AutocompleteFieldComponent }) => AutocompleteFieldComponent),
1505
+ autocompleteChiplist: Promise.resolve().then(function () { return index$2; }).then(({ AutocompleteChiplistFieldComponent }) => AutocompleteChiplistFieldComponent),
1506
+ textarea: Promise.resolve().then(function () { return index$2; }).then(({ TextareaFieldComponent }) => TextareaFieldComponent),
1507
+ checkbox: Promise.resolve().then(function () { return index$2; }).then(({ CheckboxFieldComponent }) => CheckboxFieldComponent),
1508
+ slider: Promise.resolve().then(function () { return index$2; }).then(({ SliderFieldComponent }) => SliderFieldComponent),
1509
+ datepicker: Promise.resolve().then(function () { return index$2; }).then(({ DatepickerFieldComponent }) => DatepickerFieldComponent),
1510
+ fileUpload: Promise.resolve().then(function () { return index$2; }).then(({ FileUploadFieldComponent }) => FileUploadFieldComponent),
1511
+ imageUpload: Promise.resolve().then(function () { return index$2; }).then(({ ImageUploadFieldComponent }) => ImageUploadFieldComponent),
1512
+ heading: Promise.resolve().then(function () { return index$2; }).then(({ HeadingComponent }) => HeadingComponent),
1513
+ divider: Promise.resolve().then(function () { return index$2; }).then(({ DividerComponent }) => DividerComponent),
1514
+ unitConversion: Promise.resolve().then(function () { return index$2; }).then(({ UnitConversionFieldComponent }) => UnitConversionFieldComponent)
1515
+ };
1516
+ function isControlComponent(component) {
1517
+ return isControlConfig(component.config) || component.config.controlType === ControlType.BUTTON;
1518
+ }
1519
+
1520
+ class CrisprFieldDirective {
1521
+ constructor(container, renderer, cdr) {
1522
+ this.container = container;
1523
+ this.renderer = renderer;
1524
+ this.cdr = cdr;
1525
+ }
1526
+ async ngOnInit() {
1527
+ /**
1528
+ * create component and set values from config on its instance
1529
+ */
1530
+ const component = this.config.component || await FIELD_COMPONENTS[this.config.controlType];
1531
+ const componentRef = this.container.createComponent(component);
1532
+ this.component = componentRef.instance;
1533
+ this.component.config = this.config;
1534
+ if (isControlComponent(this.component)) {
1535
+ this.component.group = this.group;
1536
+ if ('value' in this.component) {
1537
+ this.component.value = this.value;
1538
+ }
1539
+ }
1540
+ this.cdr.detectChanges();
1541
+ // adds any config classes to the dynamically generated component
1542
+ // doing this here keeps us from having to extend a base component into each field component individually
1543
+ if (!this.config.classes)
1544
+ return;
1545
+ this.config.classes.forEach((klass) => {
1546
+ // check for passing multiple classes in one array element
1547
+ if (klass.includes(' ')) {
1548
+ throw Error(`Improperly formatted class. '${klass}' cannot contain spaces.`);
1549
+ }
1550
+ else {
1551
+ this.renderer.addClass(componentRef.location.nativeElement, klass);
1552
+ }
1553
+ });
1554
+ }
1555
+ }
1556
+ CrisprFieldDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: CrisprFieldDirective, deps: [{ token: i0.ViewContainerRef }, { token: i0.Renderer2 }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Directive });
1557
+ CrisprFieldDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "13.2.1", type: CrisprFieldDirective, selector: "[crisprField]", inputs: { config: "config", group: "group", value: "value" }, ngImport: i0 });
1558
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: CrisprFieldDirective, decorators: [{
1559
+ type: Directive,
1560
+ args: [{
1561
+ selector: '[crisprField]'
1562
+ }]
1563
+ }], ctorParameters: function () { return [{ type: i0.ViewContainerRef }, { type: i0.Renderer2 }, { type: i0.ChangeDetectorRef }]; }, propDecorators: { config: [{
1564
+ type: Input
1565
+ }], group: [{
1566
+ type: Input
1567
+ }], value: [{
1568
+ type: Input
1569
+ }] } });
1570
+ class CrisprFieldModule {
1571
+ }
1572
+ CrisprFieldModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: CrisprFieldModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
1573
+ CrisprFieldModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: CrisprFieldModule, declarations: [CrisprFieldDirective], imports: [CommonModule], exports: [CrisprFieldDirective] });
1574
+ CrisprFieldModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: CrisprFieldModule, imports: [[
1575
+ CommonModule,
1576
+ ]] });
1577
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: CrisprFieldModule, decorators: [{
1578
+ type: NgModule,
1579
+ args: [{
1580
+ imports: [
1581
+ CommonModule,
1582
+ ],
1583
+ exports: [
1584
+ CrisprFieldDirective
1585
+ ],
1586
+ declarations: [
1587
+ CrisprFieldDirective
1588
+ ]
1589
+ }]
1590
+ }] });
1591
+
1592
+ class InitialControlValuePipe {
1593
+ // TODO: does changing any to unknown break anything?
1594
+ transform(initialFormValue, fieldConfig) {
1595
+ return (initialFormValue && isControlConfig(fieldConfig))
1596
+ ? initialFormValue[fieldConfig.controlName] || null
1597
+ : null;
1598
+ }
1599
+ }
1600
+ InitialControlValuePipe.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: InitialControlValuePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
1601
+ InitialControlValuePipe.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: InitialControlValuePipe, name: "initialControlValue" });
1602
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: InitialControlValuePipe, decorators: [{
1603
+ type: Pipe,
1604
+ args: [{
1605
+ name: 'initialControlValue'
1606
+ }]
1607
+ }] });
1608
+
1609
+ class CrisprFormComponent {
1610
+ constructor() {
1611
+ this.form = new FormGroup({});
1612
+ this.value = null;
1613
+ this.submitted = new EventEmitter();
1614
+ // proxy value and status change events through to consuming component
1615
+ this.valueChanges = this.form.valueChanges;
1616
+ this.statusChanges = this.form.statusChanges;
1617
+ this.subs = [];
1618
+ }
1619
+ ngOnInit() {
1620
+ // build out the form, note that we pass in the form as the third argument and the function modifies it
1621
+ buildFormGroupFromConfig(this.config, this.value, this.form);
1622
+ }
1623
+ handleSubmit() {
1624
+ this.form.markAllAsTouched();
1625
+ this.submitted.emit(this.form);
1626
+ }
1627
+ triggerSubmit() {
1628
+ this.submitTrigger.nativeElement.click();
1629
+ }
1630
+ }
1631
+ CrisprFormComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: CrisprFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1632
+ CrisprFormComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.2.1", type: CrisprFormComponent, selector: "crispr-form", inputs: { config: "config", form: "form", value: "value" }, outputs: { submitted: "submitted", valueChanges: "valueChanges", statusChanges: "statusChanges" }, viewQueries: [{ propertyName: "submitTrigger", first: true, predicate: ["submitTrigger"], descendants: true }], ngImport: i0, template: "<form\n class=\"crispr-form\"\n [ngClass]=\"config.classes\"\n [formGroup]=\"form\"\n (ngSubmit)=\"handleSubmit()\"\n [autocomplete]=\"config.autocomplete || 'off'\"\n [errorDictionary]=\"config.errorDictionary\"\n #ngFormElement=\"ngForm\">\n\n <ng-container\n *ngFor=\"let field of config.fields;\"\n crisprField\n [value]=\"value | initialControlValue : field\"\n [config]=\"field\"\n [group]=\"form\">\n </ng-container>\n <!-- Hidden button, programmatically clicked when crispr form triggerSubmit function called.\n Uses a hidden button with type=\"submit\" because it will trigger both native form submit event\n (which the error handler has to listen for) and ngSubmit event -->\n <button #submitTrigger class=\"submit-trigger\" type=\"submit\">\n </button>\n</form>\n", styles: [".submit-trigger{display:none}\n"], directives: [{ type: i4$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { type: i4$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i5.ControlErrorsFormDirective, selector: "form", inputs: ["errorDictionary"] }, { type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { type: i4$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i5.ControlErrorContainerDirective, selector: "[controlErrorContainer], [formGroup]" }, { type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: CrisprFieldDirective, selector: "[crisprField]", inputs: ["config", "group", "value"] }], pipes: { "initialControlValue": InitialControlValuePipe }, changeDetection: i0.ChangeDetectionStrategy.OnPush, preserveWhitespaces: true });
1633
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: CrisprFormComponent, decorators: [{
1634
+ type: Component,
1635
+ args: [{ selector: 'crispr-form', changeDetection: ChangeDetectionStrategy.OnPush, template: "<form\n class=\"crispr-form\"\n [ngClass]=\"config.classes\"\n [formGroup]=\"form\"\n (ngSubmit)=\"handleSubmit()\"\n [autocomplete]=\"config.autocomplete || 'off'\"\n [errorDictionary]=\"config.errorDictionary\"\n #ngFormElement=\"ngForm\">\n\n <ng-container\n *ngFor=\"let field of config.fields;\"\n crisprField\n [value]=\"value | initialControlValue : field\"\n [config]=\"field\"\n [group]=\"form\">\n </ng-container>\n <!-- Hidden button, programmatically clicked when crispr form triggerSubmit function called.\n Uses a hidden button with type=\"submit\" because it will trigger both native form submit event\n (which the error handler has to listen for) and ngSubmit event -->\n <button #submitTrigger class=\"submit-trigger\" type=\"submit\">\n </button>\n</form>\n", styles: [".submit-trigger{display:none}\n"] }]
1636
+ }], propDecorators: { config: [{
1637
+ type: Input
1638
+ }], form: [{
1639
+ type: Input
1640
+ }], value: [{
1641
+ type: Input
1642
+ }], submitted: [{
1643
+ type: Output
1644
+ }], valueChanges: [{
1645
+ type: Output
1646
+ }], statusChanges: [{
1647
+ type: Output
1648
+ }], submitTrigger: [{
1649
+ type: ViewChild,
1650
+ args: ['submitTrigger']
1651
+ }] } });
1652
+
1653
+ const defaultConfig = {
1654
+ addButtonLabel: 'ADD ITEM',
1655
+ minListLength: 1,
1656
+ };
1657
+ const FormGroupListMixin = crisprControlMixin(CrisprFieldComponent);
1658
+ class FormGroupListComponent extends FormGroupListMixin {
1659
+ constructor() {
1660
+ super(...arguments);
1661
+ this.defaultConfig = defaultConfig;
1662
+ }
1663
+ ngOnInit() {
1664
+ super.ngOnInit();
1665
+ // TODO: this is required to ngFor of controls in template, must be a better way
1666
+ this.formArray = this.control;
1667
+ }
1668
+ setControlValue(values) {
1669
+ if (this.control) {
1670
+ if (values?.length > 0) {
1671
+ values.forEach(value => this.addGroup(value));
1672
+ }
1673
+ else if (this.config.displayInitialItem) {
1674
+ this.addGroup();
1675
+ }
1676
+ }
1677
+ }
1678
+ addGroup(value = null) {
1679
+ this.control.push(createControlForType(this.config.itemConfig, value));
1680
+ }
1681
+ deleteGroup(index) {
1682
+ this.control.removeAt(index);
1683
+ }
1684
+ }
1685
+ FormGroupListComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: FormGroupListComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
1686
+ FormGroupListComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.2.1", type: FormGroupListComponent, selector: "crispr-form-group-list", usesInheritance: true, ngImport: i0, template: "\n<crispr-field-container\n [config]=\"config\"\n [group]=\"group\"\n [formGroup]=\"group\">\n\n <div [formArrayName]=\"config.controlName\">\n <!-- TODO: add sortBy function -->\n <div *ngFor=\"let control of formArray?.controls; let i = index;\">\n <!-- TODO: use content projection to allow custom item label component -->\n <div class=\"item-header\">\n <span class=\"mat-h2\" *ngIf=\"config.itemLabelBuilder\"> {{ config.itemLabelBuilder(i) }} </span>\n <button\n mat-icon-button\n *ngIf=\"i + 1 > config.minListLength\">\n <mat-icon (click)=\"deleteGroup(i)\">delete</mat-icon>\n </button>\n </div>\n <div\n [formGroupName]=\"i\">\n <ng-container\n *ngFor=\"let field of config.itemConfig.fields;\"\n crisprField\n [config]=\"field\"\n [value]=\"value && value[i] | initialControlValue : field\"\n [group]=\"control\">\n </ng-container>\n </div>\n </div>\n </div>\n <div class=\"group-footer\">\n <button\n type=\"button\"\n class=\"add\"\n mat-raised-button\n [color]=\"config.addButtonColor\"\n (click)=\"addGroup()\">\n {{config.addItemLabel || config.addButtonLabel}}\n </button>\n </div>\n\n</crispr-field-container>\n", styles: [".item-header{display:flex;justify-content:space-between}.group-footer{display:flex;justify-content:flex-end}.group-footer button.add{margin-bottom:16px}\n"], components: [{ type: FieldContainerComponent, selector: "crispr-field-container", inputs: ["config", "group", "inlineField"] }, { type: i1.MatButton, selector: "button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }, { type: i4.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }], directives: [{ type: i4$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i4$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i5.ControlErrorContainerDirective, selector: "[controlErrorContainer], [formGroup]" }, { type: i4$1.FormArrayName, selector: "[formArrayName]", inputs: ["formArrayName"] }, { type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i4$1.FormGroupName, selector: "[formGroupName]", inputs: ["formGroupName"] }, { type: CrisprFieldDirective, selector: "[crisprField]", inputs: ["config", "group", "value"] }], pipes: { "initialControlValue": InitialControlValuePipe }, changeDetection: i0.ChangeDetectionStrategy.OnPush, preserveWhitespaces: true });
1687
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: FormGroupListComponent, decorators: [{
1688
+ type: Component,
1689
+ args: [{ selector: 'crispr-form-group-list', changeDetection: ChangeDetectionStrategy.OnPush, template: "\n<crispr-field-container\n [config]=\"config\"\n [group]=\"group\"\n [formGroup]=\"group\">\n\n <div [formArrayName]=\"config.controlName\">\n <!-- TODO: add sortBy function -->\n <div *ngFor=\"let control of formArray?.controls; let i = index;\">\n <!-- TODO: use content projection to allow custom item label component -->\n <div class=\"item-header\">\n <span class=\"mat-h2\" *ngIf=\"config.itemLabelBuilder\"> {{ config.itemLabelBuilder(i) }} </span>\n <button\n mat-icon-button\n *ngIf=\"i + 1 > config.minListLength\">\n <mat-icon (click)=\"deleteGroup(i)\">delete</mat-icon>\n </button>\n </div>\n <div\n [formGroupName]=\"i\">\n <ng-container\n *ngFor=\"let field of config.itemConfig.fields;\"\n crisprField\n [config]=\"field\"\n [value]=\"value && value[i] | initialControlValue : field\"\n [group]=\"control\">\n </ng-container>\n </div>\n </div>\n </div>\n <div class=\"group-footer\">\n <button\n type=\"button\"\n class=\"add\"\n mat-raised-button\n [color]=\"config.addButtonColor\"\n (click)=\"addGroup()\">\n {{config.addItemLabel || config.addButtonLabel}}\n </button>\n </div>\n\n</crispr-field-container>\n", styles: [".item-header{display:flex;justify-content:space-between}.group-footer{display:flex;justify-content:flex-end}.group-footer button.add{margin-bottom:16px}\n"] }]
1690
+ }] });
1691
+
1692
+ class CrisprPipesModule {
1693
+ }
1694
+ CrisprPipesModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: CrisprPipesModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
1695
+ CrisprPipesModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: CrisprPipesModule, declarations: [InitialControlValuePipe], imports: [CommonModule], exports: [InitialControlValuePipe] });
1696
+ CrisprPipesModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: CrisprPipesModule, imports: [[
1697
+ CommonModule
1698
+ ]] });
1699
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: CrisprPipesModule, decorators: [{
1700
+ type: NgModule,
1701
+ args: [{
1702
+ imports: [
1703
+ CommonModule
1704
+ ],
1705
+ exports: [
1706
+ InitialControlValuePipe
1707
+ ],
1708
+ declarations: [
1709
+ InitialControlValuePipe
1710
+ ]
1711
+ }]
1712
+ }] });
1713
+
1714
+ class FormGroupListModule {
1715
+ }
1716
+ FormGroupListModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: FormGroupListModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
1717
+ FormGroupListModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: FormGroupListModule, declarations: [FormGroupListComponent], imports: [CommonModule,
1718
+ MatButtonModule,
1719
+ MatIconModule,
1720
+ FieldContainerModule,
1721
+ ReactiveFormsModule,
1722
+ CrisprFieldModule,
1723
+ CrisprPipesModule,
1724
+ FormValidationHandlerModule], exports: [FormGroupListComponent] });
1725
+ FormGroupListModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: FormGroupListModule, imports: [[
1726
+ CommonModule,
1727
+ MatButtonModule,
1728
+ MatIconModule,
1729
+ FieldContainerModule,
1730
+ ReactiveFormsModule,
1731
+ CrisprFieldModule,
1732
+ CrisprPipesModule,
1733
+ FormValidationHandlerModule
1734
+ ]] });
1735
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: FormGroupListModule, decorators: [{
1736
+ type: NgModule,
1737
+ args: [{
1738
+ imports: [
1739
+ CommonModule,
1740
+ MatButtonModule,
1741
+ MatIconModule,
1742
+ FieldContainerModule,
1743
+ ReactiveFormsModule,
1744
+ CrisprFieldModule,
1745
+ CrisprPipesModule,
1746
+ FormValidationHandlerModule
1747
+ ],
1748
+ exports: [
1749
+ FormGroupListComponent
1750
+ ],
1751
+ declarations: [
1752
+ FormGroupListComponent
1753
+ ]
1754
+ }]
1755
+ }] });
1756
+
1757
+ var index$1 = /*#__PURE__*/Object.freeze({
1758
+ __proto__: null,
1759
+ FormGroupListComponent: FormGroupListComponent,
1760
+ FormGroupListModule: FormGroupListModule
1761
+ });
1762
+
1763
+ const FormGroupMixin = crisprControlMixin(CrisprFieldComponent);
1764
+ class SubGroupComponent extends FormGroupMixin {
1765
+ ngOnInit() {
1766
+ super.ngOnInit();
1767
+ }
1768
+ }
1769
+ SubGroupComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: SubGroupComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
1770
+ SubGroupComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.2.1", type: SubGroupComponent, selector: "crispr-sub-group", usesInheritance: true, ngImport: i0, template: "<crispr-field-container\n [config]=\"config\"\n [group]=\"group\">\n <ng-container\n *ngFor=\"let fieldConfig of config.fields;\"\n crisprField\n [value]=\"value | initialControlValue : fieldConfig\"\n [config]=\"fieldConfig\"\n [group]=\"control\">\n </ng-container>\n</crispr-field-container>\n\n", styles: [""], components: [{ type: FieldContainerComponent, selector: "crispr-field-container", inputs: ["config", "group", "inlineField"] }], directives: [{ type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: CrisprFieldDirective, selector: "[crisprField]", inputs: ["config", "group", "value"] }], pipes: { "initialControlValue": InitialControlValuePipe }, changeDetection: i0.ChangeDetectionStrategy.OnPush, preserveWhitespaces: true });
1771
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: SubGroupComponent, decorators: [{
1772
+ type: Component,
1773
+ args: [{ selector: 'crispr-sub-group', changeDetection: ChangeDetectionStrategy.OnPush, template: "<crispr-field-container\n [config]=\"config\"\n [group]=\"group\">\n <ng-container\n *ngFor=\"let fieldConfig of config.fields;\"\n crisprField\n [value]=\"value | initialControlValue : fieldConfig\"\n [config]=\"fieldConfig\"\n [group]=\"control\">\n </ng-container>\n</crispr-field-container>\n\n", styles: [""] }]
1774
+ }] });
1775
+
1776
+ class SubGroupModule {
1777
+ }
1778
+ SubGroupModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: SubGroupModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
1779
+ SubGroupModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: SubGroupModule, declarations: [SubGroupComponent], imports: [CommonModule,
1780
+ CrisprFieldModule,
1781
+ FieldContainerModule,
1782
+ CrisprPipesModule,
1783
+ // TODO: Does this need to be here?
1784
+ FormValidationHandlerModule], exports: [SubGroupComponent] });
1785
+ SubGroupModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: SubGroupModule, imports: [[
1786
+ CommonModule,
1787
+ CrisprFieldModule,
1788
+ FieldContainerModule,
1789
+ CrisprPipesModule,
1790
+ // TODO: Does this need to be here?
1791
+ FormValidationHandlerModule
1792
+ ]] });
1793
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: SubGroupModule, decorators: [{
1794
+ type: NgModule,
1795
+ args: [{
1796
+ imports: [
1797
+ CommonModule,
1798
+ CrisprFieldModule,
1799
+ FieldContainerModule,
1800
+ CrisprPipesModule,
1801
+ // TODO: Does this need to be here?
1802
+ FormValidationHandlerModule
1803
+ ],
1804
+ exports: [
1805
+ SubGroupComponent
1806
+ ],
1807
+ declarations: [
1808
+ SubGroupComponent
1809
+ ]
1810
+ }]
1811
+ }] });
1812
+
1813
+ var index = /*#__PURE__*/Object.freeze({
1814
+ __proto__: null,
1815
+ SubGroupComponent: SubGroupComponent,
1816
+ SubGroupModule: SubGroupModule
1817
+ });
1818
+
1819
+ class CrisprFormsModule {
1820
+ }
1821
+ CrisprFormsModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: CrisprFormsModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
1822
+ CrisprFormsModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: CrisprFormsModule, declarations: [CrisprFormComponent], imports: [CommonModule,
1823
+ ReactiveFormsModule,
1824
+ FormValidationHandlerModule,
1825
+ FormGroupListModule,
1826
+ FieldContainerModule,
1827
+ CrisprFieldModule,
1828
+ SubGroupModule,
1829
+ MaterialModule,
1830
+ CrisprPipesModule], exports: [CrisprFormComponent,
1831
+ FieldContainerModule,
1832
+ MaterialModule] });
1833
+ CrisprFormsModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: CrisprFormsModule, imports: [[
1834
+ CommonModule,
1835
+ ReactiveFormsModule,
1836
+ FormValidationHandlerModule,
1837
+ FormGroupListModule,
1838
+ FieldContainerModule,
1839
+ CrisprFieldModule,
1840
+ SubGroupModule,
1841
+ MaterialModule,
1842
+ CrisprPipesModule,
1843
+ ], FieldContainerModule,
1844
+ MaterialModule] });
1845
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.1", ngImport: i0, type: CrisprFormsModule, decorators: [{
1846
+ type: NgModule,
1847
+ args: [{
1848
+ imports: [
1849
+ CommonModule,
1850
+ ReactiveFormsModule,
1851
+ FormValidationHandlerModule,
1852
+ FormGroupListModule,
1853
+ FieldContainerModule,
1854
+ CrisprFieldModule,
1855
+ SubGroupModule,
1856
+ MaterialModule,
1857
+ CrisprPipesModule,
1858
+ ],
1859
+ declarations: [
1860
+ CrisprFormComponent,
1861
+ ],
1862
+ exports: [
1863
+ CrisprFormComponent,
1864
+ FieldContainerModule,
1865
+ MaterialModule
1866
+ ]
1867
+ }]
1868
+ }] });
1869
+
1870
+ /**
1871
+ * Generated bundle index. Do not edit.
1872
+ */
1873
+
1874
+ export { AbstractAutocompleteComponent, AutocompleteChiplistFieldComponent, AutocompleteFieldComponent, ButtonComponent, CheckboxFieldComponent, ControlType, CrisprFieldComponent, CrisprFormComponent, CrisprFormsModule, DEFAULT_EMPTY_OPTIONS_MESSAGE, DatepickerFieldComponent, DividerComponent, FieldContainerComponent, FieldContainerModule, FileDropzoneDirective, FileUploadFieldComponent, FileUploadFieldModule, HeadingComponent, HeadingModule, ImageUploadFieldComponent, ImageUploadFieldModule, InputFieldComponent, MaterialModule, OptionComponent, RadioFieldComponent, SelectFieldComponent, SliderFieldComponent, TextareaFieldComponent, UnitConversionFieldComponent, buildFormGroupFromConfig, callOptionsIfFunction, checkControlForValues, checkControlsForValues, computeValueFromFields, createControlForType, crisprControlMixin, filterOptionsByLabel, isControlConfig, maxFileSizeValidator, observablifyOptions };
1875
+ //# sourceMappingURL=tft-crispr-forms.mjs.map