@kirbydesign/designsystem 0.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 (552) hide show
  1. package/README.md +7 -0
  2. package/karma.conf.js +34 -0
  3. package/ng-package.json +32 -0
  4. package/ngcc.config.js +3 -0
  5. package/package.json +27 -0
  6. package/src/index.ts +1 -0
  7. package/src/lib/animation/kirby-animation.ts +12 -0
  8. package/src/lib/components/accordion/accordion-item.component.html +25 -0
  9. package/src/lib/components/accordion/accordion-item.component.scss +64 -0
  10. package/src/lib/components/accordion/accordion-item.component.spec.ts +52 -0
  11. package/src/lib/components/accordion/accordion-item.component.ts +27 -0
  12. package/src/lib/components/accordion/accordion.directive.ts +7 -0
  13. package/src/lib/components/accordion/index.ts +2 -0
  14. package/src/lib/components/angular-component-lib/utils.ts +43 -0
  15. package/src/lib/components/app/app.component.html +3 -0
  16. package/src/lib/components/app/app.component.scss +10 -0
  17. package/src/lib/components/app/app.component.spec.ts +52 -0
  18. package/src/lib/components/app/app.component.ts +50 -0
  19. package/src/lib/components/app/app.module.ts +12 -0
  20. package/src/lib/components/app/index.ts +2 -0
  21. package/src/lib/components/avatar/avatar.component.html +6 -0
  22. package/src/lib/components/avatar/avatar.component.scss +153 -0
  23. package/src/lib/components/avatar/avatar.component.spec.ts +207 -0
  24. package/src/lib/components/avatar/avatar.component.ts +32 -0
  25. package/src/lib/components/badge/badge.component.spec.ts +78 -0
  26. package/src/lib/components/button/button.component.html +1 -0
  27. package/src/lib/components/button/button.component.integration.spec.ts +576 -0
  28. package/src/lib/components/button/button.component.scss +286 -0
  29. package/src/lib/components/button/button.component.spec.ts +404 -0
  30. package/src/lib/components/button/button.component.ts +96 -0
  31. package/src/lib/components/calendar/calendar.component.html +49 -0
  32. package/src/lib/components/calendar/calendar.component.initialization.spec.ts +93 -0
  33. package/src/lib/components/calendar/calendar.component.scss +132 -0
  34. package/src/lib/components/calendar/calendar.component.spec.ts +470 -0
  35. package/src/lib/components/calendar/calendar.component.ts +513 -0
  36. package/src/lib/components/calendar/helpers/calendar-cell.model.ts +7 -0
  37. package/src/lib/components/calendar/helpers/calendar-options.model.ts +10 -0
  38. package/src/lib/components/calendar/helpers/calendar.helper.ts +108 -0
  39. package/src/lib/components/calendar/index.ts +2 -0
  40. package/src/lib/components/calendar/options/calendar-year-navigator-config.ts +4 -0
  41. package/src/lib/components/card/card-footer/card-footer.component.html +3 -0
  42. package/src/lib/components/card/card-footer/card-footer.component.scss +19 -0
  43. package/src/lib/components/card/card-footer/card-footer.component.ts +13 -0
  44. package/src/lib/components/card/card-header/card-header.component.html +5 -0
  45. package/src/lib/components/card/card-header/card-header.component.scss +63 -0
  46. package/src/lib/components/card/card-header/card-header.component.ts +20 -0
  47. package/src/lib/components/card/card.component.html +5 -0
  48. package/src/lib/components/card/card.component.scss +56 -0
  49. package/src/lib/components/card/card.component.spec.ts +81 -0
  50. package/src/lib/components/card/card.component.ts +95 -0
  51. package/src/lib/components/card/index.ts +3 -0
  52. package/src/lib/components/chart/chart-js/chart-js.service.integration.spec.ts +320 -0
  53. package/src/lib/components/chart/chart-js/chart-js.service.spec.ts +1004 -0
  54. package/src/lib/components/chart/chart-js/chart-js.service.ts +445 -0
  55. package/src/lib/components/chart/chart-js/chartjs-plugin-marker/chartjs-plugin-marker.ts +254 -0
  56. package/src/lib/components/chart/chart-js/configured-chart-js.ts +39 -0
  57. package/src/lib/components/chart/chart-js/test-utils.ts +171 -0
  58. package/src/lib/components/chart/chart.component.html +7 -0
  59. package/src/lib/components/chart/chart.component.scss +6 -0
  60. package/src/lib/components/chart/chart.component.spec.ts +188 -0
  61. package/src/lib/components/chart/chart.component.ts +148 -0
  62. package/src/lib/components/chart/chart.module.ts +11 -0
  63. package/src/lib/components/chart/chart.types.ts +34 -0
  64. package/src/lib/components/chart/configs/annotations.config.ts +36 -0
  65. package/src/lib/components/chart/configs/chart-config.service.spec.ts +21 -0
  66. package/src/lib/components/chart/configs/chart-config.service.ts +34 -0
  67. package/src/lib/components/chart/configs/global-defaults.config.ts +50 -0
  68. package/src/lib/components/chart/configs/interaction-functions-extensions.config.ts +19 -0
  69. package/src/lib/components/chart/configs/shared.utils.ts +28 -0
  70. package/src/lib/components/chart/configs/type.config.ts +214 -0
  71. package/src/lib/components/chart/index.ts +5 -0
  72. package/src/lib/components/chart-deprecated/chart-deprecated-helper.ts +25 -0
  73. package/src/lib/components/chart-deprecated/chart-deprecated-type.ts +10 -0
  74. package/src/lib/components/chart-deprecated/chart-deprecated.component.scss +3 -0
  75. package/src/lib/components/chart-deprecated/chart-deprecated.component.spec.ts +271 -0
  76. package/src/lib/components/chart-deprecated/chart-deprecated.component.ts +233 -0
  77. package/src/lib/components/chart-deprecated/index.ts +2 -0
  78. package/src/lib/components/chart-deprecated/options/activitygauge.ts +87 -0
  79. package/src/lib/components/chart-deprecated/options/areaspline.ts +95 -0
  80. package/src/lib/components/chart-deprecated/options/bar.ts +93 -0
  81. package/src/lib/components/chart-deprecated/options/column.ts +101 -0
  82. package/src/lib/components/chart-deprecated/options/donut.ts +118 -0
  83. package/src/lib/components/chart-deprecated/options/timeseries.ts +96 -0
  84. package/src/lib/components/checkbox/checkbox.component.html +10 -0
  85. package/src/lib/components/checkbox/checkbox.component.integration.spec.ts +59 -0
  86. package/src/lib/components/checkbox/checkbox.component.scss +130 -0
  87. package/src/lib/components/checkbox/checkbox.component.spec.ts +205 -0
  88. package/src/lib/components/checkbox/checkbox.component.ts +56 -0
  89. package/src/lib/components/chip/chip.component.html +1 -0
  90. package/src/lib/components/chip/chip.component.integration.spec.ts +111 -0
  91. package/src/lib/components/chip/chip.component.scss +49 -0
  92. package/src/lib/components/chip/chip.component.spec.ts +84 -0
  93. package/src/lib/components/chip/chip.component.ts +16 -0
  94. package/src/lib/components/divider/divider.component.html +1 -0
  95. package/src/lib/components/divider/divider.component.scss +22 -0
  96. package/src/lib/components/divider/divider.component.spec.ts +24 -0
  97. package/src/lib/components/divider/divider.component.ts +12 -0
  98. package/src/lib/components/dropdown/dropdown-popover.component.integration.spec.ts +177 -0
  99. package/src/lib/components/dropdown/dropdown-popover.component.spec.ts +1154 -0
  100. package/src/lib/components/dropdown/dropdown.component.html +42 -0
  101. package/src/lib/components/dropdown/dropdown.component.scss +142 -0
  102. package/src/lib/components/dropdown/dropdown.component.spec.ts +1215 -0
  103. package/src/lib/components/dropdown/dropdown.component.ts +538 -0
  104. package/src/lib/components/dropdown/dropdown.types.ts +10 -0
  105. package/src/lib/components/dropdown/keyboard-handler.service.ts +38 -0
  106. package/src/lib/components/empty-state/empty-state.component.html +10 -0
  107. package/src/lib/components/empty-state/empty-state.component.integration.spec.ts +110 -0
  108. package/src/lib/components/empty-state/empty-state.component.scss +50 -0
  109. package/src/lib/components/empty-state/empty-state.component.spec.ts +40 -0
  110. package/src/lib/components/empty-state/empty-state.component.ts +50 -0
  111. package/src/lib/components/fab-sheet/fab-sheet.component.html +13 -0
  112. package/src/lib/components/fab-sheet/fab-sheet.component.scss +67 -0
  113. package/src/lib/components/fab-sheet/fab-sheet.component.spec.ts +29 -0
  114. package/src/lib/components/fab-sheet/fab-sheet.component.ts +100 -0
  115. package/src/lib/components/flag/flag.component.scss +40 -0
  116. package/src/lib/components/flag/flag.component.spec.ts +152 -0
  117. package/src/lib/components/flag/flag.component.ts +18 -0
  118. package/src/lib/components/form-field/_form-field-inputs.shared.scss +62 -0
  119. package/src/lib/components/form-field/directives/date/date-input.directive.spec.ts +127 -0
  120. package/src/lib/components/form-field/directives/date/date-input.directive.ts +94 -0
  121. package/src/lib/components/form-field/directives/decimal-mask/decimal-mask.directive.spec.ts +231 -0
  122. package/src/lib/components/form-field/directives/decimal-mask/decimal-mask.directive.ts +113 -0
  123. package/src/lib/components/form-field/form-field-message/form-field-message.component.html +1 -0
  124. package/src/lib/components/form-field/form-field-message/form-field-message.component.scss +11 -0
  125. package/src/lib/components/form-field/form-field-message/form-field-message.component.ts +12 -0
  126. package/src/lib/components/form-field/form-field.component.html +39 -0
  127. package/src/lib/components/form-field/form-field.component.scss +43 -0
  128. package/src/lib/components/form-field/form-field.component.spec.ts +521 -0
  129. package/src/lib/components/form-field/form-field.component.ts +141 -0
  130. package/src/lib/components/form-field/index.ts +7 -0
  131. package/src/lib/components/form-field/input/input.component.integration.spec.ts +83 -0
  132. package/src/lib/components/form-field/input/input.component.scss +54 -0
  133. package/src/lib/components/form-field/input/input.component.spec.ts +159 -0
  134. package/src/lib/components/form-field/input/input.component.ts +91 -0
  135. package/src/lib/components/form-field/input-counter/input-counter.component.html +1 -0
  136. package/src/lib/components/form-field/input-counter/input-counter.component.spec.ts +184 -0
  137. package/src/lib/components/form-field/input-counter/input-counter.component.ts +41 -0
  138. package/src/lib/components/form-field/textarea/textarea.component.html +2 -0
  139. package/src/lib/components/form-field/textarea/textarea.component.scss +11 -0
  140. package/src/lib/components/form-field/textarea/textarea.component.spec.ts +100 -0
  141. package/src/lib/components/form-field/textarea/textarea.component.ts +64 -0
  142. package/src/lib/components/grid/breakpoint-helper.service.ts +27 -0
  143. package/src/lib/components/grid/grid-card-configuration.ts +7 -0
  144. package/src/lib/components/grid/grid.component.html +6 -0
  145. package/src/lib/components/grid/grid.component.scss +26 -0
  146. package/src/lib/components/grid/grid.component.ts +106 -0
  147. package/src/lib/components/icon/icon-registry.service.spec.ts +107 -0
  148. package/src/lib/components/icon/icon-registry.service.ts +39 -0
  149. package/src/lib/components/icon/icon-settings.ts +8 -0
  150. package/src/lib/components/icon/icon.component.html +1 -0
  151. package/src/lib/components/icon/icon.component.scss +47 -0
  152. package/src/lib/components/icon/icon.component.spec.ts +254 -0
  153. package/src/lib/components/icon/icon.component.ts +89 -0
  154. package/src/lib/components/icon/icon.module.ts +11 -0
  155. package/src/lib/components/icon/index.ts +5 -0
  156. package/src/lib/components/icon/kirby-icon-settings.ts +65 -0
  157. package/src/lib/components/icon/readme.md +16 -0
  158. package/src/lib/components/icon/selection.json +1776 -0
  159. package/src/lib/components/index.ts +67 -0
  160. package/src/lib/components/item/_item.utils.scss +36 -0
  161. package/src/lib/components/item/index.ts +3 -0
  162. package/src/lib/components/item/item.component.html +16 -0
  163. package/src/lib/components/item/item.component.integration.spec.ts +64 -0
  164. package/src/lib/components/item/item.component.scss +156 -0
  165. package/src/lib/components/item/item.component.spec.ts +85 -0
  166. package/src/lib/components/item/item.component.ts +37 -0
  167. package/src/lib/components/item/item.module.ts +14 -0
  168. package/src/lib/components/item/label/label.component.html +3 -0
  169. package/src/lib/components/item/label/label.component.scss +36 -0
  170. package/src/lib/components/item/label/label.component.spec.ts +23 -0
  171. package/src/lib/components/item/label/label.component.ts +16 -0
  172. package/src/lib/components/item-group/item-group.component.html +1 -0
  173. package/src/lib/components/item-group/item-group.component.scss +3 -0
  174. package/src/lib/components/item-group/item-group.component.spec.ts +42 -0
  175. package/src/lib/components/item-group/item-group.component.ts +10 -0
  176. package/src/lib/components/item-sliding/index.ts +2 -0
  177. package/src/lib/components/item-sliding/item-sliding.component.html +20 -0
  178. package/src/lib/components/item-sliding/item-sliding.component.scss +9 -0
  179. package/src/lib/components/item-sliding/item-sliding.component.spec.ts +174 -0
  180. package/src/lib/components/item-sliding/item-sliding.component.ts +23 -0
  181. package/src/lib/components/item-sliding/item-sliding.shared.scss +18 -0
  182. package/src/lib/components/item-sliding/item-sliding.types.ts +13 -0
  183. package/src/lib/components/list/directives/infinite-scroll.directive.spec.ts +131 -0
  184. package/src/lib/components/list/directives/infinite-scroll.directive.ts +137 -0
  185. package/src/lib/components/list/directives/list-item-color.directive.ts +27 -0
  186. package/src/lib/components/list/directives/scroll.model.ts +5 -0
  187. package/src/lib/components/list/helpers/list-helper.spec.ts +109 -0
  188. package/src/lib/components/list/helpers/list-helper.ts +19 -0
  189. package/src/lib/components/list/index.ts +21 -0
  190. package/src/lib/components/list/list-experimental/list-experimental.component.html +4 -0
  191. package/src/lib/components/list/list-experimental/list-experimental.component.scss +6 -0
  192. package/src/lib/components/list/list-experimental/list-experimental.component.spec.ts +112 -0
  193. package/src/lib/components/list/list-experimental/list-experimental.component.ts +21 -0
  194. package/src/lib/components/list/list-header/list-header.component.html +1 -0
  195. package/src/lib/components/list/list-header/list-header.component.scss +10 -0
  196. package/src/lib/components/list/list-header/list-header.component.spec.ts +24 -0
  197. package/src/lib/components/list/list-header/list-header.component.ts +11 -0
  198. package/src/lib/components/list/list-item/list-item.component.html +39 -0
  199. package/src/lib/components/list/list-item/list-item.component.scss +13 -0
  200. package/src/lib/components/list/list-item/list-item.component.ts +144 -0
  201. package/src/lib/components/list/list-section-header/list-section-header.component.html +3 -0
  202. package/src/lib/components/list/list-section-header/list-section-header.component.spec.ts +24 -0
  203. package/src/lib/components/list/list-section-header/list-section-header.component.ts +13 -0
  204. package/src/lib/components/list/list-swipe-action.ts +2 -0
  205. package/src/lib/components/list/list-swipe-action.type.ts +23 -0
  206. package/src/lib/components/list/list.component.html +65 -0
  207. package/src/lib/components/list/list.component.integration.spec.ts +177 -0
  208. package/src/lib/components/list/list.component.scss +243 -0
  209. package/src/lib/components/list/list.component.spec.ts +219 -0
  210. package/src/lib/components/list/list.component.ts +213 -0
  211. package/src/lib/components/list/list.directive.ts +21 -0
  212. package/src/lib/components/list/list.event.ts +8 -0
  213. package/src/lib/components/list/list.module.ts +47 -0
  214. package/src/lib/components/list/pipes/group-by.pipe.spec.ts +71 -0
  215. package/src/lib/components/list/pipes/group-by.pipe.ts +34 -0
  216. package/src/lib/components/loading-overlay/index.ts +2 -0
  217. package/src/lib/components/loading-overlay/loading-overlay.component.html +8 -0
  218. package/src/lib/components/loading-overlay/loading-overlay.component.scss +37 -0
  219. package/src/lib/components/loading-overlay/loading-overlay.component.ts +12 -0
  220. package/src/lib/components/loading-overlay/loading-overlay.service.ts +44 -0
  221. package/src/lib/components/modal/action-sheet/action-sheet.component.html +24 -0
  222. package/src/lib/components/modal/action-sheet/action-sheet.component.scss +47 -0
  223. package/src/lib/components/modal/action-sheet/action-sheet.component.spec.ts +153 -0
  224. package/src/lib/components/modal/action-sheet/action-sheet.component.ts +27 -0
  225. package/src/lib/components/modal/action-sheet/config/action-sheet-config.ts +8 -0
  226. package/src/lib/components/modal/action-sheet/config/action-sheet-item.ts +4 -0
  227. package/src/lib/components/modal/alert/alert.component.html +29 -0
  228. package/src/lib/components/modal/alert/alert.component.scss +21 -0
  229. package/src/lib/components/modal/alert/alert.component.spec.ts +104 -0
  230. package/src/lib/components/modal/alert/alert.component.ts +67 -0
  231. package/src/lib/components/modal/alert/config/alert-config.ts +19 -0
  232. package/src/lib/components/modal/footer/modal-footer.component.html +3 -0
  233. package/src/lib/components/modal/footer/modal-footer.component.scss +57 -0
  234. package/src/lib/components/modal/footer/modal-footer.component.spec.ts +209 -0
  235. package/src/lib/components/modal/footer/modal-footer.component.ts +17 -0
  236. package/src/lib/components/modal/index.ts +9 -0
  237. package/src/lib/components/modal/modal-wrapper/compact/modal-compact-wrapper.component.html +3 -0
  238. package/src/lib/components/modal/modal-wrapper/compact/modal-compact-wrapper.component.scss +8 -0
  239. package/src/lib/components/modal/modal-wrapper/compact/modal-compact-wrapper.component.ts +79 -0
  240. package/src/lib/components/modal/modal-wrapper/config/drawer-supplementary-action.ts +4 -0
  241. package/src/lib/components/modal/modal-wrapper/config/modal-config.helper.ts +3 -0
  242. package/src/lib/components/modal/modal-wrapper/config/modal-config.ts +22 -0
  243. package/src/lib/components/modal/modal-wrapper/modal-wrapper.component.html +43 -0
  244. package/src/lib/components/modal/modal-wrapper/modal-wrapper.component.scss +159 -0
  245. package/src/lib/components/modal/modal-wrapper/modal-wrapper.component.spec.ts +942 -0
  246. package/src/lib/components/modal/modal-wrapper/modal-wrapper.component.ts +587 -0
  247. package/src/lib/components/modal/modal-wrapper/modal-wrapper.testbuilder.ts +155 -0
  248. package/src/lib/components/modal/services/action-sheet.helper.spec.ts +86 -0
  249. package/src/lib/components/modal/services/action-sheet.helper.ts +47 -0
  250. package/src/lib/components/modal/services/alert.helper.spec.ts +89 -0
  251. package/src/lib/components/modal/services/alert.helper.ts +57 -0
  252. package/src/lib/components/modal/services/modal-animation-builder.service.ts +276 -0
  253. package/src/lib/components/modal/services/modal-navigation.service.spec.ts +543 -0
  254. package/src/lib/components/modal/services/modal-navigation.service.ts +331 -0
  255. package/src/lib/components/modal/services/modal.controller.spec.ts +212 -0
  256. package/src/lib/components/modal/services/modal.controller.ts +194 -0
  257. package/src/lib/components/modal/services/modal.helper.spec.ts +828 -0
  258. package/src/lib/components/modal/services/modal.helper.ts +128 -0
  259. package/src/lib/components/modal/services/modal.interfaces.ts +28 -0
  260. package/src/lib/components/page/index.ts +13 -0
  261. package/src/lib/components/page/page-footer/page-footer.component.html +3 -0
  262. package/src/lib/components/page/page-footer/page-footer.component.scss +23 -0
  263. package/src/lib/components/page/page-footer/page-footer.component.spec.ts +52 -0
  264. package/src/lib/components/page/page-footer/page-footer.component.ts +46 -0
  265. package/src/lib/components/page/page.component.html +101 -0
  266. package/src/lib/components/page/page.component.scss +141 -0
  267. package/src/lib/components/page/page.component.spec.ts +224 -0
  268. package/src/lib/components/page/page.component.ts +415 -0
  269. package/src/lib/components/page/page.module.ts +52 -0
  270. package/src/lib/components/popover/popover.component.scss +26 -0
  271. package/src/lib/components/popover/popover.component.spec.ts +0 -0
  272. package/src/lib/components/popover/popover.component.ts +221 -0
  273. package/src/lib/components/progress-circle/progress-circle-ring.component.scss +22 -0
  274. package/src/lib/components/progress-circle/progress-circle-ring.component.spec.ts +143 -0
  275. package/src/lib/components/progress-circle/progress-circle-ring.component.svg +23 -0
  276. package/src/lib/components/progress-circle/progress-circle-ring.component.ts +42 -0
  277. package/src/lib/components/progress-circle/progress-circle.component.html +11 -0
  278. package/src/lib/components/progress-circle/progress-circle.component.scss +28 -0
  279. package/src/lib/components/progress-circle/progress-circle.component.spec.ts +339 -0
  280. package/src/lib/components/progress-circle/progress-circle.component.ts +96 -0
  281. package/src/lib/components/radio/index.ts +2 -0
  282. package/src/lib/components/radio/radio-group/radio-group.component.html +24 -0
  283. package/src/lib/components/radio/radio-group/radio-group.component.spec.ts +1328 -0
  284. package/src/lib/components/radio/radio-group/radio-group.component.ts +272 -0
  285. package/src/lib/components/radio/radio.component.html +9 -0
  286. package/src/lib/components/radio/radio.component.integration.spec.ts +93 -0
  287. package/src/lib/components/radio/radio.component.scss +133 -0
  288. package/src/lib/components/radio/radio.component.spec.ts +244 -0
  289. package/src/lib/components/radio/radio.component.ts +50 -0
  290. package/src/lib/components/range/range.component.html +16 -0
  291. package/src/lib/components/range/range.component.scss +81 -0
  292. package/src/lib/components/range/range.component.ts +105 -0
  293. package/src/lib/components/reorder-list/index.ts +3 -0
  294. package/src/lib/components/reorder-list/reorder-event.ts +17 -0
  295. package/src/lib/components/reorder-list/reorder-list.component.html +30 -0
  296. package/src/lib/components/reorder-list/reorder-list.component.scss +90 -0
  297. package/src/lib/components/reorder-list/reorder-list.component.spec.ts +123 -0
  298. package/src/lib/components/reorder-list/reorder-list.component.ts +86 -0
  299. package/src/lib/components/router-outlet/index.ts +5 -0
  300. package/src/lib/components/router-outlet/router-outlet.component.html +6 -0
  301. package/src/lib/components/router-outlet/router-outlet.component.scss +13 -0
  302. package/src/lib/components/router-outlet/router-outlet.component.spec.ts +28 -0
  303. package/src/lib/components/router-outlet/router-outlet.component.ts +11 -0
  304. package/src/lib/components/router-outlet/router-outlet.module.ts +12 -0
  305. package/src/lib/components/section-header/_section-header.utils.scss +34 -0
  306. package/src/lib/components/section-header/section-header.component.html +3 -0
  307. package/src/lib/components/section-header/section-header.component.scss +15 -0
  308. package/src/lib/components/section-header/section-header.component.spec.ts +59 -0
  309. package/src/lib/components/section-header/section-header.component.ts +9 -0
  310. package/src/lib/components/section-header/section-header.integration.spec.ts +67 -0
  311. package/src/lib/components/segmented-control/segment-item.ts +18 -0
  312. package/src/lib/components/segmented-control/segmented-control.component.html +39 -0
  313. package/src/lib/components/segmented-control/segmented-control.component.scss +84 -0
  314. package/src/lib/components/segmented-control/segmented-control.component.spec.ts +247 -0
  315. package/src/lib/components/segmented-control/segmented-control.component.ts +96 -0
  316. package/src/lib/components/shared/component-configuration.ts +6 -0
  317. package/src/lib/components/shared/component-loader.directive.ts +42 -0
  318. package/src/lib/components/shared/dynamic-component.ts +3 -0
  319. package/src/lib/components/shared/index.ts +9 -0
  320. package/src/lib/components/shared/resize-observer/resize-observer.factory.ts +20 -0
  321. package/src/lib/components/shared/resize-observer/resize-observer.service.ts +65 -0
  322. package/src/lib/components/shared/resize-observer/types/resize-observer-callback.ts +7 -0
  323. package/src/lib/components/shared/resize-observer/types/resize-observer-entry.ts +14 -0
  324. package/src/lib/components/shared/resize-observer/types/resize-observer.ts +17 -0
  325. package/src/lib/components/slide-button/slide-button.component.html +14 -0
  326. package/src/lib/components/slide-button/slide-button.component.scss +81 -0
  327. package/src/lib/components/slide-button/slide-button.component.shared.scss +12 -0
  328. package/src/lib/components/slide-button/slide-button.component.spec.ts +75 -0
  329. package/src/lib/components/slide-button/slide-button.component.ts +81 -0
  330. package/src/lib/components/slides/slides.component.spec.ts +76 -0
  331. package/src/lib/components/slides/slides.component.ts +57 -0
  332. package/src/lib/components/spinner/index.ts +2 -0
  333. package/src/lib/components/spinner/spinner.component.html +4 -0
  334. package/src/lib/components/spinner/spinner.component.scss +37 -0
  335. package/src/lib/components/spinner/spinner.component.ts +13 -0
  336. package/src/lib/components/spinner/spinner.module.ts +12 -0
  337. package/src/lib/components/stock-chart-deprecated/index.ts +2 -0
  338. package/src/lib/components/stock-chart-deprecated/options/stock-chart-deprecated-options.ts +220 -0
  339. package/src/lib/components/stock-chart-deprecated/stock-chart-deprecated.component.scss +3 -0
  340. package/src/lib/components/stock-chart-deprecated/stock-chart-deprecated.component.spec.ts +32 -0
  341. package/src/lib/components/stock-chart-deprecated/stock-chart-deprecated.component.ts +92 -0
  342. package/src/lib/components/tabs/index.ts +5 -0
  343. package/src/lib/components/tabs/tab-button/tab-button.component.html +13 -0
  344. package/src/lib/components/tabs/tab-button/tab-button.component.scss +48 -0
  345. package/src/lib/components/tabs/tab-button/tab-button.component.spec.ts +24 -0
  346. package/src/lib/components/tabs/tab-button/tab-button.component.ts +47 -0
  347. package/src/lib/components/tabs/tab-button/tab-button.events.ts +1 -0
  348. package/src/lib/components/tabs/tabs.component.html +5 -0
  349. package/src/lib/components/tabs/tabs.component.scss +52 -0
  350. package/src/lib/components/tabs/tabs.component.spec.ts +125 -0
  351. package/src/lib/components/tabs/tabs.component.ts +21 -0
  352. package/src/lib/components/tabs/tabs.module.ts +16 -0
  353. package/src/lib/components/tabs/tabs.service.ts +17 -0
  354. package/src/lib/components/toast/config/toast-config.ts +8 -0
  355. package/src/lib/components/toast/index.ts +2 -0
  356. package/src/lib/components/toast/services/toast.controller.ts +18 -0
  357. package/src/lib/components/toast/services/toast.helper.spec.ts +89 -0
  358. package/src/lib/components/toast/services/toast.helper.ts +39 -0
  359. package/src/lib/components/toggle/toggle.component.html +5 -0
  360. package/src/lib/components/toggle/toggle.component.scss +5 -0
  361. package/src/lib/components/toggle/toggle.component.spec.ts +62 -0
  362. package/src/lib/components/toggle/toggle.component.ts +17 -0
  363. package/src/lib/components/toggle-button/index.ts +2 -0
  364. package/src/lib/components/toggle-button/toggle-button.component.html +6 -0
  365. package/src/lib/components/toggle-button/toggle-button.component.spec.ts +23 -0
  366. package/src/lib/components/toggle-button/toggle-button.component.ts +24 -0
  367. package/src/lib/components/toggle-button/toggle-button.module.ts +13 -0
  368. package/src/lib/components/web-component-proxies.component.ts +25 -0
  369. package/src/lib/custom-elements-initializer.ts +19 -0
  370. package/src/lib/directives/element-as-button/element-as-button.directive.spec.ts +31 -0
  371. package/src/lib/directives/element-as-button/element-as-button.directive.ts +26 -0
  372. package/src/lib/directives/fit-heading/fit-heading.directive.ts +131 -0
  373. package/src/lib/directives/fit-heading/fit-heading.module.ts +9 -0
  374. package/src/lib/directives/index.ts +9 -0
  375. package/src/lib/directives/key-handler/key-handler.directive.ts +20 -0
  376. package/src/lib/directives/modal-router-link/modal-router-link.directive.ts +24 -0
  377. package/src/lib/directives/theme-color/theme-color.directive.ts +117 -0
  378. package/src/lib/helpers/color-helper.styles.ts +193 -0
  379. package/src/lib/helpers/color-helper.ts +1 -0
  380. package/src/lib/helpers/deep-copy.ts +13 -0
  381. package/src/lib/helpers/design-token-helper.styles.ts +78 -0
  382. package/src/lib/helpers/design-token-helper.ts +6 -0
  383. package/src/lib/helpers/element-has-ancestor.ts +28 -0
  384. package/src/lib/helpers/index.ts +8 -0
  385. package/src/lib/helpers/line-clamp-helper.ts +28 -0
  386. package/src/lib/helpers/merge-deep.spec.ts +11 -0
  387. package/src/lib/helpers/merge-deep.ts +41 -0
  388. package/src/lib/helpers/platform.service.ts +22 -0
  389. package/src/lib/helpers/string-helper.ts +6 -0
  390. package/src/lib/helpers/theme-color.type.ts +1 -0
  391. package/src/lib/helpers/unique-id-generator.helper.spec.ts +58 -0
  392. package/src/lib/helpers/unique-id-generator.helper.ts +19 -0
  393. package/src/lib/icons/svg/QR.svg +7 -0
  394. package/src/lib/icons/svg/accounts-outline.svg +9 -0
  395. package/src/lib/icons/svg/accounts.svg +9 -0
  396. package/src/lib/icons/svg/add.svg +7 -0
  397. package/src/lib/icons/svg/arrow-back.svg +7 -0
  398. package/src/lib/icons/svg/arrow-down.svg +7 -0
  399. package/src/lib/icons/svg/arrow-more.svg +7 -0
  400. package/src/lib/icons/svg/arrow-up.svg +7 -0
  401. package/src/lib/icons/svg/attach.svg +7 -0
  402. package/src/lib/icons/svg/backspace.svg +9 -0
  403. package/src/lib/icons/svg/calendar.svg +7 -0
  404. package/src/lib/icons/svg/camera.svg +9 -0
  405. package/src/lib/icons/svg/checkbox-outline.svg +7 -0
  406. package/src/lib/icons/svg/checkbox.svg +7 -0
  407. package/src/lib/icons/svg/checkmark-selected.svg +3 -0
  408. package/src/lib/icons/svg/clock.svg +7 -0
  409. package/src/lib/icons/svg/close.svg +7 -0
  410. package/src/lib/icons/svg/cog.svg +7 -0
  411. package/src/lib/icons/svg/copy.svg +9 -0
  412. package/src/lib/icons/svg/edit.svg +7 -0
  413. package/src/lib/icons/svg/filter.svg +7 -0
  414. package/src/lib/icons/svg/flag.svg +9 -0
  415. package/src/lib/icons/svg/flash-off.svg +7 -0
  416. package/src/lib/icons/svg/flash.svg +7 -0
  417. package/src/lib/icons/svg/foreign-payment.svg +7 -0
  418. package/src/lib/icons/svg/help.svg +7 -0
  419. package/src/lib/icons/svg/home.svg +5 -0
  420. package/src/lib/icons/svg/inbox-outline.svg +9 -0
  421. package/src/lib/icons/svg/inbox.svg +9 -0
  422. package/src/lib/icons/svg/information.svg +9 -0
  423. package/src/lib/icons/svg/investment.svg +5 -0
  424. package/src/lib/icons/svg/kirby.svg +3 -0
  425. package/src/lib/icons/svg/link.svg +7 -0
  426. package/src/lib/icons/svg/log-out.svg +7 -0
  427. package/src/lib/icons/svg/menu-outline.svg +9 -0
  428. package/src/lib/icons/svg/menu.svg +9 -0
  429. package/src/lib/icons/svg/misc.svg +5 -0
  430. package/src/lib/icons/svg/moneybag.svg +7 -0
  431. package/src/lib/icons/svg/more.svg +5 -0
  432. package/src/lib/icons/svg/move.svg +7 -0
  433. package/src/lib/icons/svg/payment-card.svg +6 -0
  434. package/src/lib/icons/svg/pension.svg +7 -0
  435. package/src/lib/icons/svg/person-outline.svg +9 -0
  436. package/src/lib/icons/svg/person.svg +9 -0
  437. package/src/lib/icons/svg/remove.svg +6 -0
  438. package/src/lib/icons/svg/reorder.svg +9 -0
  439. package/src/lib/icons/svg/search.svg +7 -0
  440. package/src/lib/icons/svg/share.svg +7 -0
  441. package/src/lib/icons/svg/sort.svg +7 -0
  442. package/src/lib/icons/svg/support.svg +9 -0
  443. package/src/lib/icons/svg/swap.svg +7 -0
  444. package/src/lib/icons/svg/trash.svg +7 -0
  445. package/src/lib/icons/svg/unsubscribe.svg +7 -0
  446. package/src/lib/icons/svg/verify.svg +7 -0
  447. package/src/lib/icons/svg/warning.svg +7 -0
  448. package/src/lib/icons/svg/write-message.svg +7 -0
  449. package/src/lib/index.ts +8 -0
  450. package/src/lib/kirby.module.spec.ts +20 -0
  451. package/src/lib/kirby.module.ts +219 -0
  452. package/src/lib/polyfills/intersection-observer-polyfill-loader.js +14 -0
  453. package/src/lib/polyfills/intersection-observer-polyfill-loader.min.js +1 -0
  454. package/src/lib/polyfills/intersection-observer-polyfill.js +2 -0
  455. package/src/lib/polyfills/intersection-observer-polyfill.min.js +1 -0
  456. package/src/lib/polyfills/resize-observer-polyfill-loader.js +14 -0
  457. package/src/lib/polyfills/resize-observer-polyfill-loader.min.js +1 -0
  458. package/src/lib/polyfills/resize-observer-polyfill.js +2 -0
  459. package/src/lib/polyfills/resize-observer-polyfill.min.js +1 -0
  460. package/src/lib/scss/link.spec.ts +47 -0
  461. package/src/lib/scss/scss-helper.ts +8 -0
  462. package/src/lib/scss/typography.spec.ts +241 -0
  463. package/src/lib/testing/element-css-custom-matchers.d.ts +7 -0
  464. package/src/lib/testing/element-css-custom-matchers.ts +139 -0
  465. package/src/lib/testing/styles.scss +13 -0
  466. package/src/lib/testing/test-helper.ts +158 -0
  467. package/src/lib/types/index.ts +1 -0
  468. package/src/lib/types/window-ref.ts +10 -0
  469. package/src/test.ts +34 -0
  470. package/src/typings.test.d.ts +1 -0
  471. package/testing-base/ng-package.json +3 -0
  472. package/testing-base/src/lib/components/index.ts +66 -0
  473. package/testing-base/src/lib/components/mock.accordion-item.component.ts +21 -0
  474. package/testing-base/src/lib/components/mock.action-sheet.component.ts +27 -0
  475. package/testing-base/src/lib/components/mock.app.component.ts +18 -0
  476. package/testing-base/src/lib/components/mock.avatar.component.ts +38 -0
  477. package/testing-base/src/lib/components/mock.badge.component.ts +20 -0
  478. package/testing-base/src/lib/components/mock.button.component.ts +26 -0
  479. package/testing-base/src/lib/components/mock.calendar.component.ts +36 -0
  480. package/testing-base/src/lib/components/mock.card-footer.component.ts +18 -0
  481. package/testing-base/src/lib/components/mock.card-header.component.ts +23 -0
  482. package/testing-base/src/lib/components/mock.card.component.ts +25 -0
  483. package/testing-base/src/lib/components/mock.chart-deprecated.component.ts +28 -0
  484. package/testing-base/src/lib/components/mock.chart.component.ts +36 -0
  485. package/testing-base/src/lib/components/mock.checkbox.component.ts +26 -0
  486. package/testing-base/src/lib/components/mock.chip.component.ts +21 -0
  487. package/testing-base/src/lib/components/mock.divider.component.ts +20 -0
  488. package/testing-base/src/lib/components/mock.dropdown.component.ts +32 -0
  489. package/testing-base/src/lib/components/mock.empty-state.component.ts +23 -0
  490. package/testing-base/src/lib/components/mock.fab-sheet.component.ts +21 -0
  491. package/testing-base/src/lib/components/mock.flag.component.ts +21 -0
  492. package/testing-base/src/lib/components/mock.form-field-message.component.ts +21 -0
  493. package/testing-base/src/lib/components/mock.form-field.component.ts +23 -0
  494. package/testing-base/src/lib/components/mock.grid.component.ts +21 -0
  495. package/testing-base/src/lib/components/mock.icon.component.ts +22 -0
  496. package/testing-base/src/lib/components/mock.input-counter.component.ts +24 -0
  497. package/testing-base/src/lib/components/mock.input.component.ts +29 -0
  498. package/testing-base/src/lib/components/mock.item-group.component.ts +18 -0
  499. package/testing-base/src/lib/components/mock.item-sliding.component.ts +21 -0
  500. package/testing-base/src/lib/components/mock.item.component.ts +24 -0
  501. package/testing-base/src/lib/components/mock.label.component.ts +20 -0
  502. package/testing-base/src/lib/components/mock.list-experimental.component.ts +18 -0
  503. package/testing-base/src/lib/components/mock.list-header.component.ts +18 -0
  504. package/testing-base/src/lib/components/mock.list-item.component.ts +33 -0
  505. package/testing-base/src/lib/components/mock.list-section-header.component.ts +20 -0
  506. package/testing-base/src/lib/components/mock.list.component.ts +39 -0
  507. package/testing-base/src/lib/components/mock.loading-overlay.component.ts +21 -0
  508. package/testing-base/src/lib/components/mock.modal-footer.component.ts +21 -0
  509. package/testing-base/src/lib/components/mock.page-footer.component.ts +20 -0
  510. package/testing-base/src/lib/components/mock.page.component.ts +152 -0
  511. package/testing-base/src/lib/components/mock.popover.component.ts +22 -0
  512. package/testing-base/src/lib/components/mock.progress-circle.component.ts +22 -0
  513. package/testing-base/src/lib/components/mock.radio-group.component.ts +27 -0
  514. package/testing-base/src/lib/components/mock.radio.component.ts +23 -0
  515. package/testing-base/src/lib/components/mock.range.component.ts +35 -0
  516. package/testing-base/src/lib/components/mock.reorder-list.component.ts +25 -0
  517. package/testing-base/src/lib/components/mock.router-outlet.component.ts +20 -0
  518. package/testing-base/src/lib/components/mock.section-header.component.ts +18 -0
  519. package/testing-base/src/lib/components/mock.segmented-control.component.ts +29 -0
  520. package/testing-base/src/lib/components/mock.slide-button.component.ts +23 -0
  521. package/testing-base/src/lib/components/mock.slides.component.ts +29 -0
  522. package/testing-base/src/lib/components/mock.spinner.component.ts +18 -0
  523. package/testing-base/src/lib/components/mock.tab-button.component.ts +21 -0
  524. package/testing-base/src/lib/components/mock.tabs.component.ts +18 -0
  525. package/testing-base/src/lib/components/mock.textarea.component.ts +26 -0
  526. package/testing-base/src/lib/components/mock.toggle-button.component.ts +21 -0
  527. package/testing-base/src/lib/components/mock.toggle.component.ts +22 -0
  528. package/testing-base/src/lib/components/mock.web-component-proxies.component.ts +32 -0
  529. package/testing-base/src/lib/directives/index.ts +3 -0
  530. package/testing-base/src/lib/directives/mock.accordion.directive.ts +15 -0
  531. package/testing-base/src/lib/directives/mock.fit-heading.directive.ts +19 -0
  532. package/testing-base/src/lib/directives/mock.theme-color.directive.ts +19 -0
  533. package/testing-base/src/lib/index.ts +4 -0
  534. package/testing-base/src/lib/kirby-testing-base.module.ts +10 -0
  535. package/testing-base/src/lib/mock-components.ts +133 -0
  536. package/testing-base/src/lib/mock-directives.ts +9 -0
  537. package/testing-base/src/public_api.ts +1 -0
  538. package/testing-base/src/tsconfig.json +9 -0
  539. package/testing-jasmine/ng-package.json +3 -0
  540. package/testing-jasmine/src/lib/kirby-testing.module.ts +14 -0
  541. package/testing-jasmine/src/lib/mock-providers.ts +68 -0
  542. package/testing-jasmine/src/public_api.ts +1 -0
  543. package/testing-jasmine/src/tsconfig.json +10 -0
  544. package/testing-jest/ng-package.json +3 -0
  545. package/testing-jest/src/lib/kirby-testing.module.ts +14 -0
  546. package/testing-jest/src/lib/mock-providers.ts +76 -0
  547. package/testing-jest/src/public_api.ts +1 -0
  548. package/testing-jest/src/tsconfig.json +10 -0
  549. package/tsconfig.json +17 -0
  550. package/tsconfig.lib.json +23 -0
  551. package/tsconfig.spec.json +9 -0
  552. package/tslint.json +10 -0
@@ -0,0 +1,942 @@
1
+ import { fakeAsync, tick } from '@angular/core/testing';
2
+ import { RouterTestingModule } from '@angular/router/testing';
3
+ import { IonButtons, IonContent, IonHeader, IonTitle, IonToolbar } from '@ionic/angular';
4
+ import { createComponentFactory, Spectator } from '@ngneat/spectator';
5
+ import { MockComponents } from 'ng-mocks';
6
+
7
+ import { KirbyAnimation } from '../../../animation/kirby-animation';
8
+ import { TestHelper } from '../../../testing/test-helper';
9
+ import { WindowRef } from '../../../types';
10
+ import { ButtonComponent } from '../../button/button.component';
11
+ import { IconComponent } from '../../icon/icon.component';
12
+ import { PageProgressComponent } from '../../page';
13
+ import { ModalFooterComponent } from '../footer/modal-footer.component';
14
+
15
+ import { ModalWrapperComponent } from './modal-wrapper.component';
16
+ import {
17
+ DynamicFooterEmbeddedComponent,
18
+ DynamicPageProgressEmbeddedComponent,
19
+ InputEmbeddedComponent,
20
+ ModalWrapperTestBuilder,
21
+ StaticFooterEmbeddedComponent,
22
+ StaticPageProgressEmbeddedComponent,
23
+ TitleEmbeddedComponent,
24
+ } from './modal-wrapper.testbuilder';
25
+
26
+ describe('ModalWrapperComponent', () => {
27
+ const createComponent = createComponentFactory({
28
+ component: ModalWrapperComponent,
29
+ imports: [RouterTestingModule],
30
+ entryComponents: [
31
+ StaticFooterEmbeddedComponent,
32
+ DynamicFooterEmbeddedComponent,
33
+ InputEmbeddedComponent,
34
+ StaticPageProgressEmbeddedComponent,
35
+ DynamicPageProgressEmbeddedComponent,
36
+ ],
37
+ providers: [
38
+ {
39
+ provide: WindowRef,
40
+ useValue: <WindowRef>{ nativeWindow: window },
41
+ },
42
+ ],
43
+ declarations: [
44
+ MockComponents(
45
+ IonHeader,
46
+ IonToolbar,
47
+ IonTitle,
48
+ IonContent,
49
+ IconComponent,
50
+ ButtonComponent,
51
+ PageProgressComponent,
52
+ ModalFooterComponent,
53
+ IonButtons
54
+ ),
55
+ ],
56
+ });
57
+
58
+ let modalWrapperTestBuilder: ModalWrapperTestBuilder;
59
+ let spectator: Spectator<ModalWrapperComponent>;
60
+
61
+ beforeEach(() => {
62
+ modalWrapperTestBuilder = new ModalWrapperTestBuilder(createComponent);
63
+ });
64
+
65
+ it('should create', () => {
66
+ spectator = modalWrapperTestBuilder.build();
67
+
68
+ expect(spectator.component).toBeTruthy();
69
+ // Ensure any observers are destroyed:
70
+ spectator.fixture.destroy();
71
+ });
72
+
73
+ describe("when 'collapseTitle' is enabled", () => {
74
+ /*
75
+ Whether the title is displayed & truncated is not tested.
76
+ This is the responsibility of the ionic components; we assume
77
+ they're working as intended.
78
+
79
+ If needed, it should be implemented as an integration test.
80
+ */
81
+
82
+ let ionContentElement: HTMLIonContentElement;
83
+ let ionTitleElement: HTMLIonTitleElement;
84
+ const testTitle = 'This is a long test title';
85
+
86
+ beforeEach(() => {
87
+ spectator = modalWrapperTestBuilder
88
+ .flavor('modal')
89
+ .collapsibleTitle(true)
90
+ .title(testTitle)
91
+ .component(TitleEmbeddedComponent)
92
+ .build();
93
+
94
+ ionContentElement = spectator.query('ion-content');
95
+ ionTitleElement = spectator.query('ion-title');
96
+ });
97
+
98
+ afterEach(() => {
99
+ spectator.fixture.destroy();
100
+ });
101
+
102
+ it('should not have any padding between content & toolbar', () => {
103
+ const ionContentToolbarElement: HTMLIonToolbarElement =
104
+ ionContentElement.querySelector('ion-toolbar');
105
+ expect(ionContentToolbarElement).not.toBeUndefined();
106
+
107
+ expect(ionContentToolbarElement).toHaveComputedStyle({
108
+ 'padding-top': '0px',
109
+ '--padding-top': '0px',
110
+ '--padding-bottom': '0px',
111
+ '--padding-start': '0px',
112
+ '--padding-end': '0px',
113
+ });
114
+ expect(ionContentElement).toHaveComputedStyle({ '--padding-top': '0px' });
115
+ });
116
+
117
+ it('should place the title in both the content & the header', () => {
118
+ const contentTitle = ionContentElement.querySelector('kirby-page-title').innerHTML;
119
+ const headerTitle = ionTitleElement.querySelector('kirby-page-title').innerHTML;
120
+
121
+ expect(contentTitle).toBe(testTitle);
122
+ expect(headerTitle).toBe(testTitle);
123
+ });
124
+ });
125
+
126
+ describe('with slotted kirby-page-title', () => {
127
+ let ionTitle: HTMLIonTitleElement;
128
+
129
+ beforeEach(() => {
130
+ spectator = modalWrapperTestBuilder
131
+ .title('Test title')
132
+ .component(TitleEmbeddedComponent)
133
+ .flavor('modal')
134
+ .build();
135
+ ionTitle = spectator.query('ion-header kirby-page-title');
136
+ });
137
+
138
+ afterEach(() => {
139
+ // Ensure any observers are destroyed:
140
+ spectator.fixture.destroy();
141
+ });
142
+
143
+ it('should render', () => {
144
+ expect(ionTitle.innerHTML).toEqual('Test title');
145
+ });
146
+
147
+ it('should have css class "drawer" when drawer flavor is used', () => {
148
+ spectator.component.config.flavor = 'drawer';
149
+ spectator.detectChanges();
150
+ const rootElement: HTMLElement = spectator.element;
151
+ expect(rootElement.classList).toContain('drawer');
152
+ });
153
+
154
+ it('should have font size "m" when drawer flavor is used', () => {
155
+ spectator.component.config.flavor = 'drawer';
156
+ spectator.detectChanges();
157
+ const rootElement: HTMLElement = spectator.element;
158
+ const title = rootElement.querySelector('ion-title');
159
+ expect(window.getComputedStyle(title).fontSize).toEqual('18px');
160
+ });
161
+ });
162
+
163
+ describe('sizing', () => {
164
+ beforeEach(() => {
165
+ spectator = modalWrapperTestBuilder.flavor('modal').withEmbeddedInputComponent().build();
166
+ });
167
+ afterEach(() => {
168
+ spectator.fixture.destroy();
169
+ });
170
+
171
+ it('should observe Ionic modal-wrapper intersecting with viewport after ion-modal has been presented', async () => {
172
+ const observeSpy = spyOn(spectator.component['intersectionObserver'], 'observe');
173
+
174
+ spectator.component['ionModalDidPresent'].complete();
175
+ await TestHelper.waitForTimeout();
176
+
177
+ const dummyWrapper = spectator.element.closest('.modal-wrapper');
178
+ expect(observeSpy).toHaveBeenCalledWith(dummyWrapper);
179
+ });
180
+
181
+ it('should clean up intersection observer of Ionic modal-wrapper on destroy', async () => {
182
+ const disconnectSpy = spyOn(spectator.component['intersectionObserver'], 'disconnect');
183
+ spectator.component['ionModalDidPresent'].complete();
184
+ await TestHelper.waitForTimeout();
185
+
186
+ spectator.component.ngOnDestroy();
187
+
188
+ expect(disconnectSpy).toHaveBeenCalled();
189
+ });
190
+ });
191
+
192
+ describe('viewportResize', () => {
193
+ it('should emit when viewport is resized', async () => {
194
+ spectator = modalWrapperTestBuilder.build();
195
+ await TestHelper.whenTrue(() => !!spectator.component['initialViewportHeight']);
196
+ const viewportResizeSpy = spyOn(spectator.component['viewportResize'], 'next');
197
+
198
+ await TestHelper.resizeTestWindow(TestHelper.screensize.tablet);
199
+ await TestHelper.whenTrue(() => spectator.component['viewportResized']);
200
+
201
+ expect(viewportResizeSpy).toHaveBeenCalled();
202
+ });
203
+
204
+ afterAll(() => {
205
+ TestHelper.resetTestWindow();
206
+ });
207
+ });
208
+
209
+ describe('with interact with background', () => {
210
+ const elementHeight = 500;
211
+ const elementWidth = 300;
212
+ const screenSize = TestHelper.screensize.desktop;
213
+ let scrollbarWidth = 0;
214
+
215
+ beforeAll(async () => {
216
+ await TestHelper.resizeTestWindow(screenSize);
217
+ scrollbarWidth = window.innerWidth - document.documentElement.clientWidth;
218
+ });
219
+
220
+ afterAll(() => {
221
+ TestHelper.resetTestWindow();
222
+ });
223
+
224
+ describe('when flavor is modal', () => {
225
+ beforeEach(() => {
226
+ spectator = modalWrapperTestBuilder.flavor('modal').interactWithBackground().build();
227
+ spectator.element.style.height = `${elementHeight}px`;
228
+ spectator.element.style.width = `${elementWidth}px`;
229
+ spectator.element.style.overflow = 'hidden';
230
+ spectator.element.style.position = 'fixed'; // Use 'fixed' instead of 'absolute' to prevent test breaking if test window is scrolled
231
+ spectator.element.style.bottom = '0';
232
+ spectator.element.style.left = `calc(50% - ${elementWidth / 2}px)`; // Simulate horizontally centered modal
233
+ spectator.element.style.backgroundColor = 'charrtreuse'; // Add some background for easier debugging of test
234
+ });
235
+
236
+ afterEach(() => {
237
+ // Ensure any observers are destroyed:
238
+ spectator.fixture.destroy();
239
+ });
240
+
241
+ it('should NOT resize ion-modal to wrapper size after ion-modal has been presented', fakeAsync(() => {
242
+ spectator.component['ionModalDidPresent'].next();
243
+ spectator.component['ionModalDidPresent'].complete();
244
+ tick();
245
+
246
+ const ionModalElement = spectator.component['ionModalElement'];
247
+ expect(ionModalElement.style.top).toBe('');
248
+ expect(ionModalElement.style.left).toBe('');
249
+ expect(ionModalElement.style.right).toBe('');
250
+ }));
251
+
252
+ it('should NOT resize ion-modal to wrapper size on viewport resize', fakeAsync(() => {
253
+ spectator.component['viewportResize'].next();
254
+ spectator.component['viewportResize'].complete();
255
+ tick();
256
+
257
+ const ionModalElement = spectator.component['ionModalElement'];
258
+ expect(ionModalElement.style.top).toBe('');
259
+ expect(ionModalElement.style.left).toBe('');
260
+ expect(ionModalElement.style.right).toBe('');
261
+ }));
262
+ });
263
+
264
+ describe('when flavor is drawer', () => {
265
+ beforeEach(() => {
266
+ spectator = modalWrapperTestBuilder.flavor('drawer').interactWithBackground().build();
267
+ spectator.element.style.height = `${elementHeight}px`;
268
+ spectator.element.style.width = `${elementWidth}px`;
269
+ spectator.element.style.overflow = 'hidden';
270
+ spectator.element.style.position = 'fixed'; // Use 'fixed' instead of 'absolute' to prevent test breaking if test window is scrolled
271
+ spectator.element.style.bottom = '0';
272
+ spectator.element.style.left = `calc(50% - ${elementWidth / 2}px)`; // Simulate horizontally centered modal
273
+ spectator.element.style.backgroundColor = 'charrtreuse'; // Add some background for easier debugging of test
274
+ });
275
+
276
+ afterEach(() => {
277
+ // Ensure any observers are destroyed:
278
+ spectator.fixture.destroy();
279
+ });
280
+
281
+ it('should resize ion-modal to wrapper size after ion-modal has been presented', fakeAsync(() => {
282
+ spectator.component['ionModalDidPresent'].next();
283
+ spectator.component['ionModalDidPresent'].complete();
284
+ tick();
285
+
286
+ const elementRect = spectator.element.getBoundingClientRect();
287
+ const expectedPosition = {
288
+ top: parseInt(screenSize.height) - elementHeight,
289
+ left: elementRect.left,
290
+ right: parseInt(screenSize.width) - scrollbarWidth - elementRect.right,
291
+ };
292
+ const ionModalElement = spectator.component['ionModalElement'];
293
+ expect(ionModalElement.style.top).toBe(`${expectedPosition.top}px`);
294
+ expect(ionModalElement.style.left).toBe(`${expectedPosition.left}px`);
295
+ expect(ionModalElement.style.right).toBe(`${expectedPosition.right}px`);
296
+ }));
297
+
298
+ it('should resize ion-modal to wrapper size on viewport resize', fakeAsync(() => {
299
+ spectator.component['viewportResize'].next();
300
+ spectator.component['viewportResize'].complete();
301
+ tick();
302
+
303
+ const elementRect = spectator.element.getBoundingClientRect();
304
+ const expectedPosition = {
305
+ top: parseInt(screenSize.height) - elementHeight,
306
+ left: elementRect.left,
307
+ right: parseInt(screenSize.width) - scrollbarWidth - elementRect.right,
308
+ };
309
+ const ionModalElement = spectator.component['ionModalElement'];
310
+ expect(ionModalElement.style.top).toBe(`${expectedPosition.top}px`);
311
+ expect(ionModalElement.style.left).toBe(`${expectedPosition.left}px`);
312
+ expect(ionModalElement.style.right).toBe(`${expectedPosition.right}px`);
313
+ }));
314
+ });
315
+ });
316
+
317
+ describe('close button', () => {
318
+ beforeEach(() => {
319
+ spectator = modalWrapperTestBuilder.build();
320
+ });
321
+
322
+ afterEach(() => {
323
+ // Ensure any observers are destroyed:
324
+ spectator.fixture.destroy();
325
+ });
326
+
327
+ it('should render as a close icon by default', () => {
328
+ spectator.component.config.flavor = 'modal';
329
+ spectator.detectChanges();
330
+ var el = spectator.query(IconComponent);
331
+ expect(el.name).toBe('close');
332
+ });
333
+
334
+ it("should render arrow-down when flavor is set to 'drawer'", () => {
335
+ spectator.component.config.flavor = 'drawer';
336
+ spectator.detectChanges();
337
+ var el = spectator.query(IconComponent);
338
+ expect(el.name).toBe('arrow-down');
339
+ });
340
+ });
341
+
342
+ describe('supplementary button', () => {
343
+ beforeEach(() => {
344
+ spectator = modalWrapperTestBuilder.build();
345
+ });
346
+
347
+ afterEach(() => {
348
+ // Ensure any observers are destroyed:
349
+ spectator.fixture.destroy();
350
+ });
351
+
352
+ it('should not render if an icon was provided, but the flavor is modal', () => {
353
+ spectator.component.config.flavor = 'modal';
354
+ spectator.component.config.drawerSupplementaryAction = { iconName: 'qr', action: undefined };
355
+ spectator.detectChanges();
356
+ const elements = spectator.queryAll(IconComponent);
357
+ expect(elements.length).toBe(1);
358
+ expect(elements[0].name).toBe('close');
359
+ });
360
+
361
+ it('should render as the provided icon when flavor is drawer', () => {
362
+ spectator.component.config.flavor = 'drawer';
363
+ spectator.component.config.drawerSupplementaryAction = { iconName: 'qr', action: undefined };
364
+ spectator.detectChanges();
365
+ const elements = spectator.queryAll(IconComponent);
366
+ expect(elements.length).toBe(2);
367
+ expect(elements[0].name).toBe('arrow-down');
368
+ expect(elements[1].name).toBe('qr');
369
+ });
370
+
371
+ it('should invoke the provided callback on select', () => {
372
+ spectator.component.config.flavor = 'drawer';
373
+ spectator.component.config.drawerSupplementaryAction = {
374
+ iconName: 'qr',
375
+ action: (_: any) => {},
376
+ };
377
+ spyOn(spectator.component.config.drawerSupplementaryAction, 'action');
378
+
379
+ spectator.detectChanges();
380
+ spectator.dispatchMouseEvent('ion-buttons[slot="end"] button[kirby-button]', 'click');
381
+ expect(spectator.component.config.drawerSupplementaryAction.action).toHaveBeenCalled();
382
+ });
383
+ });
384
+
385
+ describe('scrollToTop', () => {
386
+ beforeEach(() => {
387
+ spectator = modalWrapperTestBuilder.build();
388
+ });
389
+
390
+ afterEach(() => {
391
+ // Ensure any observers are destroyed:
392
+ spectator.fixture.destroy();
393
+ });
394
+
395
+ it('should scroll to top with no scroll animation duration', () => {
396
+ const ionContent: IonContent = spectator.query(IonContent);
397
+ spyOn(ionContent, 'scrollToTop');
398
+ spectator.component.scrollToTop();
399
+ expect(ionContent.scrollToTop).toHaveBeenCalledWith(0);
400
+ });
401
+
402
+ it('should scroll to top with provided scroll animation duration', () => {
403
+ const animationDuration = KirbyAnimation.Duration.LONG;
404
+ const ionContent: IonContent = spectator.query(IonContent);
405
+ spyOn(ionContent, 'scrollToTop');
406
+
407
+ spectator.component.scrollToTop(animationDuration);
408
+
409
+ expect(ionContent.scrollToTop).toHaveBeenCalledWith(animationDuration);
410
+ });
411
+ });
412
+
413
+ describe('scrollToBottom', () => {
414
+ beforeEach(() => {
415
+ spectator = modalWrapperTestBuilder.build();
416
+ });
417
+
418
+ afterEach(() => {
419
+ // Ensure any observers are destroyed:
420
+ spectator.fixture.destroy();
421
+ });
422
+
423
+ it('should scroll to bottom with no scroll animation duration', () => {
424
+ const ionContent: IonContent = spectator.query(IonContent);
425
+ spyOn(ionContent, 'scrollToBottom');
426
+
427
+ spectator.component.scrollToBottom();
428
+
429
+ expect(ionContent.scrollToBottom).toHaveBeenCalledWith(0);
430
+ });
431
+
432
+ it('should scroll to bottom with provided scroll animation duration', () => {
433
+ const animationDuration = KirbyAnimation.Duration.LONG;
434
+ const ionContent: IonContent = spectator.query(IonContent);
435
+ spyOn(ionContent, 'scrollToBottom');
436
+
437
+ spectator.component.scrollToBottom(animationDuration);
438
+
439
+ expect(ionContent.scrollToBottom).toHaveBeenCalledWith(animationDuration);
440
+ });
441
+ });
442
+
443
+ describe('disable scroll Y', () => {
444
+ beforeEach(() => {
445
+ spectator = modalWrapperTestBuilder.build();
446
+ });
447
+
448
+ afterEach(() => {
449
+ // Ensure any observers are destroyed:
450
+ spectator.fixture.destroy();
451
+ });
452
+
453
+ it('should disable scroll Y', () => {
454
+ const ionContent: IonContent = spectator.query(IonContent);
455
+ spectator.component.scrollDisabled = true;
456
+ expect(ionContent.scrollY).toBeFalse();
457
+ });
458
+ });
459
+
460
+ describe('with embedded page progress component', () => {
461
+ describe('with static page progress', () => {
462
+ beforeEach(() => {
463
+ spectator = modalWrapperTestBuilder.flavor('modal').withStaticPageProgress().build();
464
+ spectator.detectComponentChanges();
465
+ });
466
+
467
+ afterEach(() => {
468
+ // Ensure any observers are destroyed:
469
+ spectator.fixture.destroy();
470
+ });
471
+
472
+ it('should move embedded page progress to wrapper component', () => {
473
+ const ionContentElement = spectator.query('ion-content');
474
+ const ionToolbarElement = spectator.query('ion-toolbar');
475
+ const embeddedComponentElement = ionContentElement.firstElementChild;
476
+ const embeddedPageProgress = embeddedComponentElement.querySelector('kirby-page-progress');
477
+ const pageProgressAsIonToolbarChild =
478
+ ionToolbarElement.querySelector('kirby-page-progress');
479
+
480
+ expect(embeddedPageProgress).toBeNull();
481
+ expect(pageProgressAsIonToolbarChild).not.toBeNull();
482
+ });
483
+ });
484
+
485
+ describe('with dynamic page progress', () => {
486
+ beforeEach(() => {
487
+ spectator = modalWrapperTestBuilder.flavor('modal').withDynamicPageProgress().build();
488
+ spectator.detectComponentChanges();
489
+ });
490
+
491
+ afterEach(() => {
492
+ // Ensure any observers are destroyed:
493
+ spectator.fixture.destroy();
494
+ });
495
+
496
+ it('should move embedded page progress to wrapper component when rendered', async () => {
497
+ const pageProgressContent = spectator.element.querySelector('kirby-page-progress');
498
+ expect(pageProgressContent).toBeNull();
499
+
500
+ const embeddedComponent = spectator.query(DynamicPageProgressEmbeddedComponent);
501
+ embeddedComponent.showPageProgress = true;
502
+ spectator.detectChanges();
503
+ await TestHelper.waitForResizeObserver();
504
+
505
+ const ionContentElement = spectator.query('ion-content');
506
+ const ionToolbarElement = spectator.query('ion-toolbar');
507
+ const embeddedComponentElement = ionContentElement.firstElementChild;
508
+ const embeddedPageProgress = embeddedComponentElement.querySelector('kirby-page-progress');
509
+ const pageProgressAsIonToolbarChild =
510
+ ionToolbarElement.querySelector('kirby-page-progress');
511
+ expect(embeddedPageProgress).toBeNull();
512
+ expect(pageProgressAsIonToolbarChild).not.toBeNull();
513
+ });
514
+
515
+ it('should remove embedded page progress content from wrapper component when not rendered', async () => {
516
+ let pageProgress = spectator.element.querySelector('kirby-page-progress');
517
+ expect(pageProgress).toBeNull();
518
+
519
+ const embeddedComponent = spectator.query(DynamicPageProgressEmbeddedComponent);
520
+ embeddedComponent.showPageProgress = true;
521
+ spectator.detectChanges();
522
+ await TestHelper.waitForResizeObserver();
523
+
524
+ const ionToolbarElement = spectator.query('ion-toolbar');
525
+ let pageProgressAsIonToolbarChild = ionToolbarElement.querySelector('kirby-page-progress');
526
+ expect(pageProgressAsIonToolbarChild).not.toBeNull();
527
+
528
+ embeddedComponent.showPageProgress = false;
529
+ spectator.detectChanges();
530
+
531
+ pageProgressAsIonToolbarChild = ionToolbarElement.querySelector('kirby-page-progress');
532
+ expect(pageProgressAsIonToolbarChild).toBeNull();
533
+ });
534
+ });
535
+ });
536
+
537
+ describe('with embedded component with static footer', () => {
538
+ beforeEach(() => {
539
+ spectator = modalWrapperTestBuilder.withStaticFooter().build();
540
+ spectator.detectChanges();
541
+ });
542
+
543
+ afterEach(() => {
544
+ // Ensure any observers are destroyed:
545
+ spectator.fixture.destroy();
546
+ });
547
+
548
+ it('should move embedded footer to wrapper component', () => {
549
+ const ionContentElement = spectator.query('ion-content');
550
+ const embeddedComponentElement = ionContentElement.firstElementChild;
551
+ const embeddedFooter = embeddedComponentElement.querySelector('kirby-modal-footer');
552
+ expect(embeddedFooter).toBeNull();
553
+ const footerAsWrapperChild = spectator.element.querySelector(':scope > kirby-modal-footer');
554
+ expect(footerAsWrapperChild).not.toBeNull();
555
+ });
556
+
557
+ describe(`should set custom CSS property '--keyboard-offset' on embedded footer`, () => {
558
+ const keyboardHeight = 400;
559
+
560
+ it('to a value', () => {
561
+ const kirbyModalFooter = spectator.element.querySelector<HTMLElement>(
562
+ ':scope > kirby-modal-footer'
563
+ );
564
+ spectator.component._onKeyboardShow(keyboardHeight);
565
+ expect(kirbyModalFooter.style.getPropertyValue('--keyboard-offset')).toBeDefined();
566
+ });
567
+
568
+ it('to 0 when no keyboard overlap', () => {
569
+ const kirbyModalFooter = spectator.element.querySelector(':scope > kirby-modal-footer');
570
+ spectator.element.style.position = 'fixed';
571
+ spectator.element.style.bottom = `${keyboardHeight + 200}px`;
572
+ spectator.component._onKeyboardShow(keyboardHeight);
573
+ const keyboardOverlap = 0;
574
+ expect(kirbyModalFooter).toHaveComputedStyle({
575
+ '--keyboard-offset': `${keyboardOverlap}px`,
576
+ });
577
+ });
578
+
579
+ it('to value of overlap when keyboard overlaps partially', () => {
580
+ const kirbyModalFooter = spectator.element.querySelector(':scope > kirby-modal-footer');
581
+ spectator.element.style.position = 'fixed';
582
+ spectator.element.style.bottom = `${keyboardHeight - 200}px`;
583
+ spectator.component._onKeyboardShow(keyboardHeight);
584
+ const keyboardOverlap = 200;
585
+ expect(kirbyModalFooter).toHaveComputedStyle({
586
+ '--keyboard-offset': `${keyboardOverlap}px`,
587
+ });
588
+ });
589
+
590
+ it('to keyboard height when keyboard overlaps completely', () => {
591
+ const kirbyModalFooter = spectator.element.querySelector(':scope > kirby-modal-footer');
592
+ spectator.element.style.position = 'fixed';
593
+ spectator.element.style.bottom = '0px';
594
+ spectator.component._onKeyboardShow(keyboardHeight);
595
+ const keyboardOverlap = keyboardHeight;
596
+ expect(kirbyModalFooter).toHaveComputedStyle({
597
+ '--keyboard-offset': `${keyboardOverlap}px`,
598
+ });
599
+ });
600
+ });
601
+ });
602
+
603
+ describe('with embedded component with dynamic footer', () => {
604
+ beforeEach(() => {
605
+ spectator = modalWrapperTestBuilder.flavor('modal').withDynamicFooter().build();
606
+ spectator.detectComponentChanges();
607
+ });
608
+
609
+ afterEach(() => {
610
+ // Ensure any observers are destroyed:
611
+ spectator.fixture.destroy();
612
+ });
613
+
614
+ it('should move embedded footer to wrapper component when rendered', async () => {
615
+ const footer = spectator.element.querySelector('kirby-modal-footer');
616
+ expect(footer).toBeNull();
617
+
618
+ const embeddedComponent = spectator.query(DynamicFooterEmbeddedComponent);
619
+ embeddedComponent.showFooter = true;
620
+ spectator.detectChanges();
621
+ await TestHelper.waitForResizeObserver();
622
+
623
+ const ionContentElement = spectator.query('ion-content');
624
+ const embeddedComponentElement = ionContentElement.firstElementChild;
625
+ const embeddedFooter = embeddedComponentElement.querySelector('kirby-modal-footer');
626
+ expect(embeddedFooter).toBeNull();
627
+ const footerAsWrapperChild = spectator.element.querySelector(':scope > kirby-modal-footer');
628
+ expect(footerAsWrapperChild).not.toBeNull();
629
+ });
630
+
631
+ it('should remove embedded footer from wrapper component when not rendered', async () => {
632
+ let footer = spectator.element.querySelector('kirby-modal-footer');
633
+ expect(footer).toBeNull();
634
+
635
+ const embeddedComponent = spectator.query(DynamicFooterEmbeddedComponent);
636
+ embeddedComponent.showFooter = true;
637
+ spectator.detectChanges();
638
+ await TestHelper.waitForResizeObserver();
639
+
640
+ const footerAsWrapperChild = spectator.element.querySelector(':scope > kirby-modal-footer');
641
+ expect(footerAsWrapperChild).not.toBeNull();
642
+
643
+ embeddedComponent.showFooter = false;
644
+ spectator.detectChanges();
645
+ footer = spectator.element.querySelector('kirby-modal-footer');
646
+ expect(footer).toBeNull();
647
+ });
648
+
649
+ it('should render changes to embedded footer inside wrapper component', async () => {
650
+ const footer = spectator.element.querySelector('kirby-modal-footer');
651
+ expect(footer).not.toHaveClass('enabled');
652
+ const embeddedComponent = spectator.query(DynamicFooterEmbeddedComponent);
653
+ embeddedComponent.showFooter = true;
654
+ spectator.detectChanges();
655
+ await TestHelper.waitForResizeObserver();
656
+
657
+ const ionContentElement = spectator.query('ion-content');
658
+ const embeddedComponentElement = ionContentElement.firstElementChild;
659
+ const embeddedFooter = embeddedComponentElement.querySelector('kirby-modal-footer');
660
+ expect(embeddedFooter).toBeNull();
661
+ const footerAsWrapperChild = spectator.element.querySelector(':scope > kirby-modal-footer');
662
+ expect(footerAsWrapperChild).not.toBeNull();
663
+
664
+ embeddedComponent.isEnabled = true;
665
+ spectator.detectChanges();
666
+ expect(footerAsWrapperChild).toHaveClass('enabled');
667
+ });
668
+
669
+ describe(`should set custom CSS property '--keyboard-offset' on embedded footer`, () => {
670
+ const keyboardHeight = 400;
671
+
672
+ beforeEach(async () => {
673
+ const embeddedComponent = spectator.query(DynamicFooterEmbeddedComponent);
674
+ embeddedComponent.showFooter = true;
675
+ spectator.detectChanges();
676
+ await TestHelper.waitForResizeObserver();
677
+ TestHelper.scrollMainWindowToTop();
678
+ });
679
+
680
+ it('to a value', () => {
681
+ const kirbyModalFooter = spectator.element.querySelector<HTMLElement>(
682
+ ':scope > kirby-modal-footer'
683
+ );
684
+ spectator.component._onKeyboardShow(keyboardHeight);
685
+ expect(kirbyModalFooter.style.getPropertyValue('--keyboard-offset')).toBeDefined();
686
+ });
687
+
688
+ it('to 0 when no keyboard overlap', () => {
689
+ const kirbyModalFooter = spectator.element.querySelector(':scope > kirby-modal-footer');
690
+ spectator.element.style.position = 'fixed';
691
+ spectator.element.style.bottom = `${keyboardHeight + 200}px`;
692
+ spectator.component._onKeyboardShow(keyboardHeight);
693
+ const keyboardOverlap = 0;
694
+ expect(kirbyModalFooter).toHaveComputedStyle({
695
+ '--keyboard-offset': `${keyboardOverlap}px`,
696
+ });
697
+ });
698
+
699
+ it('to value of overlap when keyboard overlaps partially', () => {
700
+ const kirbyModalFooter = spectator.element.querySelector(':scope > kirby-modal-footer');
701
+ spectator.element.style.position = 'fixed';
702
+ spectator.element.style.bottom = `${keyboardHeight - 200}px`;
703
+ spectator.component._onKeyboardShow(keyboardHeight);
704
+ const keyboardOverlap = 200;
705
+ expect(kirbyModalFooter).toHaveComputedStyle({
706
+ '--keyboard-offset': `${keyboardOverlap}px`,
707
+ });
708
+ });
709
+
710
+ it('to keyboard height when keyboard overlaps completely', () => {
711
+ const kirbyModalFooter = spectator.element.querySelector(':scope > kirby-modal-footer');
712
+ spectator.element.style.position = 'fixed';
713
+ spectator.element.style.bottom = '0px';
714
+ spectator.component._onKeyboardShow(keyboardHeight);
715
+ const keyboardOverlap = keyboardHeight;
716
+ expect(kirbyModalFooter).toHaveComputedStyle({
717
+ '--keyboard-offset': `${keyboardOverlap}px`,
718
+ });
719
+ });
720
+ });
721
+ });
722
+
723
+ describe(`on keyboard show/hide events`, () => {
724
+ beforeEach(() => {
725
+ spectator = modalWrapperTestBuilder.build();
726
+ });
727
+
728
+ afterEach(() => {
729
+ // Ensure any observers are destroyed:
730
+ spectator.fixture.destroy();
731
+ });
732
+
733
+ it('should set keyboardVisible to true on window:keyboardWillShow', () => {
734
+ const keyboardWillShowEvent = new CustomEvent('keyboardWillShow');
735
+ keyboardWillShowEvent['keyboardHeight'] = 200;
736
+ window.dispatchEvent(keyboardWillShowEvent);
737
+ expect(spectator.component['keyboardVisible']).toBeTrue();
738
+ });
739
+
740
+ it('should set keyboardVisible to true on window:ionKeyboardDidShow', () => {
741
+ const ionKeyboardDidShowEvent = new CustomEvent('ionKeyboardDidShow', {
742
+ detail: { keyboardHeight: 200 },
743
+ });
744
+ window.dispatchEvent(ionKeyboardDidShowEvent);
745
+ expect(spectator.component['keyboardVisible']).toBeTrue();
746
+ });
747
+
748
+ it('should set keyboardVisible to false on window:keyboardWillHide', () => {
749
+ spectator.component['keyboardVisible'] = true;
750
+
751
+ spectator.dispatchFakeEvent(window, 'keyboardWillHide');
752
+
753
+ expect(spectator.component['keyboardVisible']).toBeFalse();
754
+ });
755
+
756
+ it('should set keyboardVisible to false on window:ionKeyboardDidHide', () => {
757
+ spectator.component['keyboardVisible'] = true;
758
+
759
+ spectator.dispatchFakeEvent(window, 'ionKeyboardDidHide');
760
+
761
+ expect(spectator.component['keyboardVisible']).toBeFalse();
762
+ });
763
+
764
+ it('should keep same height, when keyboard is opened', async () => {
765
+ const heightWhenKeyboardClosed = spectator.element.getBoundingClientRect().height;
766
+ const ionKeyboardDidShowEvent = new CustomEvent('ionKeyboardDidShow', {
767
+ detail: { keyboardHeight: 200 },
768
+ });
769
+ window.dispatchEvent(ionKeyboardDidShowEvent);
770
+ expect(spectator.component['keyboardVisible']).toBeTrue();
771
+ const heightWhenKeyboardOpened = spectator.element.getBoundingClientRect().height;
772
+ expect(heightWhenKeyboardClosed).toEqual(heightWhenKeyboardOpened);
773
+ });
774
+ });
775
+
776
+ describe(`onHeaderTouchStart`, () => {
777
+ let ionContent: HTMLIonContentElement;
778
+ let input: HTMLInputElement;
779
+
780
+ beforeEach(async () => {
781
+ spectator = modalWrapperTestBuilder.flavor('drawer').withEmbeddedInputComponent().build();
782
+
783
+ // Ensure ion-content gets height
784
+ // or embedded component won't be visible:
785
+ spectator.element.classList.add('ion-page');
786
+ ionContent = spectator.query('ion-content');
787
+ // If other test specs have imported IonicModule before this test is run,
788
+ // then Ionic components won't be mocked - so ensure ionContent.componentOnReady is run if exists:
789
+ await TestHelper.ionComponentOnReady(ionContent);
790
+
791
+ input = ionContent.querySelector('input');
792
+ spyOn(input, 'blur');
793
+ });
794
+
795
+ afterEach(() => {
796
+ // Ensure any observers are destroyed:
797
+ spectator.fixture.destroy();
798
+ });
799
+
800
+ describe(`when keyboard is NOT visible`, () => {
801
+ beforeEach(() => {
802
+ expect(document.activeElement).not.toEqual(input);
803
+ spectator.dispatchFakeEvent(window, 'keyboardWillHide');
804
+ });
805
+
806
+ it('should not call blurActiveElement', () => {
807
+ const blurActiveElementSpy = spyOn(spectator.component, 'blurActiveElement');
808
+ spectator.dispatchTouchEvent('ion-header', 'touchstart');
809
+ expect(blurActiveElementSpy).not.toHaveBeenCalled();
810
+ });
811
+ });
812
+
813
+ describe(`when keyboard is visible`, () => {
814
+ beforeEach(() => {
815
+ input.focus();
816
+ expect(document.activeElement).toEqual(input);
817
+ spectator.component['_onKeyboardShow'](200);
818
+ });
819
+
820
+ it('should blur document.activeElement when it is an input', () => {
821
+ spectator.dispatchTouchEvent('ion-header', 'touchstart');
822
+ expect(input.blur).toHaveBeenCalled();
823
+ });
824
+
825
+ it('should blur document.activeElement when it is a textarea', () => {
826
+ const textarea = ionContent.querySelector('textarea');
827
+ spyOn(textarea, 'blur');
828
+ textarea.focus();
829
+ expect(document.activeElement).toEqual(textarea);
830
+ spectator.dispatchTouchEvent('ion-header', 'touchstart');
831
+ expect(textarea.blur).toHaveBeenCalled();
832
+ });
833
+
834
+ it('should not blur document.activeElement if not input or textarea', () => {
835
+ const button = ionContent.querySelector('button');
836
+ button.focus();
837
+ expect(document.activeElement).toEqual(button);
838
+ spectator.dispatchTouchEvent('ion-header', 'touchstart');
839
+ expect(input.blur).not.toHaveBeenCalled();
840
+ });
841
+
842
+ it('should not blur document.activeElement if event is from toolbar button', () => {
843
+ spectator.dispatchTouchEvent(
844
+ 'ion-header > ion-toolbar > ion-buttons > button',
845
+ 'touchstart'
846
+ );
847
+ expect(input.blur).not.toHaveBeenCalled();
848
+ });
849
+
850
+ it('should not blur document.activeElement if event is from toolbar button child node', () => {
851
+ spectator.dispatchTouchEvent(
852
+ 'ion-header > ion-toolbar > ion-buttons > button > kirby-icon',
853
+ 'touchstart'
854
+ );
855
+ expect(input.blur).not.toHaveBeenCalled();
856
+ });
857
+ });
858
+ });
859
+
860
+ describe(`close()`, () => {
861
+ beforeEach(() => {
862
+ spectator = modalWrapperTestBuilder.withEmbeddedInputComponent().build();
863
+ });
864
+
865
+ afterEach(() => {
866
+ // Ensure any observers are destroyed:
867
+ spectator.fixture.destroy();
868
+ });
869
+
870
+ it(`should call wrapping ion-modal's dismiss() method immediately`, () => {
871
+ spectator.component.close('test data');
872
+ expect(spectator.component['ionModalElement'].dismiss).toHaveBeenCalledWith('test data');
873
+ });
874
+
875
+ describe(`when keyboard is visible`, () => {
876
+ beforeEach(() => {
877
+ spectator.component['keyboardVisible'] = true;
878
+ });
879
+
880
+ describe(`and viewport is not resized`, () => {
881
+ it(`should call wrapping ion-modal's dismiss() method immediately`, () => {
882
+ spectator.component.close('test data');
883
+ expect(spectator.component['ionModalElement'].dismiss).toHaveBeenCalledWith('test data');
884
+ });
885
+ });
886
+
887
+ describe(`and viewport is resized`, () => {
888
+ beforeEach(async () => {
889
+ // Ensure resizeObserver triggers and initialViewportHeight is set:
890
+ await TestHelper.waitForResizeObserver();
891
+ await TestHelper.whenTrue(() => !!spectator.component['initialViewportHeight']);
892
+ expect(spectator.component['initialViewportHeight']).toBeGreaterThan(0);
893
+
894
+ const keyboardHeight = 300;
895
+ //Mimic native keyboard taking height of window:
896
+ const heightWidthKeyboard = window.innerHeight - keyboardHeight;
897
+ console.log(
898
+ `Mimic native keyboard: (window.innerHeight - keyboardHeight) = (${window.innerHeight} - ${keyboardHeight}) = ${heightWidthKeyboard}px`
899
+ );
900
+ await TestHelper.resizeTestWindow({ height: `${window.innerHeight - keyboardHeight}px` });
901
+
902
+ // Ensure resizeObserver triggers and onViewportResize fires:
903
+ await TestHelper.waitForResizeObserver();
904
+ await TestHelper.whenTrue(() => spectator.component['viewportResized']);
905
+ // Ensure keyboardVisible is true, as Ionic dispatches 'ionKeyboardDidShow' event on viewport resize:
906
+ spectator.component['keyboardVisible'] = true;
907
+ });
908
+
909
+ afterEach(() => {
910
+ // Ensure any observers are destroyed:
911
+ spectator.fixture.destroy();
912
+ TestHelper.resetTestWindow();
913
+ });
914
+
915
+ it(`should blur document.activeElement before calling wrapping ion-modal's dismiss() method`, fakeAsync(() => {
916
+ const ionContent = spectator.query('ion-content');
917
+ // If other test specs have imported IonicModule before this test is run,
918
+ // then Ionic components won't be mocked - so ensure ionContent.componentOnReady is run if exists:
919
+ TestHelper.ionComponentOnReady(ionContent);
920
+
921
+ const input = ionContent.querySelector('input');
922
+ spyOn(input, 'blur');
923
+ input.focus();
924
+ expect(document.activeElement).toEqual(input);
925
+
926
+ spectator.component.close('test data');
927
+ expect(spectator.component['ionModalElement'].dismiss).not.toHaveBeenCalled();
928
+ expect(input.blur).toHaveBeenCalled();
929
+ tick(ModalWrapperComponent.KEYBOARD_HIDE_DELAY_IN_MS);
930
+ expect(spectator.component['ionModalElement'].dismiss).toHaveBeenCalledWith('test data');
931
+ }));
932
+
933
+ it(`should delay before calling wrapping ion-modal's dismiss() method`, fakeAsync(() => {
934
+ spectator.component.close('test data');
935
+ expect(spectator.component['ionModalElement'].dismiss).not.toHaveBeenCalled();
936
+ tick(ModalWrapperComponent.KEYBOARD_HIDE_DELAY_IN_MS);
937
+ expect(spectator.component['ionModalElement'].dismiss).toHaveBeenCalledWith('test data');
938
+ }));
939
+ });
940
+ });
941
+ });
942
+ });