@koobiq/components 20.4.2 → 21.0.1

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 (798) hide show
  1. package/accordion/accordion-trigger.scss +3 -10
  2. package/accordion/accordion.scss +4 -6
  3. package/actions-panel/actions-panel-container.scss +45 -1
  4. package/alert/alert.component.scss +3 -2
  5. package/app-switcher/_app-switcher-theme.scss +0 -4
  6. package/app-switcher/app-switcher-dropdown-app.scss +3 -2
  7. package/app-switcher/app-switcher-dropdown-site.scss +2 -1
  8. package/app-switcher/{kbq-app-switcher-list-item.scss → app-switcher-list-item.scss} +18 -4
  9. package/app-switcher/app-switcher-tokens.scss +15 -0
  10. package/app-switcher/app-switcher.scss +14 -4
  11. package/autocomplete/autocomplete.scss +7 -6
  12. package/badge/badge.component.scss +5 -8
  13. package/breadcrumbs/breadcrumbs.scss +25 -10
  14. package/button/_button-base.scss +30 -7
  15. package/button/_button-theme.scss +16 -0
  16. package/button/button-group.scss +7 -0
  17. package/button/button-tokens.scss +0 -2
  18. package/button/button.scss +34 -2
  19. package/button-toggle/_button-toggle-theme.scss +7 -2
  20. package/button-toggle/button-toggle.scss +65 -15
  21. package/checkbox/_checkbox-theme.scss +4 -3
  22. package/checkbox/checkbox.scss +3 -6
  23. package/clamped-text/clamped-text.scss +6 -2
  24. package/code-block/code-block-tokens.scss +0 -224
  25. package/code-block/code-block.scss +20 -9
  26. package/content-panel/content-panel-aside.scss +3 -2
  27. package/content-panel/content-panel-container.scss +37 -0
  28. package/content-panel/content-panel.scss +4 -3
  29. package/core/highlight/_highlight-theme.scss +3 -1
  30. package/core/option/action-container.scss +2 -2
  31. package/core/option/action.scss +2 -1
  32. package/core/option/option.scss +2 -1
  33. package/core/pop-up/_pop-up.scss +0 -37
  34. package/core/selection/pseudo-checkbox/pseudo-checkbox.scss +5 -10
  35. package/core/styles/_core.scss +3 -0
  36. package/core/styles/_koobiq-theme.scss +5 -6
  37. package/core/styles/common/_animation.scss +44 -16
  38. package/core/styles/common/_groups-mixins.scss +21 -19
  39. package/core/styles/common/_groups.scss +4 -32
  40. package/core/styles/common/_index.scss +0 -2
  41. package/core/styles/common/_link.scss +117 -0
  42. package/core/styles/common/_list.scss +0 -26
  43. package/core/styles/common/_overlay.scss +8 -10
  44. package/core/styles/common/_rtl.scss +0 -14
  45. package/core/styles/common/_select.scss +33 -15
  46. package/core/styles/common/_squircle.scss +63 -0
  47. package/core/styles/common/_tokens.scss +0 -11
  48. package/core/styles/common/_vendor-prefixes.scss +0 -20
  49. package/core/styles/functions/_timing.scss +0 -22
  50. package/core/styles/theming/_scrollbar-theme.scss +6 -1
  51. package/core/styles/theming/_theming.scss +13 -65
  52. package/core/styles/typography/_index.scss +0 -1
  53. package/core/styles/typography/_typography.scss +0 -143
  54. package/core/styles/visual/_body.scss +1 -6
  55. package/core/styles/visual/_layout.scss +0 -12
  56. package/datepicker/calendar-body.scss +3 -1
  57. package/datepicker/calendar-header.scss +0 -1
  58. package/datepicker/datepicker-content.scss +33 -1
  59. package/datepicker/datepicker-toggle.scss +0 -38
  60. package/dl/dl-tokens.scss +10 -0
  61. package/dl/dl.scss +113 -13
  62. package/dropdown/_dropdown-theme.scss +4 -16
  63. package/dropdown/dropdown-item.scss +4 -10
  64. package/dropdown/dropdown.scss +2 -1
  65. package/empty-state/_empty-state-theme.scss +10 -4
  66. package/empty-state/empty-state-tokens.scss +4 -4
  67. package/empty-state/empty-state.scss +4 -0
  68. package/fesm2022/koobiq-components-accordion.mjs +347 -229
  69. package/fesm2022/koobiq-components-accordion.mjs.map +1 -1
  70. package/fesm2022/koobiq-components-actions-panel.mjs +302 -187
  71. package/fesm2022/koobiq-components-actions-panel.mjs.map +1 -1
  72. package/fesm2022/koobiq-components-alert.mjs +39 -39
  73. package/fesm2022/koobiq-components-alert.mjs.map +1 -1
  74. package/fesm2022/koobiq-components-app-switcher.mjs +677 -367
  75. package/fesm2022/koobiq-components-app-switcher.mjs.map +1 -1
  76. package/fesm2022/koobiq-components-autocomplete.mjs +620 -253
  77. package/fesm2022/koobiq-components-autocomplete.mjs.map +1 -1
  78. package/fesm2022/koobiq-components-badge.mjs +46 -48
  79. package/fesm2022/koobiq-components-badge.mjs.map +1 -1
  80. package/fesm2022/koobiq-components-breadcrumbs.mjs +221 -169
  81. package/fesm2022/koobiq-components-breadcrumbs.mjs.map +1 -1
  82. package/fesm2022/koobiq-components-button-toggle.mjs +565 -196
  83. package/fesm2022/koobiq-components-button-toggle.mjs.map +1 -1
  84. package/fesm2022/koobiq-components-button.mjs +332 -116
  85. package/fesm2022/koobiq-components-button.mjs.map +1 -1
  86. package/fesm2022/koobiq-components-checkbox.mjs +172 -132
  87. package/fesm2022/koobiq-components-checkbox.mjs.map +1 -1
  88. package/fesm2022/koobiq-components-clamped-text.mjs +165 -158
  89. package/fesm2022/koobiq-components-clamped-text.mjs.map +1 -1
  90. package/fesm2022/koobiq-components-code-block.mjs +791 -609
  91. package/fesm2022/koobiq-components-code-block.mjs.map +1 -1
  92. package/fesm2022/koobiq-components-content-panel.mjs +260 -143
  93. package/fesm2022/koobiq-components-content-panel.mjs.map +1 -1
  94. package/fesm2022/koobiq-components-core.mjs +4342 -1595
  95. package/fesm2022/koobiq-components-core.mjs.map +1 -1
  96. package/fesm2022/koobiq-components-datepicker.mjs +1713 -1606
  97. package/fesm2022/koobiq-components-datepicker.mjs.map +1 -1
  98. package/fesm2022/koobiq-components-divider.mjs +73 -36
  99. package/fesm2022/koobiq-components-divider.mjs.map +1 -1
  100. package/fesm2022/koobiq-components-dl.mjs +447 -89
  101. package/fesm2022/koobiq-components-dl.mjs.map +1 -1
  102. package/fesm2022/koobiq-components-dropdown.mjs +703 -599
  103. package/fesm2022/koobiq-components-dropdown.mjs.map +1 -1
  104. package/fesm2022/koobiq-components-dynamic-translation.mjs +20 -20
  105. package/fesm2022/koobiq-components-dynamic-translation.mjs.map +1 -1
  106. package/fesm2022/koobiq-components-ellipsis-center.mjs +46 -31
  107. package/fesm2022/koobiq-components-ellipsis-center.mjs.map +1 -1
  108. package/fesm2022/koobiq-components-empty-state.mjs +116 -60
  109. package/fesm2022/koobiq-components-empty-state.mjs.map +1 -1
  110. package/fesm2022/koobiq-components-file-upload.mjs +550 -290
  111. package/fesm2022/koobiq-components-file-upload.mjs.map +1 -1
  112. package/fesm2022/koobiq-components-filter-bar.mjs +2871 -2595
  113. package/fesm2022/koobiq-components-filter-bar.mjs.map +1 -1
  114. package/fesm2022/koobiq-components-flag.mjs +79 -24
  115. package/fesm2022/koobiq-components-flag.mjs.map +1 -1
  116. package/fesm2022/koobiq-components-form-field.mjs +389 -525
  117. package/fesm2022/koobiq-components-form-field.mjs.map +1 -1
  118. package/fesm2022/koobiq-components-icon.mjs +400 -149
  119. package/fesm2022/koobiq-components-icon.mjs.map +1 -1
  120. package/fesm2022/koobiq-components-inline-edit.mjs +429 -212
  121. package/fesm2022/koobiq-components-inline-edit.mjs.map +1 -1
  122. package/fesm2022/koobiq-components-input.mjs +601 -459
  123. package/fesm2022/koobiq-components-input.mjs.map +1 -1
  124. package/fesm2022/koobiq-components-link-deprecated.mjs +196 -0
  125. package/fesm2022/koobiq-components-link-deprecated.mjs.map +1 -0
  126. package/fesm2022/koobiq-components-link.mjs +328 -125
  127. package/fesm2022/koobiq-components-link.mjs.map +1 -1
  128. package/fesm2022/koobiq-components-list.mjs +583 -433
  129. package/fesm2022/koobiq-components-list.mjs.map +1 -1
  130. package/fesm2022/koobiq-components-loader-overlay.mjs +167 -68
  131. package/fesm2022/koobiq-components-loader-overlay.mjs.map +1 -1
  132. package/fesm2022/koobiq-components-markdown.mjs +55 -78
  133. package/fesm2022/koobiq-components-markdown.mjs.map +1 -1
  134. package/fesm2022/koobiq-components-modal.mjs +853 -475
  135. package/fesm2022/koobiq-components-modal.mjs.map +1 -1
  136. package/fesm2022/koobiq-components-navbar.mjs +895 -556
  137. package/fesm2022/koobiq-components-navbar.mjs.map +1 -1
  138. package/fesm2022/koobiq-components-notification-center.mjs +680 -310
  139. package/fesm2022/koobiq-components-notification-center.mjs.map +1 -1
  140. package/fesm2022/koobiq-components-overflow-items.mjs +46 -64
  141. package/fesm2022/koobiq-components-overflow-items.mjs.map +1 -1
  142. package/fesm2022/koobiq-components-popover.mjs +684 -285
  143. package/fesm2022/koobiq-components-popover.mjs.map +1 -1
  144. package/fesm2022/koobiq-components-progress-bar.mjs +87 -33
  145. package/fesm2022/koobiq-components-progress-bar.mjs.map +1 -1
  146. package/fesm2022/koobiq-components-progress-spinner.mjs +52 -43
  147. package/fesm2022/koobiq-components-progress-spinner.mjs.map +1 -1
  148. package/fesm2022/koobiq-components-radio.mjs +450 -231
  149. package/fesm2022/koobiq-components-radio.mjs.map +1 -1
  150. package/fesm2022/koobiq-components-resizer.mjs +127 -21
  151. package/fesm2022/koobiq-components-resizer.mjs.map +1 -1
  152. package/fesm2022/koobiq-components-scrollbar-deprecated.mjs +299 -0
  153. package/fesm2022/koobiq-components-scrollbar-deprecated.mjs.map +1 -0
  154. package/fesm2022/koobiq-components-scrollbar.mjs +745 -222
  155. package/fesm2022/koobiq-components-scrollbar.mjs.map +1 -1
  156. package/fesm2022/koobiq-components-search-expandable.mjs +288 -126
  157. package/fesm2022/koobiq-components-search-expandable.mjs.map +1 -1
  158. package/fesm2022/koobiq-components-select.mjs +883 -693
  159. package/fesm2022/koobiq-components-select.mjs.map +1 -1
  160. package/fesm2022/koobiq-components-sidebar.mjs +207 -88
  161. package/fesm2022/koobiq-components-sidebar.mjs.map +1 -1
  162. package/fesm2022/koobiq-components-sidepanel.mjs +689 -296
  163. package/fesm2022/koobiq-components-sidepanel.mjs.map +1 -1
  164. package/fesm2022/koobiq-components-skeleton.mjs +815 -41
  165. package/fesm2022/koobiq-components-skeleton.mjs.map +1 -1
  166. package/fesm2022/koobiq-components-split-button.mjs +109 -88
  167. package/fesm2022/koobiq-components-split-button.mjs.map +1 -1
  168. package/fesm2022/koobiq-components-splitter-deprecated.mjs +591 -0
  169. package/fesm2022/koobiq-components-splitter-deprecated.mjs.map +1 -0
  170. package/fesm2022/koobiq-components-splitter.mjs +890 -501
  171. package/fesm2022/koobiq-components-splitter.mjs.map +1 -1
  172. package/fesm2022/koobiq-components-table.mjs +63 -49
  173. package/fesm2022/koobiq-components-table.mjs.map +1 -1
  174. package/fesm2022/koobiq-components-tabs.mjs +1062 -603
  175. package/fesm2022/koobiq-components-tabs.mjs.map +1 -1
  176. package/fesm2022/koobiq-components-tags.mjs +886 -733
  177. package/fesm2022/koobiq-components-tags.mjs.map +1 -1
  178. package/fesm2022/koobiq-components-textarea.mjs +213 -185
  179. package/fesm2022/koobiq-components-textarea.mjs.map +1 -1
  180. package/fesm2022/koobiq-components-time-range.mjs +299 -147
  181. package/fesm2022/koobiq-components-time-range.mjs.map +1 -1
  182. package/fesm2022/koobiq-components-timepicker.mjs +233 -245
  183. package/fesm2022/koobiq-components-timepicker.mjs.map +1 -1
  184. package/fesm2022/koobiq-components-timezone.mjs +344 -142
  185. package/fesm2022/koobiq-components-timezone.mjs.map +1 -1
  186. package/fesm2022/koobiq-components-title.mjs +229 -145
  187. package/fesm2022/koobiq-components-title.mjs.map +1 -1
  188. package/fesm2022/koobiq-components-toast.mjs +463 -143
  189. package/fesm2022/koobiq-components-toast.mjs.map +1 -1
  190. package/fesm2022/koobiq-components-toggle.mjs +177 -130
  191. package/fesm2022/koobiq-components-toggle.mjs.map +1 -1
  192. package/fesm2022/koobiq-components-tooltip.mjs +657 -214
  193. package/fesm2022/koobiq-components-tooltip.mjs.map +1 -1
  194. package/fesm2022/koobiq-components-top-bar.mjs +61 -32
  195. package/fesm2022/koobiq-components-top-bar.mjs.map +1 -1
  196. package/fesm2022/koobiq-components-tree-select.mjs +734 -488
  197. package/fesm2022/koobiq-components-tree-select.mjs.map +1 -1
  198. package/fesm2022/koobiq-components-tree.mjs +1700 -617
  199. package/fesm2022/koobiq-components-tree.mjs.map +1 -1
  200. package/fesm2022/koobiq-components-username.mjs +290 -135
  201. package/fesm2022/koobiq-components-username.mjs.map +1 -1
  202. package/file-upload/dropzone.scss +31 -3
  203. package/file-upload/file-upload-tokens.scss +2 -22
  204. package/file-upload/file-upload.scss +6 -0
  205. package/file-upload/multiple-file-upload.component.scss +14 -12
  206. package/file-upload/single-file-upload.component.scss +3 -2
  207. package/filter-bar/filters.scss +7 -0
  208. package/filter-bar/pipes/base-pipe.scss +3 -3
  209. package/filter-bar/pipes/pipe-date.scss +8 -1
  210. package/flag/flag-tokens.scss +22 -0
  211. package/flag/flag.scss +34 -21
  212. package/form-field/{_fiedset-theme.scss → _fieldset-theme.scss} +1 -5
  213. package/form-field/_form-field-theme.scss +4 -9
  214. package/form-field/cleaner.scss +3 -1
  215. package/form-field/fieldset.scss +3 -4
  216. package/form-field/form-field.scss +26 -21
  217. package/form-field/password-toggle.scss +3 -1
  218. package/icon/_icon-button-theme.scss +7 -0
  219. package/icon/_icon-theme.scss +10 -7
  220. package/icon/icon-button.scss +0 -2
  221. package/icon/icon-tokens.scss +12 -9
  222. package/inline-edit/inline-edit.scss +40 -54
  223. package/input/input.scss +4 -0
  224. package/link/{_link-theme.scss → deprecated/_link-theme.scss} +11 -6
  225. package/link/deprecated/link-tokens.scss +27 -0
  226. package/link/link-tokens.scss +6 -25
  227. package/link/link.scss +137 -0
  228. package/list/list.scss +3 -2
  229. package/loader-overlay/_loader-overlay-theme.scss +19 -10
  230. package/loader-overlay/loader-overlay-tokens.scss +0 -2
  231. package/loader-overlay/loader-overlay.scss +7 -1
  232. package/markdown/_markdown-theme.scss +16 -0
  233. package/markdown/markdown-tokens.scss +5 -0
  234. package/markdown/markdown.scss +2 -1
  235. package/modal/_modal-animation.scss +23 -14
  236. package/modal/modal-tokens.scss +2 -1
  237. package/modal/modal.scss +35 -31
  238. package/navbar/_navbar-item_horizontal.scss +8 -6
  239. package/navbar/_navbar-item_vertical.scss +18 -6
  240. package/navbar/_navbar-theme.scss +9 -1
  241. package/navbar/navbar-brand.scss +8 -6
  242. package/navbar/navbar-divider.scss +1 -1
  243. package/navbar/navbar-item.scss +8 -9
  244. package/navbar/navbar-toggle.scss +3 -3
  245. package/navbar/navbar-tokens.scss +14 -0
  246. package/navbar/navbar.scss +1 -2
  247. package/navbar/vertical-navbar.scss +2 -2
  248. package/notification-center/_notification-center-theme.scss +11 -6
  249. package/notification-center/notification-center-tokens.scss +33 -0
  250. package/notification-center/notification-center.scss +58 -20
  251. package/notification-center/notification-item.scss +15 -6
  252. package/package.json +112 -81
  253. package/popover/popover-tokens.scss +0 -2
  254. package/popover/popover.scss +41 -19
  255. package/prebuilt-themes/theme.css +1 -1
  256. package/progress-bar/_progress-bar-theme.scss +20 -3
  257. package/progress-bar/progress-bar-tokens.scss +3 -0
  258. package/progress-bar/progress-bar.scss +36 -8
  259. package/progress-spinner/progress-spinner.scss +4 -3
  260. package/radio/_radio-theme.scss +21 -4
  261. package/radio/radio-tokens.scss +7 -3
  262. package/radio/radio.scss +55 -8
  263. package/schematics/collection.json +415 -18
  264. package/schematics/migrations/accordion-state-saving-default/README.md +60 -0
  265. package/schematics/migrations/accordion-state-saving-default/data.cjs +75 -0
  266. package/schematics/migrations/accordion-state-saving-default/index.cjs +61 -0
  267. package/schematics/migrations/accordion-state-saving-default/schema.json +15 -0
  268. package/schematics/migrations/actions-panel-overlay-container/README.md +35 -0
  269. package/schematics/migrations/actions-panel-overlay-container/data.cjs +47 -0
  270. package/schematics/migrations/actions-panel-overlay-container/index.cjs +55 -0
  271. package/schematics/migrations/actions-panel-overlay-container/schema.json +15 -0
  272. package/schematics/migrations/alert-signals/README.md +13 -7
  273. package/schematics/migrations/alert-signals/{data.js → data.cjs} +3 -0
  274. package/schematics/migrations/alert-signals/index.cjs +221 -0
  275. package/schematics/migrations/angular-animations-removal/README.md +46 -0
  276. package/schematics/migrations/angular-animations-removal/data.cjs +150 -0
  277. package/schematics/migrations/angular-animations-removal/index.cjs +21 -0
  278. package/schematics/migrations/angular-animations-removal/schema.json +15 -0
  279. package/schematics/migrations/app-switcher-signals/README.md +88 -0
  280. package/schematics/migrations/app-switcher-signals/data.cjs +136 -0
  281. package/schematics/migrations/app-switcher-signals/index.cjs +366 -0
  282. package/schematics/migrations/app-switcher-signals/schema.json +20 -0
  283. package/schematics/migrations/autocomplete-panel-width-auto/README.md +2 -2
  284. package/schematics/migrations/autocomplete-panel-width-auto/{index.js → index.cjs} +6 -5
  285. package/schematics/migrations/autocomplete-signals/README.md +92 -0
  286. package/schematics/migrations/autocomplete-signals/data.cjs +149 -0
  287. package/schematics/migrations/autocomplete-signals/index.cjs +707 -0
  288. package/schematics/migrations/autocomplete-signals/schema.json +20 -0
  289. package/schematics/migrations/badge-signals/README.md +77 -0
  290. package/schematics/migrations/badge-signals/data.cjs +109 -0
  291. package/schematics/migrations/badge-signals/index.cjs +694 -0
  292. package/schematics/migrations/badge-signals/schema.json +20 -0
  293. package/schematics/migrations/button-state-and-styles/README.md +129 -0
  294. package/schematics/migrations/button-state-and-styles/data.cjs +136 -0
  295. package/schematics/migrations/button-state-and-styles/index.cjs +221 -0
  296. package/schematics/migrations/button-state-and-styles/schema.json +20 -0
  297. package/schematics/migrations/button-supported-colors/README.md +73 -0
  298. package/schematics/migrations/button-supported-colors/data.cjs +106 -0
  299. package/schematics/migrations/button-supported-colors/index.cjs +261 -0
  300. package/schematics/migrations/button-supported-colors/schema.json +20 -0
  301. package/schematics/migrations/button-toggle-signals-and-aria/README.md +137 -0
  302. package/schematics/migrations/button-toggle-signals-and-aria/data.cjs +200 -0
  303. package/schematics/migrations/button-toggle-signals-and-aria/index.cjs +497 -0
  304. package/schematics/migrations/button-toggle-signals-and-aria/schema.json +20 -0
  305. package/schematics/migrations/button-truncation/README.md +110 -0
  306. package/schematics/migrations/button-truncation/data.cjs +88 -0
  307. package/schematics/migrations/button-truncation/index.cjs +270 -0
  308. package/schematics/migrations/button-truncation/schema.json +20 -0
  309. package/schematics/migrations/checkbox-signals/README.md +76 -0
  310. package/schematics/migrations/checkbox-signals/data.cjs +114 -0
  311. package/schematics/migrations/checkbox-signals/index.cjs +635 -0
  312. package/schematics/migrations/checkbox-signals/schema.json +20 -0
  313. package/schematics/migrations/clamped-text-disclosure/README.md +62 -0
  314. package/schematics/migrations/clamped-text-disclosure/data.cjs +101 -0
  315. package/schematics/migrations/clamped-text-disclosure/index.cjs +60 -0
  316. package/schematics/migrations/clamped-text-disclosure/schema.json +15 -0
  317. package/schematics/migrations/code-block-highlight-js-core/README.md +53 -0
  318. package/schematics/migrations/code-block-highlight-js-core/data.cjs +64 -0
  319. package/schematics/migrations/code-block-highlight-js-core/index.cjs +319 -0
  320. package/schematics/migrations/code-block-highlight-js-core/schema.json +20 -0
  321. package/schematics/migrations/code-block-signals/README.md +84 -0
  322. package/schematics/migrations/code-block-signals/data.cjs +121 -0
  323. package/schematics/migrations/code-block-signals/index.cjs +701 -0
  324. package/schematics/migrations/code-block-signals/schema.json +20 -0
  325. package/schematics/migrations/color-signals/README.md +46 -0
  326. package/schematics/migrations/color-signals/data.cjs +131 -0
  327. package/schematics/migrations/color-signals/index.cjs +20 -0
  328. package/schematics/migrations/color-signals/schema.json +20 -0
  329. package/schematics/migrations/core-mixins-removal/README.md +20 -0
  330. package/schematics/migrations/core-mixins-removal/data.cjs +27 -0
  331. package/schematics/migrations/core-mixins-removal/index.cjs +18 -0
  332. package/schematics/migrations/core-mixins-removal/schema.json +15 -0
  333. package/schematics/migrations/css-selectors/README.md +2 -2
  334. package/schematics/migrations/css-selectors/{index.js → index.cjs} +4 -3
  335. package/schematics/migrations/datepicker-signals/README.md +24 -0
  336. package/schematics/migrations/datepicker-signals/data.cjs +49 -0
  337. package/schematics/migrations/datepicker-signals/index.cjs +18 -0
  338. package/schematics/migrations/datepicker-signals/schema.json +15 -0
  339. package/schematics/migrations/deprecated-icons/README.md +2 -2
  340. package/schematics/migrations/deprecated-icons/{index.js → index.cjs} +8 -7
  341. package/schematics/migrations/design-tokens-v4/README.md +75 -0
  342. package/schematics/migrations/design-tokens-v4/index.cjs +60 -0
  343. package/schematics/migrations/design-tokens-v4/schema.json +15 -0
  344. package/schematics/migrations/divider-signals-and-aria/README.md +47 -0
  345. package/schematics/migrations/divider-signals-and-aria/data.cjs +62 -0
  346. package/schematics/migrations/divider-signals-and-aria/index.cjs +212 -0
  347. package/schematics/migrations/divider-signals-and-aria/schema.json +15 -0
  348. package/schematics/migrations/dl-attribute-coercion/README.md +59 -0
  349. package/schematics/migrations/dl-attribute-coercion/data.cjs +85 -0
  350. package/schematics/migrations/dl-attribute-coercion/index.cjs +162 -0
  351. package/schematics/migrations/dl-attribute-coercion/schema.json +15 -0
  352. package/schematics/migrations/dl-standalone-names/README.md +49 -0
  353. package/schematics/migrations/dl-standalone-names/data.cjs +44 -0
  354. package/schematics/migrations/dl-standalone-names/index.cjs +322 -0
  355. package/schematics/migrations/dl-standalone-names/schema.json +20 -0
  356. package/schematics/migrations/dropdown-demote-overlay/README.md +137 -0
  357. package/schematics/migrations/dropdown-demote-overlay/data.cjs +84 -0
  358. package/schematics/migrations/dropdown-demote-overlay/index.cjs +289 -0
  359. package/schematics/migrations/dropdown-demote-overlay/schema.json +20 -0
  360. package/schematics/migrations/dropdown-signals/README.md +83 -0
  361. package/schematics/migrations/dropdown-signals/data.cjs +152 -0
  362. package/schematics/migrations/dropdown-signals/index.cjs +20 -0
  363. package/schematics/migrations/dropdown-signals/schema.json +20 -0
  364. package/schematics/migrations/empty-state-error-color/README.md +84 -0
  365. package/schematics/migrations/empty-state-error-color/data.cjs +85 -0
  366. package/schematics/migrations/empty-state-error-color/index.cjs +72 -0
  367. package/schematics/migrations/empty-state-error-color/schema.json +15 -0
  368. package/schematics/migrations/empty-state-size-attr/README.md +2 -2
  369. package/schematics/migrations/empty-state-size-attr/{index.js → index.cjs} +6 -5
  370. package/schematics/migrations/file-upload-cva-and-primitives/README.md +70 -0
  371. package/schematics/migrations/file-upload-cva-and-primitives/data.cjs +97 -0
  372. package/schematics/migrations/file-upload-cva-and-primitives/index.cjs +61 -0
  373. package/schematics/migrations/file-upload-cva-and-primitives/schema.json +15 -0
  374. package/schematics/migrations/file-upload-deprecated-outputs/README.md +90 -0
  375. package/schematics/migrations/file-upload-deprecated-outputs/data.cjs +20 -0
  376. package/schematics/migrations/file-upload-deprecated-outputs/index.cjs +71 -0
  377. package/schematics/migrations/file-upload-deprecated-outputs/schema.json +20 -0
  378. package/schematics/migrations/filter-bar-rename-action/README.md +183 -0
  379. package/schematics/migrations/filter-bar-rename-action/data.cjs +151 -0
  380. package/schematics/migrations/filter-bar-rename-action/index.cjs +178 -0
  381. package/schematics/migrations/filter-bar-rename-action/schema.json +20 -0
  382. package/schematics/migrations/filter-bar-signals/README.md +27 -16
  383. package/schematics/migrations/filter-bar-signals/{data.js → data.cjs} +1 -2
  384. package/schematics/migrations/filter-bar-signals/index.cjs +225 -0
  385. package/schematics/migrations/filter-bar-state-saving-default/README.md +53 -0
  386. package/schematics/migrations/filter-bar-state-saving-default/data.cjs +87 -0
  387. package/schematics/migrations/filter-bar-state-saving-default/index.cjs +62 -0
  388. package/schematics/migrations/filter-bar-state-saving-default/schema.json +15 -0
  389. package/schematics/migrations/flag-inner-html/README.md +67 -0
  390. package/schematics/migrations/flag-inner-html/data.cjs +58 -0
  391. package/schematics/migrations/flag-inner-html/index.cjs +62 -0
  392. package/schematics/migrations/flag-inner-html/schema.json +15 -0
  393. package/schematics/migrations/form-field-signals/README.md +125 -0
  394. package/schematics/migrations/form-field-signals/data.cjs +288 -0
  395. package/schematics/migrations/form-field-signals/index.cjs +383 -0
  396. package/schematics/migrations/form-field-signals/schema.json +20 -0
  397. package/schematics/migrations/icon-semantics-and-api/README.md +65 -0
  398. package/schematics/migrations/icon-semantics-and-api/data.cjs +97 -0
  399. package/schematics/migrations/icon-semantics-and-api/index.cjs +65 -0
  400. package/schematics/migrations/icon-semantics-and-api/schema.json +15 -0
  401. package/schematics/migrations/icons-replacement/README.md +5 -5
  402. package/schematics/migrations/icons-replacement/{index.js → index.cjs} +4 -3
  403. package/schematics/migrations/inline-edit-a11y-and-types/README.md +82 -0
  404. package/schematics/migrations/inline-edit-a11y-and-types/data.cjs +117 -0
  405. package/schematics/migrations/inline-edit-a11y-and-types/index.cjs +98 -0
  406. package/schematics/migrations/inline-edit-a11y-and-types/schema.json +20 -0
  407. package/schematics/migrations/input-number-surface/README.md +140 -0
  408. package/schematics/migrations/input-number-surface/data.cjs +135 -0
  409. package/schematics/migrations/input-number-surface/index.cjs +293 -0
  410. package/schematics/migrations/input-number-surface/schema.json +20 -0
  411. package/schematics/migrations/input-signals/README.md +20 -0
  412. package/schematics/migrations/input-signals/data.cjs +30 -0
  413. package/schematics/migrations/input-signals/index.cjs +18 -0
  414. package/schematics/migrations/input-signals/schema.json +15 -0
  415. package/schematics/migrations/link-deprecated-path/README.md +144 -0
  416. package/schematics/migrations/link-deprecated-path/index.cjs +20 -0
  417. package/schematics/migrations/link-deprecated-path/schema.json +20 -0
  418. package/schematics/migrations/link-signals/README.md +71 -0
  419. package/schematics/migrations/link-signals/data.cjs +116 -0
  420. package/schematics/migrations/link-signals/index.cjs +416 -0
  421. package/schematics/migrations/link-signals/schema.json +20 -0
  422. package/schematics/migrations/list-signals/README.md +22 -0
  423. package/schematics/migrations/list-signals/data.cjs +35 -0
  424. package/schematics/migrations/list-signals/index.cjs +18 -0
  425. package/schematics/migrations/list-signals/schema.json +15 -0
  426. package/schematics/migrations/list-tree-multiple-input/README.md +105 -0
  427. package/schematics/migrations/list-tree-multiple-input/data.cjs +74 -0
  428. package/schematics/migrations/list-tree-multiple-input/index.cjs +222 -0
  429. package/schematics/migrations/list-tree-multiple-input/schema.json +20 -0
  430. package/schematics/migrations/loader-overlay-signals/README.md +62 -0
  431. package/schematics/migrations/loader-overlay-signals/data.cjs +101 -0
  432. package/schematics/migrations/loader-overlay-signals/index.cjs +698 -0
  433. package/schematics/migrations/loader-overlay-signals/schema.json +20 -0
  434. package/schematics/migrations/loader-overlay-size-attr/README.md +2 -2
  435. package/schematics/migrations/loader-overlay-size-attr/{index.js → index.cjs} +6 -5
  436. package/schematics/migrations/locale-configuration-providers/README.md +163 -0
  437. package/schematics/migrations/locale-configuration-providers/data.cjs +257 -0
  438. package/schematics/migrations/locale-configuration-providers/index.cjs +295 -0
  439. package/schematics/migrations/locale-configuration-providers/schema.json +20 -0
  440. package/schematics/migrations/mandatory-peer-dependencies/README.md +70 -0
  441. package/schematics/migrations/mandatory-peer-dependencies/index.cjs +43 -0
  442. package/schematics/migrations/mandatory-peer-dependencies/schema.json +15 -0
  443. package/schematics/migrations/markdown-signals/README.md +58 -0
  444. package/schematics/migrations/markdown-signals/data.cjs +79 -0
  445. package/schematics/migrations/markdown-signals/index.cjs +640 -0
  446. package/schematics/migrations/markdown-signals/schema.json +20 -0
  447. package/schematics/migrations/modal-dialog-semantics/README.md +106 -0
  448. package/schematics/migrations/modal-dialog-semantics/data.cjs +110 -0
  449. package/schematics/migrations/modal-dialog-semantics/index.cjs +59 -0
  450. package/schematics/migrations/modal-dialog-semantics/schema.json +15 -0
  451. package/schematics/migrations/modal-signals/README.md +88 -0
  452. package/schematics/migrations/modal-signals/data.cjs +132 -0
  453. package/schematics/migrations/modal-signals/index.cjs +20 -0
  454. package/schematics/migrations/modal-signals/schema.json +20 -0
  455. package/schematics/migrations/navbar-signals-and-aria/README.md +111 -0
  456. package/schematics/migrations/navbar-signals-and-aria/data.cjs +198 -0
  457. package/schematics/migrations/navbar-signals-and-aria/index.cjs +569 -0
  458. package/schematics/migrations/navbar-signals-and-aria/schema.json +20 -0
  459. package/schematics/migrations/new-icons-pack/README.md +10 -10
  460. package/schematics/migrations/new-icons-pack/{index.js → index.cjs} +8 -7
  461. package/schematics/migrations/notification-center-signals/README.md +67 -0
  462. package/schematics/migrations/notification-center-signals/data.cjs +66 -0
  463. package/schematics/migrations/notification-center-signals/index.cjs +62 -0
  464. package/schematics/migrations/notification-center-signals/schema.json +15 -0
  465. package/schematics/migrations/option-signals/README.md +37 -0
  466. package/schematics/migrations/option-signals/data.cjs +86 -0
  467. package/schematics/migrations/option-signals/index.cjs +20 -0
  468. package/schematics/migrations/option-signals/schema.json +20 -0
  469. package/schematics/migrations/popover-leave-delay/README.md +51 -0
  470. package/schematics/migrations/popover-leave-delay/data.cjs +61 -0
  471. package/schematics/migrations/popover-leave-delay/index.cjs +55 -0
  472. package/schematics/migrations/popover-leave-delay/schema.json +15 -0
  473. package/schematics/migrations/progress-bar-percentage-and-aria/README.md +54 -0
  474. package/schematics/migrations/progress-bar-percentage-and-aria/data.cjs +76 -0
  475. package/schematics/migrations/progress-bar-percentage-and-aria/index.cjs +59 -0
  476. package/schematics/migrations/progress-bar-percentage-and-aria/schema.json +15 -0
  477. package/schematics/migrations/progress-spinner-signals/README.md +72 -0
  478. package/schematics/migrations/progress-spinner-signals/data.cjs +83 -0
  479. package/schematics/migrations/progress-spinner-signals/index.cjs +695 -0
  480. package/schematics/migrations/progress-spinner-signals/schema.json +20 -0
  481. package/schematics/migrations/query-list-signals/README.md +32 -0
  482. package/schematics/migrations/query-list-signals/data.cjs +70 -0
  483. package/schematics/migrations/query-list-signals/index.cjs +18 -0
  484. package/schematics/migrations/query-list-signals/schema.json +15 -0
  485. package/schematics/migrations/radio-signals-and-aria/README.md +82 -0
  486. package/schematics/migrations/radio-signals-and-aria/data.cjs +163 -0
  487. package/schematics/migrations/radio-signals-and-aria/index.cjs +40 -0
  488. package/schematics/migrations/radio-signals-and-aria/schema.json +20 -0
  489. package/schematics/migrations/read-state-dwell-handlers/README.md +125 -0
  490. package/schematics/migrations/read-state-dwell-handlers/data.cjs +45 -0
  491. package/schematics/migrations/read-state-dwell-handlers/index.cjs +216 -0
  492. package/schematics/migrations/read-state-dwell-handlers/schema.json +20 -0
  493. package/schematics/migrations/scrollbar-deprecated-path/README.md +128 -0
  494. package/schematics/migrations/scrollbar-deprecated-path/index.cjs +21 -0
  495. package/schematics/migrations/scrollbar-deprecated-path/schema.json +20 -0
  496. package/schematics/migrations/select-signal-inputs/README.md +61 -0
  497. package/schematics/migrations/select-signal-inputs/data.cjs +99 -0
  498. package/schematics/migrations/select-signal-inputs/index.cjs +58 -0
  499. package/schematics/migrations/select-signal-inputs/schema.json +15 -0
  500. package/schematics/migrations/sidepanel-non-modal-behavior/README.md +57 -0
  501. package/schematics/migrations/sidepanel-non-modal-behavior/data.cjs +111 -0
  502. package/schematics/migrations/sidepanel-non-modal-behavior/index.cjs +58 -0
  503. package/schematics/migrations/sidepanel-non-modal-behavior/schema.json +15 -0
  504. package/schematics/migrations/signal-inputs-subclasses/README.md +28 -0
  505. package/schematics/migrations/signal-inputs-subclasses/data.cjs +69 -0
  506. package/schematics/migrations/signal-inputs-subclasses/index.cjs +18 -0
  507. package/schematics/migrations/signal-inputs-subclasses/schema.json +15 -0
  508. package/schematics/migrations/split-button-optional-disabled/README.md +47 -0
  509. package/schematics/migrations/split-button-optional-disabled/data.cjs +53 -0
  510. package/schematics/migrations/split-button-optional-disabled/index.cjs +58 -0
  511. package/schematics/migrations/split-button-optional-disabled/schema.json +15 -0
  512. package/schematics/migrations/splitter-deprecated-path/README.md +136 -0
  513. package/schematics/migrations/splitter-deprecated-path/index.cjs +21 -0
  514. package/schematics/migrations/splitter-deprecated-path/schema.json +20 -0
  515. package/schematics/migrations/state-saving-default/README.md +67 -0
  516. package/schematics/migrations/state-saving-default/data.cjs +88 -0
  517. package/schematics/migrations/state-saving-default/index.cjs +63 -0
  518. package/schematics/migrations/state-saving-default/schema.json +15 -0
  519. package/schematics/migrations/table-cell-content/README.md +55 -0
  520. package/schematics/migrations/table-cell-content/data.cjs +66 -0
  521. package/schematics/migrations/table-cell-content/index.cjs +67 -0
  522. package/schematics/migrations/table-cell-content/schema.json +15 -0
  523. package/schematics/migrations/tabs-signals-and-aria/README.md +93 -0
  524. package/schematics/migrations/tabs-signals-and-aria/data.cjs +139 -0
  525. package/schematics/migrations/tabs-signals-and-aria/index.cjs +66 -0
  526. package/schematics/migrations/tabs-signals-and-aria/schema.json +15 -0
  527. package/schematics/migrations/tag-list-cleaner/README.md +58 -0
  528. package/schematics/migrations/tag-list-cleaner/data.cjs +42 -0
  529. package/schematics/migrations/tag-list-cleaner/index.cjs +197 -0
  530. package/schematics/migrations/tag-list-cleaner/schema.json +20 -0
  531. package/schematics/migrations/tag-slots/README.md +41 -0
  532. package/schematics/migrations/tag-slots/index.cjs +191 -0
  533. package/schematics/migrations/tag-slots/schema.json +20 -0
  534. package/schematics/migrations/tags-signals/README.md +85 -0
  535. package/schematics/migrations/tags-signals/data.cjs +103 -0
  536. package/schematics/migrations/tags-signals/index.cjs +674 -0
  537. package/schematics/migrations/tags-signals/schema.json +20 -0
  538. package/schematics/migrations/textarea-signals/README.md +72 -0
  539. package/schematics/migrations/textarea-signals/data.cjs +121 -0
  540. package/schematics/migrations/textarea-signals/index.cjs +380 -0
  541. package/schematics/migrations/textarea-signals/schema.json +20 -0
  542. package/schematics/migrations/time-range-title-for/README.md +164 -0
  543. package/schematics/migrations/time-range-title-for/data.cjs +139 -0
  544. package/schematics/migrations/time-range-title-for/index.cjs +164 -0
  545. package/schematics/migrations/time-range-title-for/schema.json +20 -0
  546. package/schematics/migrations/timepicker-signals/README.md +78 -0
  547. package/schematics/migrations/timepicker-signals/data.cjs +82 -0
  548. package/schematics/migrations/timepicker-signals/index.cjs +710 -0
  549. package/schematics/migrations/timepicker-signals/schema.json +20 -0
  550. package/schematics/migrations/timezone-grouping-utils/README.md +73 -0
  551. package/schematics/migrations/timezone-grouping-utils/data.cjs +101 -0
  552. package/schematics/migrations/timezone-grouping-utils/index.cjs +65 -0
  553. package/schematics/migrations/timezone-grouping-utils/schema.json +15 -0
  554. package/schematics/migrations/title-encapsulation/README.md +49 -0
  555. package/schematics/migrations/title-encapsulation/data.cjs +69 -0
  556. package/schematics/migrations/title-encapsulation/index.cjs +58 -0
  557. package/schematics/migrations/title-encapsulation/schema.json +15 -0
  558. package/schematics/migrations/toast-stack-and-defaults/README.md +102 -0
  559. package/schematics/migrations/toast-stack-and-defaults/data.cjs +79 -0
  560. package/schematics/migrations/toast-stack-and-defaults/index.cjs +54 -0
  561. package/schematics/migrations/toast-stack-and-defaults/schema.json +15 -0
  562. package/schematics/migrations/tooltip-pointer-events-and-types/README.md +53 -0
  563. package/schematics/migrations/tooltip-pointer-events-and-types/data.cjs +89 -0
  564. package/schematics/migrations/tooltip-pointer-events-and-types/index.cjs +61 -0
  565. package/schematics/migrations/tooltip-pointer-events-and-types/schema.json +15 -0
  566. package/schematics/migrations/top-bar-container-selectors/README.md +111 -0
  567. package/schematics/migrations/top-bar-container-selectors/data.cjs +56 -0
  568. package/schematics/migrations/top-bar-container-selectors/index.cjs +85 -0
  569. package/schematics/migrations/top-bar-container-selectors/schema.json +20 -0
  570. package/schematics/migrations/tree-select-signals/README.md +61 -0
  571. package/schematics/migrations/tree-select-signals/data.cjs +106 -0
  572. package/schematics/migrations/tree-select-signals/index.cjs +59 -0
  573. package/schematics/migrations/tree-select-signals/schema.json +15 -0
  574. package/schematics/migrations/tree-signals/README.md +82 -0
  575. package/schematics/migrations/tree-signals/data.cjs +123 -0
  576. package/schematics/migrations/tree-signals/index.cjs +55 -0
  577. package/schematics/migrations/tree-signals/schema.json +15 -0
  578. package/schematics/migrations/tree-state-saving-default/README.md +66 -0
  579. package/schematics/migrations/tree-state-saving-default/data.cjs +78 -0
  580. package/schematics/migrations/tree-state-saving-default/index.cjs +61 -0
  581. package/schematics/migrations/tree-state-saving-default/schema.json +15 -0
  582. package/schematics/migrations/username-pipe-injection/README.md +59 -0
  583. package/schematics/migrations/username-pipe-injection/data.cjs +78 -0
  584. package/schematics/migrations/username-pipe-injection/index.cjs +59 -0
  585. package/schematics/migrations/username-pipe-injection/schema.json +15 -0
  586. package/schematics/migrations/v20-upgrade/README.md +36 -16
  587. package/schematics/migrations/v20-upgrade/{data.js → data.cjs} +124 -77
  588. package/schematics/migrations/v20-upgrade/index.cjs +19 -0
  589. package/schematics/migrations/v21-upgrade/README.md +271 -0
  590. package/schematics/migrations/v21-upgrade/data.cjs +1371 -0
  591. package/schematics/migrations/v21-upgrade/index.cjs +95 -0
  592. package/schematics/migrations/v21-upgrade/schema.json +20 -0
  593. package/schematics/migrations/zoneless-change-detection/README.md +30 -0
  594. package/schematics/migrations/zoneless-change-detection/data.cjs +29 -0
  595. package/schematics/migrations/zoneless-change-detection/index.cjs +21 -0
  596. package/schematics/migrations/zoneless-change-detection/schema.json +15 -0
  597. package/schematics/migrations.json +401 -6
  598. package/schematics/ng-add/index.cjs +266 -0
  599. package/schematics/ng-add/schema.json +15 -0
  600. package/schematics/utils/{angular-parsing.js → angular-parsing.cjs} +2 -2
  601. package/schematics/utils/deprecated-path-migration.cjs +62 -0
  602. package/schematics/utils/html-config.cjs +148 -0
  603. package/schematics/utils/{icon-migration.js → icon-migration.cjs} +2 -2
  604. package/schematics/utils/list-item-pattern.cjs +16 -0
  605. package/schematics/utils/{package-config.js → package-config.cjs} +3 -32
  606. package/schematics/utils/project-files.cjs +25 -0
  607. package/schematics/utils/replacement-driver.cjs +337 -0
  608. package/schematics/utils/safe-rule.cjs +23 -0
  609. package/schematics/utils/signal-members-migration.cjs +779 -0
  610. package/schematics/utils/tag-patterns.cjs +21 -0
  611. package/schematics/utils/template-ref-access.cjs +155 -0
  612. package/schematics/utils/{typescript.js → typescript.cjs} +1 -1
  613. package/schematics/utils/warn-only-migration.cjs +52 -0
  614. package/schematics/utils/workspace-styles.cjs +123 -0
  615. package/scrollbar/{_scrollbar-component-theme.scss → deprecated/_scrollbar-component-theme.scss} +1 -1
  616. package/scrollbar/{scrollbar.component.scss → deprecated/scrollbar.component.scss} +1 -1
  617. package/scrollbar/native-scrollbar.scss +68 -0
  618. package/scrollbar/scrollbar-tokens.scss +13 -22
  619. package/scrollbar/scrollbar-track.scss +94 -0
  620. package/scrollbar/scrollbar-viewport.scss +33 -0
  621. package/scrollbar/scrollbar.scss +24 -0
  622. package/search-expandable/search-expandable-tokens.scss +4 -0
  623. package/search-expandable/search-expandable.scss +4 -2
  624. package/select/_select-theme.scss +3 -16
  625. package/select/select.scss +0 -6
  626. package/sidebar/sidebar.scss +20 -0
  627. package/sidepanel/_sidepanel-theme.scss +1 -1
  628. package/sidepanel/sidepanel-tokens.scss +7 -1
  629. package/sidepanel/sidepanel.scss +41 -5
  630. package/skeleton/skeleton-presets.scss +350 -0
  631. package/skeleton/skeleton-tokens.scss +127 -0
  632. package/skeleton/skeleton.scss +53 -45
  633. package/split-button/_split-button-theme.scss +4 -4
  634. package/split-button/split-button.scss +2 -6
  635. package/splitter/{_splitter-theme.scss → deprecated/_splitter-theme.scss} +1 -1
  636. package/splitter/deprecated/splitter.scss +51 -0
  637. package/splitter/splitter-tokens.scss +19 -0
  638. package/splitter/splitter.scss +148 -28
  639. package/table/_table-theme.scss +13 -12
  640. package/table/table-tokens.scss +8 -0
  641. package/table/table.scss +47 -22
  642. package/tabs/_tabs-common.scss +14 -14
  643. package/tabs/_tabs-theme.scss +4 -5
  644. package/tabs/tab-body.scss +49 -1
  645. package/tabs/tab-header.scss +2 -1
  646. package/tags/tag-list.scss +4 -0
  647. package/tags/tag.scss +19 -1
  648. package/time-range/time-range.scss +9 -0
  649. package/timezone/timezone-option.component.scss +4 -7
  650. package/timezone/timezone-select.component.scss +3 -0
  651. package/toast/_toast-theme.scss +1 -4
  652. package/toast/toast-container.component.scss +19 -13
  653. package/toast/toast-tokens.scss +12 -6
  654. package/toast/toast.component.scss +42 -19
  655. package/toggle/_toggle-theme.scss +4 -10
  656. package/toggle/toggle.scss +67 -26
  657. package/tooltip/_tooltip-theme.scss +7 -1
  658. package/tooltip/tooltip-tokens.scss +1 -2
  659. package/tooltip/tooltip.scss +55 -9
  660. package/top-bar/top-bar-tokens.scss +13 -2
  661. package/top-bar/top-bar.scss +24 -19
  662. package/tree/_tree-theme.scss +0 -1
  663. package/tree/toggle.scss +5 -9
  664. package/tree/tree-option.scss +2 -4
  665. package/tree/tree-tokens.scss +2 -1
  666. package/tree/tree.scss +3 -5
  667. package/tree-select/_tree-select-theme.scss +4 -15
  668. package/tree-select/tree-select-tokens.scss +16 -0
  669. package/tree-select/tree-select.scss +0 -6
  670. package/{accordion/index.d.ts → types/koobiq-components-accordion.d.ts} +102 -84
  671. package/{actions-panel/index.d.ts → types/koobiq-components-actions-panel.d.ts} +44 -59
  672. package/{alert/index.d.ts → types/koobiq-components-alert.d.ts} +8 -3
  673. package/types/koobiq-components-app-switcher.d.ts +406 -0
  674. package/types/koobiq-components-autocomplete.d.ts +443 -0
  675. package/{badge/index.d.ts → types/koobiq-components-badge.d.ts} +25 -20
  676. package/{breadcrumbs/index.d.ts → types/koobiq-components-breadcrumbs.d.ts} +97 -46
  677. package/types/koobiq-components-button-toggle.d.ts +340 -0
  678. package/types/koobiq-components-button.d.ts +296 -0
  679. package/types/koobiq-components-checkbox.d.ts +172 -0
  680. package/types/koobiq-components-clamped-text.d.ts +184 -0
  681. package/{code-block/index.d.ts → types/koobiq-components-code-block.d.ts} +150 -88
  682. package/{content-panel/index.d.ts → types/koobiq-components-content-panel.d.ts} +81 -25
  683. package/{core/index.d.ts → types/koobiq-components-core.d.ts} +2827 -865
  684. package/{datepicker/index.d.ts → types/koobiq-components-datepicker.d.ts} +161 -116
  685. package/types/koobiq-components-divider.d.ts +43 -0
  686. package/types/koobiq-components-dl.d.ts +235 -0
  687. package/{dropdown/index.d.ts → types/koobiq-components-dropdown.d.ts} +245 -239
  688. package/types/koobiq-components-ellipsis-center.d.ts +85 -0
  689. package/types/koobiq-components-empty-state.d.ts +106 -0
  690. package/{file-upload/index.d.ts → types/koobiq-components-file-upload.d.ts} +214 -107
  691. package/{filter-bar/index.d.ts → types/koobiq-components-filter-bar.d.ts} +410 -495
  692. package/types/koobiq-components-flag.d.ts +68 -0
  693. package/{form-field/index.d.ts → types/koobiq-components-form-field.d.ts} +167 -191
  694. package/types/koobiq-components-icon.d.ts +333 -0
  695. package/{inline-edit/index.d.ts → types/koobiq-components-inline-edit.d.ts} +109 -46
  696. package/types/koobiq-components-input.d.ts +477 -0
  697. package/types/koobiq-components-link-deprecated.d.ts +101 -0
  698. package/types/koobiq-components-link.d.ts +176 -0
  699. package/{list/index.d.ts → types/koobiq-components-list.d.ts} +162 -99
  700. package/types/koobiq-components-loader-overlay.d.ts +101 -0
  701. package/{markdown/index.d.ts → types/koobiq-components-markdown.d.ts} +16 -24
  702. package/types/koobiq-components-modal.d.ts +666 -0
  703. package/types/koobiq-components-navbar.d.ts +569 -0
  704. package/types/koobiq-components-notification-center.d.ts +500 -0
  705. package/{overflow-items/index.d.ts → types/koobiq-components-overflow-items.d.ts} +8 -22
  706. package/types/koobiq-components-popover.d.ts +468 -0
  707. package/types/koobiq-components-progress-bar.d.ts +67 -0
  708. package/{progress-spinner/index.d.ts → types/koobiq-components-progress-spinner.d.ts} +33 -10
  709. package/types/koobiq-components-radio.d.ts +294 -0
  710. package/{resizer/index.d.ts → types/koobiq-components-resizer.d.ts} +37 -2
  711. package/{scrollbar/index.d.ts → types/koobiq-components-scrollbar-deprecated.d.ts} +18 -1
  712. package/types/koobiq-components-scrollbar.d.ts +154 -0
  713. package/types/koobiq-components-search-expandable.d.ts +164 -0
  714. package/{select/index.d.ts → types/koobiq-components-select.d.ts} +360 -167
  715. package/types/koobiq-components-sidebar.d.ts +152 -0
  716. package/types/koobiq-components-sidepanel.d.ts +436 -0
  717. package/types/koobiq-components-skeleton.d.ts +234 -0
  718. package/types/koobiq-components-split-button.d.ts +65 -0
  719. package/{splitter/index.d.ts → types/koobiq-components-splitter-deprecated.d.ts} +44 -1
  720. package/types/koobiq-components-splitter.d.ts +406 -0
  721. package/types/koobiq-components-table.d.ts +44 -0
  722. package/types/koobiq-components-tabs.d.ts +888 -0
  723. package/{tags/index.d.ts → types/koobiq-components-tags.d.ts} +249 -133
  724. package/types/koobiq-components-textarea.d.ts +178 -0
  725. package/{time-range/index.d.ts → types/koobiq-components-time-range.d.ts} +135 -62
  726. package/types/koobiq-components-timepicker.d.ts +223 -0
  727. package/types/koobiq-components-timezone.d.ts +266 -0
  728. package/types/koobiq-components-title.d.ts +184 -0
  729. package/types/koobiq-components-toast.d.ts +289 -0
  730. package/types/koobiq-components-toggle.d.ts +121 -0
  731. package/types/koobiq-components-tooltip.d.ts +610 -0
  732. package/types/koobiq-components-top-bar.d.ts +61 -0
  733. package/types/koobiq-components-tree-select.d.ts +670 -0
  734. package/types/koobiq-components-tree.d.ts +1339 -0
  735. package/types/koobiq-components-username.d.ts +340 -0
  736. package/username/_username-theme.scss +35 -0
  737. package/username/username.scss +10 -34
  738. package/app-switcher/index.d.ts +0 -276
  739. package/autocomplete/index.d.ts +0 -286
  740. package/button/index.d.ts +0 -153
  741. package/button-toggle/index.d.ts +0 -162
  742. package/checkbox/index.d.ts +0 -163
  743. package/clamped-text/index.d.ts +0 -146
  744. package/core/styles/_tokens.scss +0 -7
  745. package/core/styles/common/_clearfix.scss +0 -13
  746. package/core/styles/common/_popup.scss +0 -6
  747. package/core/styles/functions/_index.scss +0 -3
  748. package/core/styles/functions/_number.scss +0 -60
  749. package/core/styles/functions/_string.scss +0 -18
  750. package/core/styles/theming/scrollbar-tokens.scss +0 -25
  751. package/core/styles/typography/_typography-utils.scss +0 -84
  752. package/divider/index.d.ts +0 -20
  753. package/dl/index.d.ts +0 -45
  754. package/ellipsis-center/index.d.ts +0 -71
  755. package/empty-state/index.d.ts +0 -45
  756. package/flag/index.d.ts +0 -44
  757. package/icon/index.d.ts +0 -200
  758. package/input/index.d.ts +0 -354
  759. package/link/index.d.ts +0 -56
  760. package/loader-overlay/index.d.ts +0 -57
  761. package/modal/index.d.ts +0 -339
  762. package/navbar/index.d.ts +0 -372
  763. package/notification-center/index.d.ts +0 -323
  764. package/popover/index.d.ts +0 -182
  765. package/prebuilt-themes/dark-theme.css +0 -1
  766. package/prebuilt-themes/light-theme.css +0 -1
  767. package/progress-bar/index.d.ts +0 -31
  768. package/radio/index.d.ts +0 -203
  769. package/schematics/migrations/alert-signals/index.js +0 -353
  770. package/schematics/migrations/filter-bar-signals/index.js +0 -319
  771. package/schematics/migrations/v20-upgrade/index.js +0 -225
  772. package/schematics/ng-add/index.js +0 -39
  773. package/search-expandable/index.d.ts +0 -101
  774. package/sidebar/index.d.ts +0 -94
  775. package/sidepanel/index.d.ts +0 -272
  776. package/skeleton/index.d.ts +0 -26
  777. package/split-button/index.d.ts +0 -46
  778. package/table/index.d.ts +0 -25
  779. package/tabs/index.d.ts +0 -677
  780. package/textarea/index.d.ts +0 -138
  781. package/timepicker/index.d.ts +0 -197
  782. package/timezone/index.d.ts +0 -125
  783. package/title/index.d.ts +0 -139
  784. package/toast/index.d.ts +0 -178
  785. package/toggle/index.d.ts +0 -104
  786. package/tooltip/index.d.ts +0 -335
  787. package/top-bar/index.d.ts +0 -33
  788. package/tree/index.d.ts +0 -802
  789. package/tree-select/index.d.ts +0 -475
  790. package/username/index.d.ts +0 -194
  791. /package/schematics/migrations/css-selectors/{data.js → data.cjs} +0 -0
  792. /package/schematics/migrations/deprecated-icons/{data.js → data.cjs} +0 -0
  793. /package/schematics/migrations/icons-replacement/{data.js → data.cjs} +0 -0
  794. /package/schematics/migrations/new-icons-pack/{data.js → data.cjs} +0 -0
  795. /package/schematics/utils/{ast.js → ast.cjs} +0 -0
  796. /package/schematics/utils/{messages.js → messages.cjs} +0 -0
  797. /package/{dynamic-translation/index.d.ts → types/koobiq-components-dynamic-translation.d.ts} +0 -0
  798. /package/{index.d.ts → types/koobiq-components.d.ts} +0 -0
@@ -1,43 +1,49 @@
1
- import { FocusMonitor, CdkTrapFocus, A11yModule, ConfigurableFocusTrapFactory, FocusTrapFactory } from '@angular/cdk/a11y';
2
- import { Overlay, OverlayRef, OverlayModule } from '@angular/cdk/overlay';
1
+ import * as i0 from '@angular/core';
2
+ import { Pipe, InjectionToken, inject, signal, computed, Injectable, TemplateRef, Type, Renderer2, EnvironmentInjector, ElementRef, ViewContainerRef, ChangeDetectorRef, Injector, input, model, booleanAttribute, EventEmitter, viewChild, viewChildren, linkedSignal, untracked, isDevMode, afterNextRender, createComponent, ViewEncapsulation, ChangeDetectionStrategy, Component, effect, Directive, DestroyRef, NgModule } from '@angular/core';
3
+ import { FocusMonitor, InputModalityDetector, CdkTrapFocus, A11yModule, ConfigurableFocusTrapFactory, FocusTrapFactory } from '@angular/cdk/a11y';
4
+ import { Overlay, OverlayRef, OverlayConfig, OverlayModule } from '@angular/cdk/overlay';
3
5
  import { _getFocusedElementPierceShadowDom } from '@angular/cdk/platform';
4
6
  import { DOCUMENT, NgTemplateOutlet } from '@angular/common';
5
- import * as i0 from '@angular/core';
6
- import { Pipe, inject, Injectable, Renderer2, EnvironmentInjector, ElementRef, ViewContainerRef, ChangeDetectorRef, output, EventEmitter, viewChild, viewChildren, signal, TemplateRef, Type, Injector, createComponent, Input, Output, ViewEncapsulation, ChangeDetectionStrategy, Component, effect, Directive, InjectionToken, isDevMode, NgModule } from '@angular/core';
7
- import * as i1 from '@koobiq/components/button';
7
+ import { outputFromObservable, takeUntilDestroyed } from '@angular/core/rxjs-interop';
8
+ import * as i2 from '@koobiq/components/button';
8
9
  import { KbqButtonModule } from '@koobiq/components/button';
9
- import * as i4 from '@koobiq/components/core';
10
- import { KbqComponentColors, ESCAPE, ENTER, KbqOverflowShadowContainer, KbqOverflowShadowTop, KbqOverflowShadowBottom } from '@koobiq/components/core';
11
- import * as i2 from '@koobiq/components/icon';
10
+ import * as i1 from '@koobiq/components/core';
11
+ import { kbqAnimationsDisabled, KbqLocaleOverridesDirective, KBQ_A11Y_LOCALE_CONFIGURATION, KbqComponentColors, ESCAPE, ENTER, KbqOverflowShadowContainer, KbqOverflowShadowTop, KbqOverflowShadowBottom } from '@koobiq/components/core';
12
+ import * as i3 from '@koobiq/components/icon';
12
13
  import { KbqIconModule } from '@koobiq/components/icon';
13
- import * as i3 from '@koobiq/components/title';
14
+ import * as i5 from '@koobiq/components/scrollbar';
15
+ import { KbqScrollbarViewport } from '@koobiq/components/scrollbar';
16
+ import * as i4 from '@koobiq/components/title';
14
17
  import { KbqTitleModule, KbqTitleDirective } from '@koobiq/components/title';
15
- import { take, switchMap, filter } from 'rxjs/operators';
18
+ import { take } from 'rxjs/operators';
16
19
  import { Subject } from 'rxjs';
17
20
  import { ComponentPortal } from '@angular/cdk/portal';
18
21
 
19
- /**
20
- * API class that public to users to handle the modal instance.
21
- * KbqModalRef is aim to avoid accessing to the modal instance directly by users.
22
- */
23
- class KbqModalRef {
24
- }
25
-
26
22
  class CssUnitPipe {
23
+ /** Returns `null` for a value that was never set, so the style binding it feeds is cleared. */
27
24
  transform(value, defaultUnit = 'px') {
25
+ if (value === null || value === undefined)
26
+ return null;
28
27
  const formatted = +value;
29
28
  return isNaN(formatted) ? `${value}` : `${formatted}${defaultUnit}`;
30
29
  }
31
- /** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.30", ngImport: i0, type: CssUnitPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
32
- /** @nocollapse */ static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "20.3.30", ngImport: i0, type: CssUnitPipe, isStandalone: true, name: "toCssUnit" }); }
30
+ /** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: CssUnitPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
31
+ /** @nocollapse */ static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.2.25", ngImport: i0, type: CssUnitPipe, isStandalone: true, name: "toCssUnit" }); }
33
32
  }
34
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.30", ngImport: i0, type: CssUnitPipe, decorators: [{
33
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: CssUnitPipe, decorators: [{
35
34
  type: Pipe,
36
35
  args: [{
37
36
  name: 'toCssUnit'
38
37
  }]
39
38
  }] });
40
39
 
40
+ /**
41
+ * API class that public to users to handle the modal instance.
42
+ * KbqModalRef is aim to avoid accessing to the modal instance directly by users.
43
+ */
44
+ class KbqModalRef {
45
+ }
46
+
41
47
  var ModalSize;
42
48
  (function (ModalSize) {
43
49
  ModalSize["Small"] = "small";
@@ -46,13 +52,26 @@ var ModalSize;
46
52
  })(ModalSize || (ModalSize = {}));
47
53
  /**
48
54
  * Duration when perform animations (ms)
49
- * @docs-private
55
+ *
56
+ * @internal
50
57
  */
51
58
  const MODAL_ANIMATE_DURATION = 300;
59
+ /** Injection token exposing the dialog to the directives composed inside it. */
60
+ const KBQ_MODAL = new InjectionToken('KBQ_MODAL');
61
+ /**
62
+ * Options `KbqModalService` passes to the dialog it creates. The dialog reads them as the initial
63
+ * values of its inputs, which is how the imperative path reaches signal inputs at all: a dialog
64
+ * created by the service has no template bindings, so an input keeps its initial value for life.
65
+ * Never provided on the declarative path, where the bindings carry the same values.
66
+ *
67
+ * @docs-private
68
+ */
69
+ const KBQ_MODAL_OPTIONS = new InjectionToken('KBQ_MODAL_OPTIONS');
52
70
 
53
71
  class KbqModalControlService {
54
72
  constructor() {
55
73
  this.parentService = inject(KbqModalControlService, { optional: true, skipSelf: true });
74
+ this.document = inject(DOCUMENT);
56
75
  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
57
76
  // @ts-ignore
58
77
  this.rootOpenModals = this.parentService ? null : [];
@@ -62,6 +81,18 @@ class KbqModalControlService {
62
81
  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
63
82
  // @ts-ignore
64
83
  this.rootRegisteredMetaMap = this.parentService ? null : new Map();
84
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
85
+ // @ts-ignore
86
+ this.rootVisibleModals = this.parentService
87
+ ? null
88
+ : signal([]);
89
+ // Lazy, so the copy a child-level service never reads costs nothing.
90
+ this.rootTopVisibleModal = computed(() => {
91
+ const modals = this.visibleModals();
92
+ return modals.length ? modals[modals.length - 1] : null;
93
+ }, ...(ngDevMode ? [{ debugName: "rootTopVisibleModal" }] : /* istanbul ignore next */ []));
94
+ /** Elements this service took out of the accessibility tree while a dialog is shown. */
95
+ this.inertedElements = [];
65
96
  }
66
97
  // Track singleton afterAllClose through over the injection tree
67
98
  get afterAllClose() {
@@ -71,6 +102,18 @@ class KbqModalControlService {
71
102
  get openModals() {
72
103
  return this.parentService ? this.parentService.openModals : this.rootOpenModals;
73
104
  }
105
+ /**
106
+ * Dialogs currently shown, in the order they were shown. Unlike `openModals` this is updated
107
+ * synchronously, before the opening animation, so the body scroll lock and the stacking rules
108
+ * do not lag 300ms behind the dialog they describe.
109
+ */
110
+ get visibleModals() {
111
+ return this.parentService ? this.parentService.visibleModals : this.rootVisibleModals;
112
+ }
113
+ /** The dialog on top of the stack, i.e. the only one assistive technology should reach. */
114
+ get topVisibleModal() {
115
+ return this.parentService ? this.parentService.topVisibleModal : this.rootTopVisibleModal;
116
+ }
74
117
  // Registered modal for later usage
75
118
  get registeredMetaMap() {
76
119
  return this.parentService ? this.parentService.registeredMetaMap : this.rootRegisteredMetaMap;
@@ -84,6 +127,36 @@ class KbqModalControlService {
84
127
  this.handleMultipleMasks(modalRef);
85
128
  }
86
129
  }
130
+ /**
131
+ * Releases everything the registry holds for a dialog, whether or not it was ever shown.
132
+ * `removeOpenModal` only ever runs for a dialog that reached `afterOpen`, so a dialog created
133
+ * and destroyed without being shown — the normal life of a `<kbq-modal>` in a template nobody
134
+ * triggers — would otherwise stay in the root-level map forever.
135
+ */
136
+ deregisterModal(modalRef) {
137
+ this.setVisible(modalRef, false);
138
+ this.removeOpenModal(modalRef);
139
+ }
140
+ /** Records whether a dialog is shown, synchronously with the visibility change itself. */
141
+ setVisible(modalRef, visible) {
142
+ if (this.parentService) {
143
+ this.parentService.setVisible(modalRef, visible);
144
+ return;
145
+ }
146
+ const modals = this.rootVisibleModals();
147
+ const index = modals.indexOf(modalRef);
148
+ if (visible) {
149
+ if (index > -1)
150
+ return;
151
+ this.rootVisibleModals.set([...modals, modalRef]);
152
+ }
153
+ else {
154
+ if (index === -1)
155
+ return;
156
+ this.rootVisibleModals.set(modals.filter((modal) => modal !== modalRef));
157
+ }
158
+ this.syncBackgroundInert();
159
+ }
87
160
  hasRegistered(modalRef) {
88
161
  return this.registeredMetaMap.has(modalRef);
89
162
  }
@@ -94,84 +167,132 @@ class KbqModalControlService {
94
167
  this.openModals[i].close();
95
168
  }
96
169
  }
170
+ /**
171
+ * Takes the page behind the dialog out of the accessibility tree and the tab order.
172
+ *
173
+ * `aria-modal="true"` is enough for modern screen readers, but it is advisory: `inert` is what
174
+ * actually stops the virtual cursor and the pointer from reaching the page underneath. Only
175
+ * body children that do not contain a shown dialog are marked, so every overlay — the dialogs
176
+ * themselves, dropdowns opened inside them, toasts — stays reachable, and so do live regions.
177
+ */
178
+ syncBackgroundInert() {
179
+ const visible = this.rootVisibleModals();
180
+ if (visible.length) {
181
+ const modalElements = visible.map((modal) => modal.getElement()).filter(Boolean);
182
+ for (const child of Array.from(this.document.body.children)) {
183
+ if (this.inertedElements.includes(child) || child.hasAttribute('inert'))
184
+ continue;
185
+ if (child.hasAttribute('aria-live') || child.querySelector('[aria-live]'))
186
+ continue;
187
+ if (modalElements.some((element) => child.contains(element)))
188
+ continue;
189
+ child.setAttribute('inert', '');
190
+ this.inertedElements.push(child);
191
+ }
192
+ }
193
+ else {
194
+ this.inertedElements.forEach((element) => element.removeAttribute('inert'));
195
+ this.inertedElements = [];
196
+ }
197
+ }
97
198
  removeOpenModal(modalRef) {
98
199
  const index = this.openModals.indexOf(modalRef);
99
200
  if (index > -1) {
100
201
  this.openModals.splice(index, 1);
101
- if (this.hasRegistered(modalRef)) {
102
- const { afterOpenSubscription, afterCloseSubscription } = this.registeredMetaMap.get(modalRef);
103
- afterOpenSubscription.unsubscribe();
104
- afterCloseSubscription.unsubscribe();
105
- this.registeredMetaMap.delete(modalRef);
106
- }
107
- if (!this.openModals.length) {
108
- this.afterAllClose.next();
109
- }
202
+ }
203
+ this.unregister(modalRef);
204
+ if (index > -1 && !this.openModals.length) {
205
+ this.afterAllClose.next();
110
206
  }
111
207
  }
208
+ unregister(modalRef) {
209
+ const meta = this.registeredMetaMap.get(modalRef);
210
+ if (!meta)
211
+ return;
212
+ meta.afterOpenSubscription.unsubscribe();
213
+ meta.afterCloseSubscription.unsubscribe();
214
+ meta.beforeCloseSubscription?.unsubscribe();
215
+ this.registeredMetaMap.delete(modalRef);
216
+ }
112
217
  handleMultipleMasks(modalRef) {
113
218
  const modals = Array.from(this.registeredMetaMap.values()).map((v) => v.modalRef);
114
- if (modals.filter((modal) => modal.kbqVisible).length > 1) {
219
+ if (modals.filter((modal) => modal.kbqVisible()).length > 1) {
115
220
  const visibleModalsWithMask = modals
116
221
  .splice(0, modals.length - 1)
117
- .filter((modal) => modal.kbqVisible && modal.kbqMask);
222
+ .filter((modal) => modal.kbqVisible() && modal.kbqMask());
118
223
  // Trigger leave animation on other masks, then disable them after animation completes
119
224
  visibleModalsWithMask.forEach((modal) => {
120
- setTimeout(() => {
121
- modal.getInstance().animateMaskTo(null);
122
- modal.getInstance().kbqMask = false;
123
- modal.markForCheck();
124
- }, MODAL_ANIMATE_DURATION);
125
225
  modal.getInstance().animateMaskTo('leave');
126
226
  modal.markForCheck();
227
+ this.afterMaskAnimation(modal, () => {
228
+ modal.getInstance().animateMaskTo(null);
229
+ modal.getInstance().setMaskEnabled(false);
230
+ modal.markForCheck();
231
+ });
127
232
  });
128
233
  // On close, restore other masks with enter animation, then reset animation state after it completes
129
- modalRef.beforeClose.subscribe(() => {
234
+ const beforeCloseSubscription = modalRef.beforeClose.subscribe(() => {
235
+ // Invariant with respect to the loop below — the dialog being closed is the same
236
+ // one every time round.
237
+ modalRef.getInstance().animateMaskTo('leave');
238
+ this.afterMaskAnimation(modalRef, () => {
239
+ modalRef.getInstance().animateMaskTo(null);
240
+ modalRef.getInstance().setMaskEnabled(false);
241
+ });
130
242
  visibleModalsWithMask.forEach((modal) => {
131
- setTimeout(() => {
132
- modalRef.getInstance().animateMaskTo(null);
133
- modalRef.getInstance().kbqMask = false;
134
- modal.getInstance().animateMaskTo(null);
135
- modal.markForCheck();
136
- }, MODAL_ANIMATE_DURATION);
137
- modalRef.getInstance().animateMaskTo('leave');
138
- modal.getInstance().kbqMask = true;
243
+ modal.getInstance().setMaskEnabled(true);
139
244
  modal.getInstance().animateMaskTo('enter');
140
245
  modal.markForCheck();
246
+ this.afterMaskAnimation(modal, () => {
247
+ modal.getInstance().animateMaskTo(null);
248
+ modal.markForCheck();
249
+ });
141
250
  });
142
251
  });
252
+ const meta = this.registeredMetaMap.get(modalRef);
253
+ // The closure captures a set of sibling dialogs, so it has to die with the registration.
254
+ if (meta)
255
+ meta.beforeCloseSubscription = beforeCloseSubscription;
143
256
  }
144
257
  }
145
- /** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.30", ngImport: i0, type: KbqModalControlService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
146
- /** @nocollapse */ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.30", ngImport: i0, type: KbqModalControlService, providedIn: 'root' }); }
258
+ /**
259
+ * Runs `fn` once the mask animation of `modal` started just now is over, at once when that dialog has
260
+ * animations disabled: the covered layer would otherwise stay painted under the new one for the whole
261
+ * duration. Read per dialog, whose injector can be below the one of this service.
262
+ */
263
+ afterMaskAnimation(modal, fn) {
264
+ if (modal.getInstance().animationsDisabled) {
265
+ fn();
266
+ return;
267
+ }
268
+ setTimeout(fn, MODAL_ANIMATE_DURATION);
269
+ }
270
+ /** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: KbqModalControlService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
271
+ /** @nocollapse */ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: KbqModalControlService, providedIn: 'root' }); }
147
272
  }
148
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.30", ngImport: i0, type: KbqModalControlService, decorators: [{
273
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: KbqModalControlService, decorators: [{
149
274
  type: Injectable,
150
275
  args: [{ providedIn: 'root' }]
151
276
  }] });
152
277
 
153
- /** @docs-private */
154
- class ModalUtil {
155
- constructor(document) {
156
- this.document = document;
157
- this.lastPosition = { x: -1, y: -1 };
158
- this.listenDocumentClick();
159
- }
160
- getLastClickPosition() {
161
- return this.lastPosition;
162
- }
163
- listenDocumentClick() {
164
- this.document?.addEventListener('click', (event) => {
165
- this.lastPosition = { x: event.clientX, y: event.clientY };
166
- });
167
- }
278
+ /**
279
+ * Classifies a slot value once, so the template dispatches on a value instead of calling a type
280
+ * guard per binding — and so the guards stay out of the component's published surface.
281
+ */
282
+ function slotKind(value) {
283
+ if (value instanceof TemplateRef)
284
+ return 'template';
285
+ if (value instanceof Type)
286
+ return 'component';
287
+ if (Array.isArray(value))
288
+ return value.length > 0 ? 'buttons' : 'none';
289
+ if (typeof value === 'string')
290
+ return value === '' ? 'none' : 'string';
291
+ return 'none';
168
292
  }
169
- /** @docs-private */
170
- const modalUtilObject = new ModalUtil(
171
- // For SSR compatibility
172
- // eslint-disable-next-line no-restricted-globals
173
- typeof document === 'undefined' ? undefined : document);
174
-
293
+ let uniqueIdCounter = 0;
294
+ // `ModalOptions` is the service's contract, not the component's shape: every option is a signal
295
+ // input here, so the two no longer match structurally and the dialog cannot declare it.
175
296
  class KbqModalComponent extends KbqModalRef {
176
297
  constructor() {
177
298
  super(...arguments);
@@ -183,114 +304,213 @@ class KbqModalComponent extends KbqModalRef {
183
304
  this.modalControl = inject(KbqModalControlService);
184
305
  this.changeDetector = inject(ChangeDetectorRef);
185
306
  this.focusMonitor = inject(FocusMonitor);
307
+ this.inputModalityDetector = inject(InputModalityDetector);
308
+ this.injector = inject(Injector);
309
+ /**
310
+ * Whether the dialog and its dim layer move without motion. Read from the dialog's own injector, under
311
+ * `options.injector` when the service opened it.
312
+ *
313
+ * @internal
314
+ */
315
+ this.animationsDisabled = kbqAnimationsDisabled();
316
+ /** Accessible name for the icon-only close button. */
317
+ this.a11yLocaleConfiguration = inject(KbqLocaleOverridesDirective, { self: true }).read('a11y', KBQ_A11Y_LOCALE_CONFIGURATION);
186
318
  this.document = inject(DOCUMENT);
319
+ /**
320
+ * Options `KbqModalService` passed in, or `null` on the declarative path. Every input below
321
+ * takes its initial value from here: a service-created dialog carries no template bindings, so
322
+ * an input it does not bind keeps that initial value for the dialog's whole life.
323
+ */
324
+ this.options = inject(KBQ_MODAL_OPTIONS, { optional: true });
187
325
  this.componentColors = KbqComponentColors;
188
- // TODO: Skipped for migration because:
189
- // This input overrides a field from a superclass, while the superclass field
190
- // is not migrated.
191
- this.kbqModalType = 'default';
192
- this._kbqVisible = false;
193
- this.kbqVisibleChange = output();
194
- // TODO: Skipped for migration because:
195
- // This input overrides a field from a superclass, while the superclass field
196
- // is not migrated.
197
- this.kbqSize = ModalSize.Medium;
198
- // TODO: Skipped for migration because:
199
- // This input overrides a field from a superclass, while the superclass field
200
- // is not migrated.
201
- this.kbqCloseByESC = true;
202
- this._kbqClosable = true;
203
- this._kbqMask = true;
204
- this._kbqMaskClosable = false;
326
+ /** Layout the dialog renders. */
327
+ this.kbqModalType = input(this.options?.kbqModalType ?? 'default', ...(ngDevMode ? [{ debugName: "kbqModalType" }] : /* istanbul ignore next */ []));
328
+ /** The instance of component opened into the dialog. */
329
+ this.kbqComponent = input(this.options?.kbqComponent, ...(ngDevMode ? [{ debugName: "kbqComponent" }] : /* istanbul ignore next */ []));
330
+ /** Body of the dialog: text, a template or a component class. Falls back to `<ng-content>`. */
331
+ // eslint-disable-next-line @typescript-eslint/no-empty-object-type
332
+ this.kbqContent = input(this.options?.kbqContent, ...(ngDevMode ? [{ debugName: "kbqContent" }] : /* istanbul ignore next */ []));
333
+ /** Footer of the dialog: text, a template, or the buttons to render. Default modal ONLY. */
334
+ // eslint-disable-next-line @typescript-eslint/no-empty-object-type
335
+ this.kbqFooter = input(this.options?.kbqFooter, ...(ngDevMode ? [{ debugName: "kbqFooter" }] : /* istanbul ignore next */ []));
336
+ /** Whether the dialog is shown. Two-way bindable as `[(kbqVisible)]`. */
337
+ this.kbqVisible = model(this.options?.kbqVisible ?? false, ...(ngDevMode ? [{ debugName: "kbqVisible" }] : /* istanbul ignore next */ []));
338
+ /** Explicit width, overriding the one `kbqSize` implies. A number is read as pixels. */
339
+ this.kbqWidth = input(this.options?.kbqWidth, ...(ngDevMode ? [{ debugName: "kbqWidth" }] : /* istanbul ignore next */ []));
340
+ /** Width preset. */
341
+ this.kbqSize = input(this.options?.kbqSize ?? ModalSize.Medium, ...(ngDevMode ? [{ debugName: "kbqSize" }] : /* istanbul ignore next */ []));
342
+ /** Extra class names for the full-screen wrapper around the dialog. */
343
+ this.kbqWrapClassName = input(this.options?.kbqWrapClassName, ...(ngDevMode ? [{ debugName: "kbqWrapClassName" }] : /* istanbul ignore next */ []));
344
+ /** Extra class names for the dialog element itself. */
345
+ this.kbqClassName = input(this.options?.kbqClassName, ...(ngDevMode ? [{ debugName: "kbqClassName" }] : /* istanbul ignore next */ []));
346
+ /** Inline styles for the dialog element. */
347
+ this.kbqStyle = input(this.options?.kbqStyle, ...(ngDevMode ? [{ debugName: "kbqStyle" }] : /* istanbul ignore next */ []));
348
+ /** Heading of the dialog. Also becomes its accessible name. */
349
+ // eslint-disable-next-line @typescript-eslint/no-empty-object-type
350
+ this.kbqTitle = input(this.options?.kbqTitle, ...(ngDevMode ? [{ debugName: "kbqTitle" }] : /* istanbul ignore next */ []));
351
+ /** Secondary line under the heading. Also becomes the dialog's accessible description. */
352
+ // eslint-disable-next-line @typescript-eslint/no-empty-object-type
353
+ this.kbqCaption = input(this.options?.kbqCaption, ...(ngDevMode ? [{ debugName: "kbqCaption" }] : /* istanbul ignore next */ []));
354
+ /** Whether <kbd>Escape</kbd> cancels the dialog. */
355
+ this.kbqCloseByESC = input(this.options?.kbqCloseByESC ?? true, { ...(ngDevMode ? { debugName: "kbqCloseByESC" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
356
+ /** Where focus lands when the dialog is shown. */
357
+ this.kbqAutoFocus = input(this.options?.kbqAutoFocus ?? 'first-tabbable', ...(ngDevMode ? [{ debugName: "kbqAutoFocus" }] : /* istanbul ignore next */ []));
358
+ /** Accessible name for a dialog rendered without `kbqTitle` — a confirm or a header-less dialog. */
359
+ this.kbqAriaLabel = input(this.options?.kbqAriaLabel, ...(ngDevMode ? [{ debugName: "kbqAriaLabel" }] : /* istanbul ignore next */ []));
360
+ /** Whether the header renders a close button. */
361
+ this.kbqClosable = input(this.options?.kbqClosable ?? true, { ...(ngDevMode ? { debugName: "kbqClosable" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
362
+ /** Whether the page behind the dialog is dimmed. */
363
+ this.kbqMask = input(this.options?.kbqMask ?? true, { ...(ngDevMode ? { debugName: "kbqMask" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
364
+ /** Whether a click on the dim layer cancels the dialog. */
365
+ this.kbqMaskClosable = input(this.options?.kbqMaskClosable ?? false, { ...(ngDevMode ? { debugName: "kbqMaskClosable" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
366
+ /** Inline styles for the dim layer. */
367
+ this.kbqMaskStyle = input(this.options?.kbqMaskStyle, ...(ngDevMode ? [{ debugName: "kbqMaskStyle" }] : /* istanbul ignore next */ []));
368
+ /** Inline styles for the body element. */
369
+ this.kbqBodyStyle = input(this.options?.kbqBodyStyle, ...(ngDevMode ? [{ debugName: "kbqBodyStyle" }] : /* istanbul ignore next */ []));
370
+ // The emitters stay the source of truth: they back the public `afterOpen`/`beforeClose`/`afterClose`
371
+ // observables and the subscriptions of `ModalBuilderForService`, which `OutputEmitterRef` cannot. The
372
+ // outputs below mirror them for template bindings; `outputFromObservable` subscribes once per listener,
373
+ // so `observed` still tells a bound output.
205
374
  // Trigger when modal open(visible) after animations
206
375
  this.kbqAfterOpen = new EventEmitter();
376
+ /** @docs-private */
377
+ this.kbqAfterOpenOutput = outputFromObservable(this.kbqAfterOpen, { alias: 'kbqAfterOpen' });
207
378
  // Trigger when modal leave-animation over
208
379
  this.kbqAfterClose = new EventEmitter();
380
+ /** @docs-private */
381
+ this.kbqAfterCloseOutput = outputFromObservable(this.kbqAfterClose, { alias: 'kbqAfterClose' });
209
382
  /** Emitted before the modal begins its closing animation. */
210
383
  this.kbqBeforeClose = new EventEmitter();
211
- // TODO: Skipped for migration because:
212
- // This input overrides a field from a superclass, while the superclass field
213
- // is not migrated.
214
- this.kbqOkType = KbqComponentColors.Contrast;
215
- // TODO: Skipped for migration because:
216
- // This input overrides a field from a superclass, while the superclass field
217
- // is not migrated.
218
- this.kbqRestoreFocus = true;
219
- this._kbqOkLoading = false;
220
- // TODO: Skipped for migration because:
221
- // This input overrides a field from a superclass, while the superclass field
222
- // is not migrated.
384
+ /** @docs-private */
385
+ this.kbqBeforeCloseOutput = outputFromObservable(this.kbqBeforeClose, { alias: 'kbqBeforeClose' });
386
+ /** Caption of the predefined OK button. The button is not rendered without it. */
387
+ this.kbqOkText = input(this.options?.kbqOkText, ...(ngDevMode ? [{ debugName: "kbqOkText" }] : /* istanbul ignore next */ []));
388
+ /** Color of the predefined OK button. */
389
+ this.kbqOkType = input(this.options?.kbqOkType ?? KbqComponentColors.Contrast, ...(ngDevMode ? [{ debugName: "kbqOkType" }] : /* istanbul ignore next */ []));
390
+ /** Whether focus returns to the trigger when the dialog closes. */
391
+ this.kbqRestoreFocus = input(this.options?.kbqRestoreFocus ?? true, { ...(ngDevMode ? { debugName: "kbqRestoreFocus" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
392
+ /** Whether the predefined OK button renders its progress state. */
393
+ this.kbqOkLoading = input(this.options?.kbqOkLoading ?? false, { ...(ngDevMode ? { debugName: "kbqOkLoading" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
394
+ /**
395
+ * Decision handler of the predefined OK button. Returning `false` — or a promise of `false` —
396
+ * keeps the dialog open; anything else closes it. Receives the body component instance when the
397
+ * body is a component.
398
+ *
399
+ * Bind this **or** `(kbqOnOk)`, never both: a handler decides the close itself, so the event has
400
+ * nothing left to report and is not emitted. Binding both is reported in development mode.
401
+ */
402
+ this.kbqOkClick = input(this.options?.kbqOkClick, ...(ngDevMode ? [{ debugName: "kbqOkClick" }] : /* istanbul ignore next */ []));
403
+ /**
404
+ * Emits when the predefined OK button is activated. A notification, not a decision — the dialog
405
+ * closes either way. Bind `[kbqOkClick]` instead to decide whether it closes.
406
+ */
223
407
  this.kbqOnOk = new EventEmitter();
224
- this._kbqCancelLoading = false;
225
- // TODO: Skipped for migration because:
226
- // This input overrides a field from a superclass, while the superclass field
227
- // is not migrated.
408
+ /** @docs-private */
409
+ this.kbqOnOkOutput = outputFromObservable(this.kbqOnOk, { alias: 'kbqOnOk' });
410
+ /** Caption of the predefined Cancel button. The button is not rendered without it. */
411
+ this.kbqCancelText = input(this.options?.kbqCancelText, ...(ngDevMode ? [{ debugName: "kbqCancelText" }] : /* istanbul ignore next */ []));
412
+ /** Whether the predefined Cancel button renders its progress state. */
413
+ this.kbqCancelLoading = input(this.options?.kbqCancelLoading ?? false, { ...(ngDevMode ? { debugName: "kbqCancelLoading" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
414
+ /**
415
+ * Decision handler of the predefined Cancel button, the close button, <kbd>Escape</kbd> and the
416
+ * dim layer. Returning `false` — or a promise of `false` — keeps the dialog open.
417
+ *
418
+ * Bind this **or** `(kbqOnCancel)`, never both — see `kbqOkClick`.
419
+ */
420
+ this.kbqCancelClick = input(this.options?.kbqCancelClick, ...(ngDevMode ? [{ debugName: "kbqCancelClick" }] : /* istanbul ignore next */ []));
421
+ /**
422
+ * Emits when the dialog is cancelled, by any of the controls `kbqCancelClick` covers. A
423
+ * notification, not a decision. Bind `[kbqCancelClick]` instead to decide whether it closes.
424
+ */
228
425
  this.kbqOnCancel = new EventEmitter();
426
+ /** @docs-private */
427
+ this.kbqOnCancelOutput = outputFromObservable(this.kbqOnCancel, { alias: 'kbqOnCancel' });
229
428
  this.modalContainer = viewChild.required('modalContainer');
230
429
  this.bodyContainer = viewChild.required('bodyContainer', { read: ViewContainerRef });
231
- // Only aim to focus the ok button that needs to be auto focused
232
- this.autoFocusedButtons = viewChildren('autoFocusedButton', ...(ngDevMode ? [{ debugName: "autoFocusedButtons", read: ElementRef }] : [{ read: ElementRef }]));
233
- // The origin point that animation based on
234
- this.transformOrigin = '0px 0px 0px';
430
+ // Both the scrollable wrap and the body of a predefined layout, so a query for one would flash
431
+ // whichever comes first in the template rather than the one that overflows.
432
+ this.scrollbarViewports = viewChildren(KbqScrollbarViewport, ...(ngDevMode ? [{ debugName: "scrollbarViewports" }] : /* istanbul ignore next */ []));
433
+ this.trapFocus = viewChild.required(CdkTrapFocus);
434
+ this.uniqueId = uniqueIdCounter++;
435
+ /** Id of the element that names the dialog. Rendered on the title of a composed modal too. */
436
+ this.titleId = `kbq-modal-title-${this.uniqueId}`;
437
+ /** Id of the element that describes the dialog. Rendered on the caption of a composed modal too. */
438
+ this.captionId = `kbq-modal-caption-${this.uniqueId}`;
235
439
  /**
236
440
  * Scroll-shadow state published by `KbqModalBody` when the modal content is composed
237
441
  * manually (`kbq-modal-title`/`kbq-modal-body`/`kbq-modal-footer`), so the header/footer
238
442
  * can render matching shadows without a direct template reference between them.
443
+ *
239
444
  * @docs-private
240
445
  */
241
- this.bodyOverflow = signal({ top: false, bottom: false }, ...(ngDevMode ? [{ debugName: "bodyOverflow" }] : []));
242
- // TODO: Skipped for migration because:
243
- // This input overrides a field from a superclass, while the superclass field
244
- // is not migrated.
245
- this.kbqGetContainer = () => this.overlay.create();
246
- }
247
- // TODO: Skipped for migration because:
248
- // Accessor inputs cannot be migrated as they are too complex.
249
- get kbqVisible() {
250
- return this._kbqVisible;
251
- }
252
- set kbqVisible(value) {
253
- this._kbqVisible = value;
254
- }
255
- // TODO: Skipped for migration because:
256
- // Accessor inputs cannot be migrated as they are too complex.
257
- get kbqClosable() {
258
- return this._kbqClosable;
259
- }
260
- set kbqClosable(value) {
261
- this._kbqClosable = value;
262
- }
263
- // TODO: Skipped for migration because:
264
- // Accessor inputs cannot be migrated as they are too complex.
265
- get kbqMask() {
266
- return this._kbqMask;
267
- }
268
- set kbqMask(value) {
269
- this._kbqMask = value;
270
- }
271
- // TODO: Skipped for migration because:
272
- // Accessor inputs cannot be migrated as they are too complex.
273
- get kbqMaskClosable() {
274
- return this._kbqMaskClosable;
275
- }
276
- set kbqMaskClosable(value) {
277
- this._kbqMaskClosable = value;
278
- }
279
- // TODO: Skipped for migration because:
280
- // Accessor inputs cannot be migrated as they are too complex.
281
- get kbqOkLoading() {
282
- return this._kbqOkLoading;
283
- }
284
- set kbqOkLoading(value) {
285
- this._kbqOkLoading = value;
286
- }
287
- // TODO: Skipped for migration because:
288
- // Accessor inputs cannot be migrated as they are too complex.
289
- get kbqCancelLoading() {
290
- return this._kbqCancelLoading;
291
- }
292
- set kbqCancelLoading(value) {
293
- this._kbqCancelLoading = value;
446
+ this.bodyOverflow = signal({ top: false, bottom: false }, ...(ngDevMode ? [{ debugName: "bodyOverflow" }] : /* istanbul ignore next */ []));
447
+ /**
448
+ * Footer buttons with their defaults filled in. `kbqFooter` reports what was bound; this is what
449
+ * the template renders, so the input is never written back over.
450
+ */
451
+ this.footer = computed(() => {
452
+ const footer = this.kbqFooter();
453
+ return Array.isArray(footer) ? this.formatModalButtons(footer) : footer;
454
+ }, ...(ngDevMode ? [{ debugName: "footer" }] : /* istanbul ignore next */ []));
455
+ /** @docs-private */
456
+ this.titleKind = computed(() => slotKind(this.kbqTitle()), ...(ngDevMode ? [{ debugName: "titleKind" }] : /* istanbul ignore next */ []));
457
+ /** @docs-private */
458
+ this.captionKind = computed(() => slotKind(this.kbqCaption()), ...(ngDevMode ? [{ debugName: "captionKind" }] : /* istanbul ignore next */ []));
459
+ /** @docs-private */
460
+ this.contentKind = computed(() => slotKind(this.kbqContent()), ...(ngDevMode ? [{ debugName: "contentKind" }] : /* istanbul ignore next */ []));
461
+ /** @docs-private */
462
+ this.footerKind = computed(() => slotKind(this.footer()), ...(ngDevMode ? [{ debugName: "footerKind" }] : /* istanbul ignore next */ []));
463
+ /** Phase of the open/close animation, which the class list and the hidden state follow. */
464
+ this.animationPhase = signal(null, ...(ngDevMode ? [{ debugName: "animationPhase" }] : /* istanbul ignore next */ []));
465
+ /** Full set of classes for the dialog element. */
466
+ this.containerClasses = computed(() => {
467
+ const phase = this.animationPhase();
468
+ const classes = ['kbq-modal-container', this.kbqClassName(), `kbq-modal_${this.kbqSize()}`];
469
+ if (phase)
470
+ classes.push(`zoom-${phase}`, `zoom-${phase}-active`);
471
+ return classes.filter(Boolean).join(' ');
472
+ }, ...(ngDevMode ? [{ debugName: "containerClasses" }] : /* istanbul ignore next */ []));
473
+ /**
474
+ * Phase of the dim layer's animation. Follows the dialog's own phase, except while
475
+ * `KbqModalControlService` fades the layer of a covered dialog out on its own.
476
+ */
477
+ this.maskPhase = signal(null, ...(ngDevMode ? [{ debugName: "maskPhase" }] : /* istanbul ignore next */ []));
478
+ /**
479
+ * Whether the dim layer is actually painted: the input, overridden while another dialog covers
480
+ * this one. Seeded from the input so re-binding `[kbqMask]` still takes effect.
481
+ *
482
+ * The override exists because `KbqModalControlService` turns the layer of the dialogs underneath
483
+ * a newly opened one off and back on. That orchestration belongs in the dialog, keyed on
484
+ * `KbqModalControlService.topVisibleModal()` the way `inert` already is.
485
+ */
486
+ this.maskEnabled = linkedSignal(() => this.kbqMask(), ...(ngDevMode ? [{ debugName: "maskEnabled" }] : /* istanbul ignore next */ []));
487
+ /** Classes for the dim layer. */
488
+ this.maskAnimationClasses = computed(() => {
489
+ const phase = this.maskPhase();
490
+ return phase ? `fade-${phase} fade-${phase}-active` : '';
491
+ }, ...(ngDevMode ? [{ debugName: "maskAnimationClasses" }] : /* istanbul ignore next */ []));
492
+ /**
493
+ * Progress state the predefined buttons actually render: the input, overridden while a handler's
494
+ * returned promise is pending. Seeded from the input so re-binding it still takes effect.
495
+ */
496
+ this.okLoading = linkedSignal(() => this.kbqOkLoading(), ...(ngDevMode ? [{ debugName: "okLoading" }] : /* istanbul ignore next */ []));
497
+ this.cancelLoading = linkedSignal(() => this.kbqCancelLoading(), ...(ngDevMode ? [{ debugName: "cancelLoading" }] : /* istanbul ignore next */ []));
498
+ this.monitoredContainer = null;
499
+ this.focusMonitorSubscription = null;
500
+ /** Whether a `kbq-modal-title` is composed inside the dialog body. */
501
+ this.composedTitle = false;
502
+ /** Whether a `kbq-modal-caption` is composed inside the dialog body. */
503
+ this.composedCaption = false;
504
+ /** Whether a `kbq-modal-footer` is composed inside the dialog body. */
505
+ this.composedFooter = false;
506
+ this.viewInitialized = false;
507
+ /** Visibility the open/close flow has already run for. See `syncVisibleState`. */
508
+ this.handledVisible = false;
509
+ /** Element or overlay the dialog is rendered into. Read once, on init. */
510
+ this.kbqGetContainer = input(
511
+ // A service-created dialog is already inside an overlay the builder owns, so it must not
512
+ // create one of its own; the declarative path has nowhere to render until it does.
513
+ this.options ? (this.options.kbqGetContainer ?? null) : () => this.overlay.create(), ...(ngDevMode ? [{ debugName: "kbqGetContainer" }] : /* istanbul ignore next */ []));
294
514
  }
295
515
  // Observable alias for kbqAfterOpen
296
516
  get afterOpen() {
@@ -304,45 +524,69 @@ class KbqModalComponent extends KbqModalRef {
304
524
  get afterClose() {
305
525
  return this.kbqAfterClose.asObservable();
306
526
  }
307
- get okText() {
308
- return this.kbqOkText;
309
- }
310
- get cancelText() {
311
- return this.kbqCancelText;
312
- }
313
527
  // Indicate whether this dialog should hidden
314
528
  get hidden() {
315
- return !this.kbqVisible && !this.animationState;
529
+ return !this.kbqVisible() && !this.animationState;
530
+ }
531
+ /** Whether the dialog renders a footer — a predefined button is enough, `kbqFooter` is not required. */
532
+ get hasFooter() {
533
+ return this.composedFooter || !!(this.kbqFooter() || this.kbqOkText() || this.kbqCancelText());
534
+ }
535
+ /** Id of the element naming the dialog, or `null` when there is no title to point at. */
536
+ get ariaLabelledBy() {
537
+ return this.hasTitle() ? this.titleId : null;
538
+ }
539
+ /** Accessible name for a dialog with no title. Never rendered next to `aria-labelledby`. */
540
+ get ariaLabel() {
541
+ return this.hasTitle() ? null : this.kbqAriaLabel() || null;
542
+ }
543
+ /** Id of the caption describing the dialog, or `null` when no caption is rendered. */
544
+ get ariaDescribedBy() {
545
+ return this.hasCaption() ? this.captionId : null;
546
+ }
547
+ /**
548
+ * Whether this dialog is covered by another one. `aria-modal` only hides the page behind the
549
+ * topmost dialog, so every dialog below it is taken out of the accessibility tree and the tab
550
+ * order explicitly.
551
+ */
552
+ get inert() {
553
+ const top = this.modalControl.topVisibleModal();
554
+ return !!top && top !== this;
555
+ }
556
+ /** @docs-private */
557
+ loading(triggerType) {
558
+ return triggerType === 'ok' ? this.okLoading() : this.cancelLoading();
316
559
  }
317
560
  // [NOTE] NOT available when using by service!
318
561
  // Because ngOnChanges never be called when using by service,
319
562
  // here we can't support "kbqContent"(Component) etc. as inputs that initialized dynamically.
320
563
  // BUT: User also can change "kbqContent" dynamically to trigger UI changes
321
- // (provided you don't use Component that needs initializations)
564
+ // (provided you don't use Component that needs initializations)
322
565
  ngOnChanges(changes) {
323
- if (changes.kbqVisible) {
324
- // Do not trigger animation while initializing
325
- this.handleVisibleStateChange(this.kbqVisible, !changes.kbqVisible.firstChange);
326
- }
566
+ // A `model()` reports a write from inside through `ngOnChanges` as well, and that write has
567
+ // already run the flow, so the guard inside is what keeps it from running twice.
568
+ if (changes.kbqVisible)
569
+ this.syncVisibleState(changes.kbqVisible.firstChange);
327
570
  }
328
571
  ngOnInit() {
572
+ const content = this.kbqContent();
573
+ const component = this.kbqComponent();
329
574
  // Create component along without View
330
- if (this.isComponent(this.kbqContent)) {
331
- this.createDynamicComponent(this.kbqContent);
332
- }
333
- // Setup default button options
334
- if (this.isModalButtons(this.kbqFooter)) {
335
- this.kbqFooter = this.formatModalButtons(this.kbqFooter);
575
+ if (slotKind(content) === 'component') {
576
+ this.createDynamicComponent(content);
336
577
  }
337
- if (this.isComponent(this.kbqComponent)) {
338
- this.createDynamicComponent(this.kbqComponent);
578
+ if (component) {
579
+ this.createDynamicComponent(component);
339
580
  }
340
581
  // Place the modal dom to elsewhere
341
- this.container = typeof this.kbqGetContainer === 'function' ? this.kbqGetContainer() : this.kbqGetContainer;
582
+ const container = this.kbqGetContainer();
583
+ this.container = (typeof container === 'function' ? container() : container);
342
584
  if (this.container instanceof HTMLElement) {
343
585
  this.container.appendChild(this.elementRef.nativeElement);
344
586
  }
345
587
  else if (this.container instanceof OverlayRef) {
588
+ // The marker the outside-click filters of other overlays (e.g. `kbq-select`) key off.
589
+ this.container.hostElement.classList.add('kbq-modal-overlay');
346
590
  // NOTE: only attach the dom to overlay, the view container is not changed actually
347
591
  this.container.overlayElement.appendChild(this.elementRef.nativeElement);
348
592
  }
@@ -352,35 +596,51 @@ class KbqModalComponent extends KbqModalRef {
352
596
  ngAfterViewInit() {
353
597
  // If using Component, it is the time to attach View while bodyContainer is ready
354
598
  if (this.contentComponentRef) {
599
+ // In the custom layout the component's host element is inserted straight into
600
+ // `.kbq-modal-content`, so it sits between the dialog and the header, body and footer it
601
+ // composes. The dialog's column layout has to carry through it or the body never
602
+ // becomes the part that gives way.
603
+ if (this.isModalType('custom')) {
604
+ this.contentComponentRef.location.nativeElement.classList.add('kbq-modal-content-host');
605
+ }
355
606
  this.bodyContainer().insert(this.contentComponentRef.hostView);
356
607
  }
357
- this.getElement().getElementsByTagName('button')[0]?.focus();
358
- this.getElement().querySelector('button[autofocus]')?.focus();
608
+ this.viewInitialized = true;
609
+ if (this.kbqVisible()) {
610
+ this.monitorContainer();
611
+ this.focusInitialElement();
612
+ }
359
613
  }
360
614
  ngOnDestroy() {
361
615
  // Created in `ngOnInit` but owned by `bodyContainer` only from `ngAfterViewInit`, so a modal
362
616
  // closed in between would leak it. Destroying an already-destroyed view is a no-op.
363
617
  this.contentComponentRef?.destroy();
618
+ this.focusMonitorSubscription?.unsubscribe();
619
+ if (this.monitoredContainer) {
620
+ this.focusMonitor.stopMonitoring(this.monitoredContainer);
621
+ this.monitoredContainer = null;
622
+ }
623
+ // Release everything the dialog holds globally even when it is torn down while still open:
624
+ // the registry entry, the place in the stack and the body scroll lock.
625
+ this.modalControl.deregisterModal(this);
626
+ this.changeBodyOverflow();
364
627
  if (this.container instanceof OverlayRef) {
365
628
  this.container.dispose();
366
629
  }
367
630
  }
368
631
  open() {
369
- this.focusedElementBeforeOpen = _getFocusedElementPierceShadowDom();
370
- this.previouslyFocusedElementOrigin = this.focusMonitor['_lastFocusOrigin'];
371
- this.focusMonitor
372
- .monitor(this.modalContainer(), true)
373
- .pipe(take(1))
374
- .subscribe(() => this.focusMonitor.stopMonitoring(this.modalContainer()));
375
- this.changeVisibleFromInside(true);
632
+ // Untracked, as `close()`, `triggerOk()` and `triggerCancel()`: called from a consumer's `effect()`, the state
633
+ // read and written on the way — `kbqVisible`, the dialogs shown, the inputs — would make the effect run again on
634
+ // every open and close, and an effect that creates a dialog would create another one at once.
635
+ untracked(() => this.changeVisibleFromInside(true));
376
636
  }
637
+ /**
638
+ * Starts the closing animation and resolves the `afterClose` contract with `result`.
639
+ *
640
+ * Closing an already closed dialog is a no-op: `afterClose` emits once per actual transition.
641
+ */
377
642
  close(result) {
378
- this.changeVisibleFromInside(false, result).then(() => {
379
- if (this.kbqRestoreFocus && this.focusedElementBeforeOpen) {
380
- this.focusMonitor.focusVia(this.focusedElementBeforeOpen, this.previouslyFocusedElementOrigin);
381
- this.focusedElementBeforeOpen = null;
382
- }
383
- });
643
+ untracked(() => this.changeVisibleFromInside(false, result));
384
644
  }
385
645
  // Destroy equals Close
386
646
  destroy(result) {
@@ -390,10 +650,10 @@ class KbqModalComponent extends KbqModalRef {
390
650
  this.changeDetector.markForCheck();
391
651
  }
392
652
  triggerOk() {
393
- this.onClickOkCancel('ok');
653
+ untracked(() => this.onClickOkCancel('ok'));
394
654
  }
395
655
  triggerCancel() {
396
- this.onClickOkCancel('cancel');
656
+ untracked(() => this.onClickOkCancel('cancel'));
397
657
  }
398
658
  getInstance() {
399
659
  return this;
@@ -407,94 +667,135 @@ class KbqModalComponent extends KbqModalRef {
407
667
  getElement() {
408
668
  return this.elementRef && this.elementRef.nativeElement;
409
669
  }
410
- getKbqFooter() {
411
- return this.getElement().getElementsByClassName('kbq-modal-footer').item(0);
670
+ /** Announces that a `kbq-modal-title` is composed inside the dialog. @docs-private */
671
+ registerTitle() {
672
+ this.composedTitle = true;
673
+ }
674
+ /** Announces that a `kbq-modal-caption` is composed inside the dialog. @docs-private */
675
+ registerCaption() {
676
+ this.composedCaption = true;
677
+ }
678
+ /** Announces that a `kbq-modal-footer` is composed inside the dialog. @docs-private */
679
+ registerFooter() {
680
+ this.composedFooter = true;
681
+ }
682
+ /** Publishes the composed body's scroll-shadow state. @docs-private */
683
+ setBodyOverflow(state) {
684
+ this.bodyOverflow.set(state);
685
+ }
686
+ /**
687
+ * Drives the dim layer's animation on its own, which is what lets `KbqModalControlService` fade
688
+ * out the layer of a dialog another one has covered.
689
+ *
690
+ * @docs-private
691
+ */
692
+ animateMaskTo(state) {
693
+ // The phase classes are the layer's whole motion, so leaving them off is what disables it.
694
+ this.maskPhase.set(this.animationsDisabled ? null : state);
695
+ }
696
+ /**
697
+ * Turns the dim layer off or back on without touching `kbqMask`, so a dialog covered by another
698
+ * one stops painting its own layer. See `maskEnabled`.
699
+ *
700
+ * @docs-private
701
+ */
702
+ setMaskEnabled(enabled) {
703
+ this.maskEnabled.set(enabled);
704
+ }
705
+ /** @docs-private */
706
+ isMaskEnabled() {
707
+ return this.maskEnabled();
708
+ }
709
+ // AoT
710
+ onClickCloseBtn() {
711
+ if (this.kbqVisible()) {
712
+ this.onClickOkCancel('cancel');
713
+ }
412
714
  }
715
+ /** @docs-private */
413
716
  onClickMask($event) {
414
717
  // Only the primary button closes the modal: the sidepanel's backdrop is driven by `click`, which
415
718
  // never fires for the right or middle button, and `mousedown` here would otherwise diverge from it.
416
719
  if ($event.button !== 0)
417
720
  return;
418
- if (this.kbqMask &&
419
- this.kbqMaskClosable &&
721
+ if (this.kbqMask() &&
722
+ this.kbqMaskClosable() &&
420
723
  $event.target.classList.contains('kbq-modal-wrap') &&
421
- this.kbqVisible) {
724
+ this.kbqVisible()) {
422
725
  this.onClickOkCancel('cancel');
423
726
  }
424
727
  }
728
+ /** @docs-private */
425
729
  isModalType(type) {
426
- return this.kbqModalType === type;
730
+ return this.kbqModalType() === type;
427
731
  }
732
+ /** @docs-private */
428
733
  onKeyDown(event) {
429
- if (event.keyCode === ESCAPE && this.container && this.container instanceof OverlayRef) {
430
- this.close();
431
- event.preventDefault();
734
+ if (event.keyCode === ESCAPE) {
735
+ // A control inside the dialog consumed the key to close a popup of its own, such as a calendar.
736
+ if (event.defaultPrevented)
737
+ return;
738
+ // One implementation for both entry paths: the event only reaches the host from inside
739
+ // the dialog, so it cannot be the keystroke that opened it. Escape is the Cancel
740
+ // button, veto included.
741
+ if (this.kbqCloseByESC() && this.kbqVisible()) {
742
+ this.onClickOkCancel('cancel');
743
+ event.preventDefault();
744
+ }
745
+ return;
432
746
  }
433
747
  if (event.ctrlKey && event.keyCode === ENTER) {
434
- if (this.kbqModalType === 'confirm') {
748
+ if (this.kbqModalType() === 'confirm') {
435
749
  this.triggerOk();
436
750
  }
437
751
  this.getElement().querySelector('[kbq-modal-main-action]')?.click();
438
752
  event.preventDefault();
439
753
  }
440
754
  }
441
- // AoT
442
- onClickCloseBtn() {
443
- if (this.kbqVisible) {
444
- this.onClickOkCancel('cancel');
445
- }
446
- }
447
- // AoT
755
+ /** @docs-private */
448
756
  onClickOkCancel(type) {
449
757
  this.handleCloseResult(type, (doClose) => doClose !== false);
450
758
  }
759
+ /** @docs-private */
451
760
  // eslint-disable-next-line @typescript-eslint/no-empty-object-type
452
761
  handleCloseResult(triggerType, canClose) {
453
- const trigger = { ok: this.kbqOnOk, cancel: this.kbqOnCancel }[triggerType];
454
- const loadingKey = { ok: 'kbqOkLoading', cancel: 'kbqCancelLoading' }[triggerType];
455
- if (trigger instanceof EventEmitter) {
456
- trigger.emit(this.getContentComponent());
762
+ const handler = triggerType === 'ok' ? this.kbqOkClick() : this.kbqCancelClick();
763
+ const emitter = triggerType === 'ok' ? this.kbqOnOk : this.kbqOnCancel;
764
+ const loading = triggerType === 'ok' ? this.okLoading : this.cancelLoading;
765
+ // Users can return "false" to prevent closing by default
766
+ // eslint-disable-next-line @typescript-eslint/no-empty-object-type
767
+ const caseClose = (doClose) => canClose(doClose) && this.close(doClose);
768
+ if (!handler) {
769
+ emitter.emit(this.getContentComponent());
770
+ caseClose(undefined);
771
+ return;
772
+ }
773
+ if (isDevMode() && emitter.observed) {
774
+ const input = triggerType === 'ok' ? 'kbqOkClick' : 'kbqCancelClick';
775
+ const output = triggerType === 'ok' ? 'kbqOnOk' : 'kbqOnCancel';
776
+ // eslint-disable-next-line no-console
777
+ console.warn(`KbqModal: both [${input}] and (${output}) are bound. The handler decides the close, ` +
778
+ `so (${output}) is never emitted. Bind one of them.`);
457
779
  }
458
- else if (typeof trigger === 'function') {
459
- const result = trigger(this.getContentComponent());
460
- // Users can return "false" to prevent closing by default
780
+ const result = handler(this.getContentComponent());
781
+ if (isPromise(result)) {
782
+ loading.set(true);
461
783
  // eslint-disable-next-line @typescript-eslint/no-empty-object-type
462
- const caseClose = (doClose) => canClose(doClose) && this.close(doClose);
463
- if (isPromise(result)) {
464
- this[loadingKey] = true;
465
- const handleThen = (doClose) => {
466
- this[loadingKey] = false;
467
- caseClose(doClose);
468
- };
469
- result.then(handleThen).catch(handleThen);
470
- }
471
- else {
472
- caseClose(result);
473
- }
784
+ const handleThen = (doClose) => {
785
+ loading.set(false);
786
+ caseClose(doClose);
787
+ };
788
+ result.then(handleThen).catch(handleThen);
789
+ }
790
+ else {
791
+ caseClose(result);
474
792
  }
475
793
  }
476
- // AoT
477
- // eslint-disable-next-line @typescript-eslint/no-empty-object-type
478
- isNonEmptyString(value) {
479
- return typeof value === 'string' && value !== '';
480
- }
481
- // AoT
482
- // eslint-disable-next-line @typescript-eslint/no-empty-object-type
483
- isTemplateRef(value) {
484
- return value instanceof TemplateRef;
485
- }
486
- // AoT
487
- // eslint-disable-next-line @typescript-eslint/no-empty-object-type
488
- isComponent(value) {
489
- return value instanceof Type;
490
- }
491
- // AoT
492
- // eslint-disable-next-line @typescript-eslint/no-empty-object-type
493
- isModalButtons(value) {
494
- return Array.isArray(value) && value.length > 0;
495
- }
496
- // Lookup a button's property, if the prop is a function, call & then return the result, otherwise, return itself.
497
- // AoT
794
+ /**
795
+ * Lookup a button's property, if the prop is a function, call & then return the result, otherwise, return itself.
796
+ *
797
+ * @docs-private
798
+ */
498
799
  // eslint-disable-next-line @typescript-eslint/no-empty-object-type
499
800
  getButtonCallableProp(options, prop) {
500
801
  const value = options[prop];
@@ -504,17 +805,11 @@ class KbqModalComponent extends KbqModalRef {
504
805
  }
505
806
  return typeof value === 'function' ? value.apply(options, args) : value;
506
807
  }
507
- /** Returns the full set of classes for the modal container: base, custom class name, size and animation classes. */
508
- getContainerClasses() {
509
- const classes = ['kbq-modal-container', this.kbqClassName, `kbq-modal_${this.kbqSize}`];
510
- if (this.modalAnimationClassMap) {
511
- const animationClasses = this.modalAnimationClassMap;
512
- classes.push(...Object.keys(animationClasses).filter((key) => animationClasses[key]));
513
- }
514
- return classes.filter(Boolean).join(' ');
515
- }
516
- // On kbqFooter's modal button click
517
- // AoT
808
+ /**
809
+ * On kbqFooter's modal button click.
810
+ *
811
+ * @docs-private
812
+ */
518
813
  onButtonClick(button) {
519
814
  // Call onClick directly
520
815
  const result = this.getButtonCallableProp(button, 'onClick');
@@ -524,62 +819,150 @@ class KbqModalComponent extends KbqModalRef {
524
819
  result.then(() => (button.loading = false)).catch(() => (button.loading = false));
525
820
  }
526
821
  }
527
- /**
528
- * Sets mask animation classes for the given state, or clears them if state is null.
529
- * @docs-private
530
- */
531
- animateMaskTo(state) {
532
- this.maskAnimationClassMap = state
533
- ? {
534
- [`fade-${state}`]: true,
535
- [`fade-${state}-active`]: true
536
- }
537
- : null;
822
+ /** Whether anything is rendered that can name the dialog. */
823
+ hasTitle() {
824
+ return this.composedTitle || (this.isModalType('default') && !!this.kbqTitle());
825
+ }
826
+ /** Whether anything is rendered that can describe the dialog. */
827
+ hasCaption() {
828
+ return this.composedCaption || (this.isModalType('default') && !!this.kbqCaption());
538
829
  }
539
830
  // Do rest things when visible state changed
540
831
  handleVisibleStateChange(visible, animation = true, closeResult) {
541
- // Hide scrollbar at the first time when shown up
542
832
  if (visible) {
543
- this.changeBodyOverflow(1);
833
+ this.captureFocus();
834
+ this.modalControl.setVisible(this, true);
835
+ // Hide scrollbar at the first time when shown up
836
+ this.changeBodyOverflow();
837
+ this.focusOnShow();
544
838
  }
545
839
  else {
546
840
  this.kbqBeforeClose.emit(closeResult);
841
+ this.modalControl.setVisible(this, false);
547
842
  }
548
843
  return (Promise.resolve(animation && this.animateTo(visible))
549
844
  // Emit open/close event after animations over
550
845
  .then(() => {
551
846
  if (visible) {
847
+ this.scrollbarViewports().forEach((viewport) => viewport.flashScrollIndicators());
552
848
  this.kbqAfterOpen.emit();
553
849
  }
554
850
  else {
555
851
  this.kbqAfterClose.emit(closeResult);
556
852
  // Show/hide scrollbar when animation is over
557
853
  this.changeBodyOverflow();
854
+ this.restoreFocus();
558
855
  }
559
856
  }));
560
857
  }
858
+ /**
859
+ * Remembers the element and the input modality to restore focus to. Both entry paths run
860
+ * through here, so a declarative `<kbq-modal [(kbqVisible)]>` restores focus like a
861
+ * service-created one.
862
+ */
863
+ captureFocus() {
864
+ this.focusedElementBeforeOpen = _getFocusedElementPierceShadowDom();
865
+ // `FocusMonitor` keeps the last origin private; the modality detector behind it is public
866
+ // and reports the same thing. No modality means the focus was moved by code.
867
+ this.previouslyFocusedElementOrigin = this.inputModalityDetector.mostRecentModality ?? 'program';
868
+ this.monitorContainer();
869
+ }
870
+ /**
871
+ * Registers the dialog element with `FocusMonitor` so focus inside it carries an origin. The
872
+ * registration is torn down on the first focus event and, failing that, on destroy — a dialog
873
+ * focus never reaches would otherwise stay in the root-provided monitor forever.
874
+ */
875
+ monitorContainer() {
876
+ if (!this.viewInitialized || this.monitoredContainer)
877
+ return;
878
+ this.monitoredContainer = this.modalContainer();
879
+ this.focusMonitorSubscription = this.focusMonitor
880
+ .monitor(this.monitoredContainer, true)
881
+ .pipe(take(1))
882
+ .subscribe(() => {
883
+ if (this.monitoredContainer) {
884
+ this.focusMonitor.stopMonitoring(this.monitoredContainer);
885
+ this.monitoredContainer = null;
886
+ }
887
+ });
888
+ }
889
+ restoreFocus() {
890
+ if (this.kbqRestoreFocus() && this.focusedElementBeforeOpen) {
891
+ this.focusMonitor.focusVia(this.focusedElementBeforeOpen, this.previouslyFocusedElementOrigin);
892
+ this.focusedElementBeforeOpen = null;
893
+ }
894
+ }
895
+ /** Moves focus into the dialog once the shown state has been rendered. */
896
+ focusOnShow() {
897
+ if (!this.viewInitialized)
898
+ return;
899
+ afterNextRender(() => this.focusInitialElement(), { injector: this.injector });
900
+ }
901
+ /**
902
+ * Initial focus policy. An explicit `[cdkFocusInitial]`/`autofocus` inside the dialog always
903
+ * wins; otherwise `kbqAutoFocus` decides. The dialog element itself is the last resort, so a
904
+ * modal without a single tabbable control still takes focus off the trigger behind it.
905
+ */
906
+ focusInitialElement() {
907
+ if (this.kbqAutoFocus() === false)
908
+ return;
909
+ const element = this.getElement();
910
+ const { focusTrap } = this.trapFocus();
911
+ // `cdkFocusInitial` is a bare attribute the CDK's own `focusInitialElement()` reads, not a
912
+ // directive, and that helper cannot be used here: it falls back to the first tabbable control
913
+ // whenever the marker is absent or its target fails the CDK's visibility check, which is
914
+ // exactly what 'dialog' and 'first-heading' must not do. So the marker is read directly, and
915
+ // it beats `autofocus` instead of losing to whichever comes first in document order.
916
+ const marked = element.querySelector('[cdkFocusInitial], [cdk-focus-initial]') ??
917
+ // Not part of the CDK's contract, but the predefined buttons carry it and the native
918
+ // attribute does nothing for an element inserted after the page has loaded.
919
+ element.querySelector('[autofocus]');
920
+ if (marked) {
921
+ marked.focus();
922
+ return;
923
+ }
924
+ if (this.kbqAutoFocus() === 'first-tabbable' && focusTrap.focusFirstTabbableElement())
925
+ return;
926
+ if (this.kbqAutoFocus() === 'first-heading') {
927
+ const heading = element.querySelector('.kbq-modal-title');
928
+ if (heading) {
929
+ heading.tabIndex = -1;
930
+ heading.focus();
931
+ return;
932
+ }
933
+ }
934
+ this.modalContainer().nativeElement.focus();
935
+ }
561
936
  // Change kbqVisible from inside
562
937
  changeVisibleFromInside(visible, closeResult) {
563
- if (this.kbqVisible !== visible) {
564
- // Change kbqVisible value immediately
565
- this.kbqVisible = visible;
566
- this.kbqVisibleChange.emit(visible);
567
- return this.handleVisibleStateChange(visible, true, closeResult);
938
+ if (this.kbqVisible() === visible)
939
+ return Promise.resolve();
940
+ // Claimed before the write, because `model.set()` reports it through `ngOnChanges` too and
941
+ // the flow is run here, synchronously, where the caller can still await it.
942
+ this.handledVisible = visible;
943
+ this.kbqVisible.set(visible);
944
+ return this.handleVisibleStateChange(visible, true, closeResult);
945
+ }
946
+ /**
947
+ * Runs the open/close flow for a visibility that arrived through a binding. A value this dialog
948
+ * set itself has already been handled, so it is skipped.
949
+ */
950
+ syncVisibleState(firstChange) {
951
+ const visible = this.kbqVisible();
952
+ if (visible === this.handledVisible)
953
+ return;
954
+ this.handledVisible = visible;
955
+ // A dialog that starts hidden has nothing to report: running the close path here used to
956
+ // emit `kbqBeforeClose`/`kbqAfterClose` before the dialog had ever been shown.
957
+ if (!firstChange || visible) {
958
+ // Do not trigger animation while initializing
959
+ this.handleVisibleStateChange(visible, !firstChange);
568
960
  }
569
- return Promise.resolve();
570
961
  }
571
962
  changeAnimationState(state) {
572
963
  this.animationState = state;
964
+ this.animationPhase.set(state);
573
965
  this.animateMaskTo(state);
574
- if (state) {
575
- this.modalAnimationClassMap = {
576
- [`zoom-${state}`]: true,
577
- [`zoom-${state}-active`]: true
578
- };
579
- }
580
- else {
581
- this.modalAnimationClassMap = null;
582
- }
583
966
  if (this.contentComponentRef) {
584
967
  this.contentComponentRef.changeDetectorRef.markForCheck();
585
968
  }
@@ -587,20 +970,51 @@ class KbqModalComponent extends KbqModalRef {
587
970
  this.changeDetector.markForCheck();
588
971
  }
589
972
  }
973
+ /**
974
+ * Runs the enter/leave animation and settles when it is really over: on `animationend`, as soon
975
+ * as the dialog is rendered when animations are disabled (`kbqAnimationsDisabled`), and on a
976
+ * timer when neither arrives.
977
+ */
590
978
  animateTo(isVisible) {
591
- // Figure out the latest click position when shows up
592
- if (isVisible) {
593
- // [NOTE] Using timeout due to the document.click event is fired later than visible change,
594
- // so if not postponed to next event-loop, we can't get the latest click position
595
- setTimeout(() => this.updateTransformOrigin());
596
- }
597
979
  this.changeAnimationState(isVisible ? 'enter' : 'leave');
598
- // Return when animation is over
980
+ if (this.animationsDisabled) {
981
+ this.changeAnimationState(null);
982
+ // There is no animation to wait for, but `open()` still runs before the first change
983
+ // detection on the imperative path. Settling synchronously would report the dialog as
984
+ // open before its view exists, and everything hanging off that — the scrollbar flash,
985
+ // whatever a consumer does in `afterOpen` — would find nothing to act on.
986
+ if (this.viewInitialized)
987
+ return Promise.resolve(null);
988
+ return new Promise((resolve) => afterNextRender(() => resolve(null), { injector: this.injector }));
989
+ }
599
990
  return new Promise((resolve) => {
600
- return setTimeout(() => {
991
+ // `open()` runs before the first change detection on the imperative path, so the view
992
+ // may not exist yet; the timer alone drives the promise then.
993
+ const container = this.viewInitialized ? this.modalContainer().nativeElement : null;
994
+ let settled = false;
995
+ let timer;
996
+ let unlisten;
997
+ const finish = () => {
998
+ if (settled)
999
+ return;
1000
+ settled = true;
1001
+ if (timer) {
1002
+ clearTimeout(timer);
1003
+ timer = undefined;
1004
+ }
1005
+ unlisten?.();
1006
+ unlisten = undefined;
601
1007
  this.changeAnimationState(null);
602
1008
  resolve(null);
603
- }, MODAL_ANIMATE_DURATION);
1009
+ };
1010
+ if (container) {
1011
+ unlisten = this.renderer.listen(container, 'animationend', (event) => {
1012
+ // The dialog hosts animated content of its own, and `animationend` bubbles.
1013
+ if (event.target === container)
1014
+ finish();
1015
+ });
1016
+ }
1017
+ timer = setTimeout(finish, MODAL_ANIMATE_DURATION);
604
1018
  });
605
1019
  }
606
1020
  formatModalButtons(buttons) {
@@ -621,6 +1035,7 @@ class KbqModalComponent extends KbqModalRef {
621
1035
  /**
622
1036
  * Create a component dynamically but not attach to any View
623
1037
  * (this action will be executed when bodyContainer is ready)
1038
+ *
624
1039
  * @param component Component class
625
1040
  */
626
1041
  createDynamicComponent(component) {
@@ -639,31 +1054,19 @@ class KbqModalComponent extends KbqModalRef {
639
1054
  // (or we do detection at ngAfterViewInit, multi-changes error will be thrown)
640
1055
  this.contentComponentRef.changeDetectorRef.detectChanges();
641
1056
  }
642
- // Update transform-origin to the last click position on document
643
- updateTransformOrigin() {
644
- const modalElement = this.modalContainer().nativeElement;
645
- const lastPosition = modalUtilObject.getLastClickPosition();
646
- if (lastPosition) {
647
- this.transformOrigin = `${lastPosition.x - modalElement.offsetLeft}px ${lastPosition.y - modalElement.offsetTop}px 0px`;
648
- }
649
- }
650
- /**
651
- * Take care of the body's overflow to decide the existence of scrollbar
652
- * @param plusNum The number that the openModals.length will increase soon
653
- */
654
- changeBodyOverflow(plusNum = 0) {
655
- const openModals = this.modalControl.openModals;
656
- if (openModals.length + plusNum > 0) {
1057
+ /** Locks the body scroll while any dialog is shown, and releases it once none is. */
1058
+ changeBodyOverflow() {
1059
+ if (this.modalControl.visibleModals().length > 0) {
657
1060
  this.renderer.setStyle(this.document.body, 'overflow', 'hidden');
658
1061
  }
659
1062
  else {
660
1063
  this.renderer.removeStyle(this.document.body, 'overflow');
661
1064
  }
662
1065
  }
663
- /** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.30", ngImport: i0, type: KbqModalComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
664
- /** @nocollapse */ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.30", type: KbqModalComponent, isStandalone: true, selector: "kbq-modal", inputs: { kbqModalType: "kbqModalType", kbqComponent: "kbqComponent", kbqContent: "kbqContent", kbqFooter: "kbqFooter", kbqVisible: "kbqVisible", kbqWidth: "kbqWidth", kbqSize: "kbqSize", kbqWrapClassName: "kbqWrapClassName", kbqClassName: "kbqClassName", kbqStyle: "kbqStyle", kbqTitle: "kbqTitle", kbqCaption: "kbqCaption", kbqCloseByESC: "kbqCloseByESC", kbqClosable: "kbqClosable", kbqMask: "kbqMask", kbqMaskClosable: "kbqMaskClosable", kbqMaskStyle: "kbqMaskStyle", kbqBodyStyle: "kbqBodyStyle", kbqOkText: "kbqOkText", kbqOkType: "kbqOkType", kbqRestoreFocus: "kbqRestoreFocus", kbqOkLoading: "kbqOkLoading", kbqOnOk: "kbqOnOk", kbqCancelText: "kbqCancelText", kbqCancelLoading: "kbqCancelLoading", kbqOnCancel: "kbqOnCancel", kbqGetContainer: "kbqGetContainer" }, outputs: { kbqVisibleChange: "kbqVisibleChange", kbqAfterOpen: "kbqAfterOpen", kbqAfterClose: "kbqAfterClose", kbqBeforeClose: "kbqBeforeClose", kbqOnOk: "kbqOnOk", kbqOnCancel: "kbqOnCancel" }, host: { listeners: { "keydown": "onKeyDown($event)" }, classAttribute: "kbq-modal" }, viewQueries: [{ propertyName: "modalContainer", first: true, predicate: ["modalContainer"], descendants: true, isSignal: true }, { propertyName: "bodyContainer", first: true, predicate: ["bodyContainer"], descendants: true, read: ViewContainerRef, isSignal: true }, { propertyName: "autoFocusedButtons", predicate: ["autoFocusedButton"], descendants: true, read: ElementRef, isSignal: true }], usesInheritance: true, usesOnChanges: true, ngImport: i0, template: "<!-- Compatible: the <ng-content> can appear only once -->\n<ng-template #tplOriginContent>\n <ng-content />\n</ng-template>\n\n<div>\n @if (kbqMask) {\n <div\n class=\"kbq-modal-mask\"\n [class.kbq-modal-mask-hidden]=\"hidden\"\n [class]=\"maskAnimationClassMap\"\n [style]=\"kbqMaskStyle\"\n ></div>\n }\n\n <div\n class=\"kbq-modal-wrap {{ kbqWrapClassName }}\"\n tabindex=\"-1\"\n [style.display]=\"hidden ? 'none' : ''\"\n (mousedown)=\"onClickMask($event)\"\n >\n <div\n #modalContainer\n [class]=\"getContainerClasses()\"\n [class.kbq-modal_no-footer]=\"!kbqFooter\"\n [style]=\"kbqStyle\"\n [style.transform-origin]=\"transformOrigin\"\n [style.width]=\"kbqWidth | toCssUnit\"\n >\n <div cdkTrapFocus class=\"kbq-modal-content\">\n @switch (true) {\n @case (isModalType('default')) {\n <ng-container [ngTemplateOutlet]=\"tplContentDefault\" />\n }\n @case (isModalType('confirm')) {\n <ng-container [ngTemplateOutlet]=\"tplContentConfirm\" />\n }\n @case (isModalType('custom')) {\n <ng-container [ngTemplateOutlet]=\"tplContentCustom\" />\n }\n }\n </div>\n </div>\n </div>\n</div>\n\n<ng-template #tplContentCustom>\n <ng-container #bodyContainer />\n</ng-template>\n\n<!-- [Predefined] Default Modal Content -->\n<ng-template #tplContentDefault>\n @if (kbqTitle || kbqCaption) {\n <div class=\"kbq-modal-header\" [kbqOverflowShadowTop]=\"modalBodyOverflow\">\n <div class=\"kbq-modal-header-content\">\n @if (kbqTitle) {\n <div class=\"kbq-modal-title\" kbq-title>\n @switch (true) {\n @case (isTemplateRef(kbqTitle)) {\n <ng-container [ngTemplateOutlet]=\"$any(kbqTitle)\" />\n }\n @case (isNonEmptyString(kbqTitle)) {\n <div #kbqTitleText [innerHTML]=\"kbqTitle\"></div>\n }\n }\n </div>\n }\n @if (kbqCaption) {\n <div class=\"kbq-modal-caption\" kbq-title>\n @switch (true) {\n @case (isTemplateRef(kbqCaption)) {\n <ng-container [ngTemplateOutlet]=\"$any(kbqCaption)\" />\n }\n @case (isNonEmptyString(kbqCaption)) {\n <div #kbqTitleText [innerHTML]=\"kbqCaption\"></div>\n }\n }\n </div>\n }\n </div>\n @if (kbqClosable) {\n <button\n kbq-button\n type=\"button\"\n class=\"kbq-modal-close kbq-button_transparent\"\n [color]=\"'contrast'\"\n (click)=\"onClickCloseBtn()\"\n >\n <i kbq-icon=\"kbq-xmark_16\" [color]=\"componentColors.Contrast\"></i>\n </button>\n }\n </div>\n }\n <div\n #modalBodyOverflow=\"kbqOverflowShadowContainer\"\n kbqOverflowShadowContainer\n class=\"kbq-modal-body kbq-scrollbar\"\n [style]=\"kbqBodyStyle\"\n >\n <ng-container #bodyContainer>\n @if (!isComponent(kbqContent)) {\n @switch (true) {\n @case (isTemplateRef(kbqContent)) {\n <ng-container [ngTemplateOutlet]=\"$any(kbqContent)\" />\n }\n @case (isNonEmptyString(kbqContent)) {\n <div [innerHTML]=\"kbqContent\"></div>\n }\n @default {\n <ng-container [ngTemplateOutlet]=\"tplOriginContent\" />\n }\n }\n }\n </ng-container>\n </div>\n @if (kbqFooter || kbqOkText || kbqCancelText) {\n <div class=\"kbq-modal-footer\" [kbqOverflowShadowBottom]=\"modalBodyOverflow\">\n @switch (true) {\n @case (isTemplateRef(kbqFooter)) {\n <ng-container [ngTemplateOutlet]=\"$any(kbqFooter)\" />\n }\n @case (isNonEmptyString(kbqFooter)) {\n <div [innerHTML]=\"kbqFooter\"></div>\n }\n @case (isModalButtons(kbqFooter)) {\n @for (button of $any(kbqFooter); track button) {\n @if (getButtonCallableProp(button, 'show')) {\n <button\n kbq-button\n [attr.autofocus]=\"button.autoFocus\"\n [attr.kbq-modal-main-action]=\"button.kbqModalMainAction\"\n [class.kbq-progress]=\"getButtonCallableProp(button, 'loading')\"\n [color]=\"button.type\"\n [disabled]=\"getButtonCallableProp(button, 'disabled')\"\n (click)=\"onButtonClick(button)\"\n >\n {{ button.label }}\n </button>\n }\n }\n }\n @default {\n @if (kbqOkText) {\n <button\n kbq-button\n [attr.autofocus]=\"true\"\n [color]=\"componentColors.Contrast\"\n (click)=\"onClickOkCancel('ok')\"\n >\n {{ okText }}\n </button>\n }\n @if (kbqCancelText) {\n <button kbq-button (click)=\"onClickOkCancel('cancel')\">\n {{ cancelText }}\n </button>\n }\n }\n }\n </div>\n }\n</ng-template>\n<!-- /[Predefined] Default Modal Content -->\n\n<!-- [Predefined] Confirm Modal Content -->\n<ng-template #tplContentConfirm>\n <div class=\"kbq-modal-body\" [style]=\"kbqBodyStyle\">\n <ng-container #bodyContainer>\n @if (!isComponent(kbqContent)) {\n @switch (true) {\n @case (isTemplateRef(kbqContent)) {\n <ng-container [ngTemplateOutlet]=\"$any(kbqContent)\" />\n }\n @case (isNonEmptyString(kbqContent)) {\n <div [innerHTML]=\"kbqContent\"></div>\n }\n @default {\n <ng-container [ngTemplateOutlet]=\"tplOriginContent\" />\n }\n }\n }\n </ng-container>\n </div>\n @if (kbqOkText || kbqCancelText) {\n <div class=\"kbq-confirm-footer\">\n @if (kbqOkText) {\n <button kbq-button [attr.autofocus]=\"true\" [color]=\"kbqOkType\" (click)=\"onClickOkCancel('ok')\">\n {{ okText }}\n </button>\n }\n @if (kbqCancelText) {\n <button kbq-button (click)=\"onClickOkCancel('cancel')\">\n {{ cancelText }}\n </button>\n }\n </div>\n }\n</ng-template>\n<!-- /[Predefined] Confirm Modal Content -->\n", styles: [".kbq-confirm .kbq-modal-close{display:none}.kbq-confirm .kbq-confirm-footer{display:flex;gap:var(--kbq-modal-size-footer-content-gap-horizontal)}@keyframes mcFadeIn{0%{opacity:0}to{opacity:1}}@keyframes mcFadeOut{0%{opacity:1}to{opacity:0}}@keyframes mcZoomIn{0%{opacity:0;transform:translateY(-25%)}to{opacity:1;transform:scale(1)}}@keyframes mcZoomOut{0%{transform:scale(1)}to{opacity:0;transform:translateY(-30%)}}.fade-enter,.fade-appear,.fade-leave{animation-duration:.3s;animation-fill-mode:both;animation-play-state:paused}.fade-enter.fade-enter-active,.fade-appear.fade-appear-active{animation-name:mcFadeIn;animation-play-state:running}.fade-leave.fade-leave-active{animation-name:mcFadeOut;animation-play-state:running;pointer-events:none}.fade-enter,.fade-appear{opacity:0;animation-timing-function:ease-out}.fade-leave{animation-timing-function:ease-out}.zoom-enter,.zoom-appear,.zoom-leave{animation-duration:.3s;animation-fill-mode:both;animation-play-state:paused}.zoom-enter.zoom-enter-active,.zoom-appear.zoom-appear-active{animation-name:mcZoomIn;animation-play-state:running}.zoom-leave.zoom-leave-active{animation-name:mcZoomOut;animation-play-state:running;pointer-events:none}.zoom-enter,.zoom-appear{transform:translateY(-25%);animation-timing-function:cubic-bezier(.075,.82,.165,1)}.zoom-leave{transform:translate(0);animation-timing-function:cubic-bezier(.785,.135,.15,.86)}.kbq-modal-container{box-sizing:border-box;position:relative;top:var(--kbq-size-5xl);border-radius:var(--kbq-modal-size-border-radius);width:auto;margin:0 auto;list-style:none}.kbq-modal-container.zoom-enter,.kbq-modal-container.zoom-appear{animation-duration:.3s;transform:none;opacity:0}.kbq-modal-container.kbq-modal_small{width:var(--kbq-modal-size-small-width)}.kbq-modal-container.kbq-modal_medium{width:var(--kbq-modal-size-medium-width)}.kbq-modal-container.kbq-modal_large{width:var(--kbq-modal-size-large-width)}.kbq-modal-container .kbq-modal-close{position:absolute;top:var(--kbq-size-l);right:var(--kbq-size-l)}.kbq-modal-wrap{position:fixed;inset:0;overflow:auto;-webkit-overflow-scrolling:touch;outline:0}.kbq-modal-content{position:relative;border-radius:var(--kbq-modal-size-border-radius);background-clip:padding-box}.kbq-modal-header{display:flex;align-items:center;justify-content:space-between;padding:var(--kbq-modal-size-header-padding-vertical) var(--kbq-modal-size-header-padding-right) var(--kbq-modal-size-header-padding-vertical) var(--kbq-modal-size-header-padding-left)}.kbq-modal-header+.kbq-modal-body{padding-top:var(--kbq-modal-size-content-padding-top)}.kbq-modal-title{display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;overflow:hidden;padding-top:var(--kbq-size-3xs);padding-bottom:var(--kbq-size-3xs)}.kbq-modal-header-content{display:flex;flex:1;flex-direction:column;min-width:0}.kbq-modal-caption{display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;overflow:hidden;text-overflow:ellipsis}.kbq-modal-body{display:block;overflow-y:auto;max-height:calc(100vh - 260px);padding:var(--kbq-modal-size-content-padding-top-without-header) var(--kbq-modal-size-content-padding-horizontal) var(--kbq-modal-size-content-padding-bottom) var(--kbq-modal-size-content-padding-horizontal);overflow-wrap:break-word}.kbq-modal-body>*{position:relative}.kbq-modal-footer,.kbq-confirm-footer{display:flex;align-items:center;padding:var(--kbq-modal-size-footer-padding-vertical) var(--kbq-modal-size-footer-padding-horizontal);gap:var(--kbq-modal-size-footer-content-gap-horizontal)}.kbq-modal-mask{position:fixed;inset:0;height:100%}.kbq-modal-mask.kbq-modal-mask-hidden{display:none}.kbq-modal-open{overflow:hidden}.kbq-modal-container{background:var(--kbq-modal-container-background);box-shadow:var(--kbq-modal-container-shadow)}.kbq-modal-container .kbq-modal-header .kbq-modal-title{color:var(--kbq-modal-header-text-color)}.kbq-modal-container .kbq-modal-header .kbq-modal-close{color:var(--kbq-modal-close-button-color)}.kbq-modal-container .kbq-modal-content{color:var(--kbq-modal-content-text-color)}.kbq-modal-container .kbq-modal-caption{color:var(--kbq-foreground-contrast-secondary)}.kbq-modal-mask{background-color:var(--kbq-modal-overlay-background)}.kbq-modal-title{font-size:var(--kbq-typography-title-font-size);font-style:var(--kbq-typography-title-font-style);font-weight:var(--kbq-typography-title-font-weight);line-height:var(--kbq-typography-title-line-height);font-family:var(--kbq-typography-title-font-family);text-transform:var(--kbq-typography-title-text-transform);font-feature-settings:var(--kbq-typography-title-font-feature-settings);letter-spacing:var(--kbq-typography-title-letter-spacing)}.kbq-modal-caption,.kbq-modal-body{font-size:var(--kbq-typography-text-normal-font-size);font-style:var(--kbq-typography-text-normal-font-style);font-weight:var(--kbq-typography-text-normal-font-weight);line-height:var(--kbq-typography-text-normal-line-height);font-family:var(--kbq-typography-text-normal-font-family);text-transform:var(--kbq-typography-text-normal-text-transform);font-feature-settings:var(--kbq-typography-text-normal-font-feature-settings);letter-spacing:var(--kbq-typography-text-normal-letter-spacing)}\n", ".kbq-modal{--kbq-modal-size-small-width: 400px;--kbq-modal-size-medium-width: 640px;--kbq-modal-size-large-width: 960px;--kbq-modal-size-border-radius: var(--kbq-size-m);--kbq-modal-size-header-padding-vertical: var(--kbq-size-l);--kbq-modal-size-header-padding-left: var(--kbq-size-xxl);--kbq-modal-size-header-padding-right: var(--kbq-size-6xl);--kbq-modal-size-close-button-margin-left: var(--kbq-size-s);--kbq-modal-size-content-padding-horizontal: var(--kbq-size-xxl);--kbq-modal-size-content-padding-top: 1px;--kbq-modal-size-content-padding-bottom: var(--kbq-size-s);--kbq-modal-size-content-padding-top-without-header: var(--kbq-size-xxl);--kbq-modal-size-content-padding-bottom-without-footer: var(--kbq-size-4xl);--kbq-modal-size-footer-padding-horizontal: var(--kbq-size-xxl);--kbq-modal-size-footer-padding-vertical: var(--kbq-size-xl);--kbq-modal-size-footer-content-gap-horizontal: var(--kbq-size-l);--kbq-modal-overlay-background: var(--kbq-background-overlay);--kbq-modal-container-background: var(--kbq-background-card);--kbq-modal-container-shadow: var(--kbq-shadow-overlay);--kbq-modal-close-button-color: var(--kbq-icon-contrast);--kbq-modal-header-text-color: var(--kbq-foreground-contrast);--kbq-modal-content-text-color: var(--kbq-foreground-contrast)}\n"], dependencies: [{ kind: "directive", type: CdkTrapFocus, selector: "[cdkTrapFocus]", inputs: ["cdkTrapFocus", "cdkTrapFocusAutoCapture"], exportAs: ["cdkTrapFocus"] }, { kind: "ngmodule", type: KbqButtonModule }, { kind: "component", type: i1.KbqButton, selector: "[kbq-button]", inputs: ["kbqStyle", "disabled", "tabIndex"] }, { kind: "directive", type: i1.KbqButtonCssStyler, selector: "[kbq-button]" }, { kind: "ngmodule", type: KbqIconModule }, { kind: "component", type: i2.KbqIcon, selector: "[kbq-icon]", inputs: ["small", "autoColor", "kbq-icon"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: KbqOverflowShadowContainer, selector: "[kbqOverflowShadowContainer]", inputs: ["debounce"], exportAs: ["kbqOverflowShadowContainer"] }, { kind: "directive", type: KbqOverflowShadowTop, selector: "[kbqOverflowShadowTop]", inputs: ["kbqOverflowShadowTop", "shadow"], exportAs: ["kbqOverflowShadowTop"] }, { kind: "directive", type: KbqOverflowShadowBottom, selector: "[kbqOverflowShadowBottom]", inputs: ["kbqOverflowShadowBottom", "shadow"], exportAs: ["kbqOverflowShadowBottom"] }, { kind: "ngmodule", type: KbqTitleModule }, { kind: "directive", type: i3.KbqTitleDirective, selector: "[kbq-title]", inputs: ["kbq-title"], exportAs: ["kbqTitle"] }, { kind: "pipe", type: CssUnitPipe, name: "toCssUnit" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
1066
+ /** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: KbqModalComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
1067
+ /** @nocollapse */ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.25", type: KbqModalComponent, isStandalone: true, selector: "kbq-modal", inputs: { kbqModalType: { classPropertyName: "kbqModalType", publicName: "kbqModalType", isSignal: true, isRequired: false, transformFunction: null }, kbqComponent: { classPropertyName: "kbqComponent", publicName: "kbqComponent", isSignal: true, isRequired: false, transformFunction: null }, kbqContent: { classPropertyName: "kbqContent", publicName: "kbqContent", isSignal: true, isRequired: false, transformFunction: null }, kbqFooter: { classPropertyName: "kbqFooter", publicName: "kbqFooter", isSignal: true, isRequired: false, transformFunction: null }, kbqVisible: { classPropertyName: "kbqVisible", publicName: "kbqVisible", isSignal: true, isRequired: false, transformFunction: null }, kbqWidth: { classPropertyName: "kbqWidth", publicName: "kbqWidth", isSignal: true, isRequired: false, transformFunction: null }, kbqSize: { classPropertyName: "kbqSize", publicName: "kbqSize", isSignal: true, isRequired: false, transformFunction: null }, kbqWrapClassName: { classPropertyName: "kbqWrapClassName", publicName: "kbqWrapClassName", isSignal: true, isRequired: false, transformFunction: null }, kbqClassName: { classPropertyName: "kbqClassName", publicName: "kbqClassName", isSignal: true, isRequired: false, transformFunction: null }, kbqStyle: { classPropertyName: "kbqStyle", publicName: "kbqStyle", isSignal: true, isRequired: false, transformFunction: null }, kbqTitle: { classPropertyName: "kbqTitle", publicName: "kbqTitle", isSignal: true, isRequired: false, transformFunction: null }, kbqCaption: { classPropertyName: "kbqCaption", publicName: "kbqCaption", isSignal: true, isRequired: false, transformFunction: null }, kbqCloseByESC: { classPropertyName: "kbqCloseByESC", publicName: "kbqCloseByESC", isSignal: true, isRequired: false, transformFunction: null }, kbqAutoFocus: { classPropertyName: "kbqAutoFocus", publicName: "kbqAutoFocus", isSignal: true, isRequired: false, transformFunction: null }, kbqAriaLabel: { classPropertyName: "kbqAriaLabel", publicName: "kbqAriaLabel", isSignal: true, isRequired: false, transformFunction: null }, kbqClosable: { classPropertyName: "kbqClosable", publicName: "kbqClosable", isSignal: true, isRequired: false, transformFunction: null }, kbqMask: { classPropertyName: "kbqMask", publicName: "kbqMask", isSignal: true, isRequired: false, transformFunction: null }, kbqMaskClosable: { classPropertyName: "kbqMaskClosable", publicName: "kbqMaskClosable", isSignal: true, isRequired: false, transformFunction: null }, kbqMaskStyle: { classPropertyName: "kbqMaskStyle", publicName: "kbqMaskStyle", isSignal: true, isRequired: false, transformFunction: null }, kbqBodyStyle: { classPropertyName: "kbqBodyStyle", publicName: "kbqBodyStyle", isSignal: true, isRequired: false, transformFunction: null }, kbqOkText: { classPropertyName: "kbqOkText", publicName: "kbqOkText", isSignal: true, isRequired: false, transformFunction: null }, kbqOkType: { classPropertyName: "kbqOkType", publicName: "kbqOkType", isSignal: true, isRequired: false, transformFunction: null }, kbqRestoreFocus: { classPropertyName: "kbqRestoreFocus", publicName: "kbqRestoreFocus", isSignal: true, isRequired: false, transformFunction: null }, kbqOkLoading: { classPropertyName: "kbqOkLoading", publicName: "kbqOkLoading", isSignal: true, isRequired: false, transformFunction: null }, kbqOkClick: { classPropertyName: "kbqOkClick", publicName: "kbqOkClick", isSignal: true, isRequired: false, transformFunction: null }, kbqCancelText: { classPropertyName: "kbqCancelText", publicName: "kbqCancelText", isSignal: true, isRequired: false, transformFunction: null }, kbqCancelLoading: { classPropertyName: "kbqCancelLoading", publicName: "kbqCancelLoading", isSignal: true, isRequired: false, transformFunction: null }, kbqCancelClick: { classPropertyName: "kbqCancelClick", publicName: "kbqCancelClick", isSignal: true, isRequired: false, transformFunction: null }, kbqGetContainer: { classPropertyName: "kbqGetContainer", publicName: "kbqGetContainer", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { kbqVisible: "kbqVisibleChange", kbqAfterOpenOutput: "kbqAfterOpen", kbqAfterCloseOutput: "kbqAfterClose", kbqBeforeCloseOutput: "kbqBeforeClose", kbqOnOkOutput: "kbqOnOk", kbqOnCancelOutput: "kbqOnCancel" }, host: { listeners: { "keydown": "onKeyDown($event)" }, classAttribute: "kbq-modal" }, providers: [{ provide: KBQ_MODAL, useExisting: KbqModalComponent }], viewQueries: [{ propertyName: "modalContainer", first: true, predicate: ["modalContainer"], descendants: true, isSignal: true }, { propertyName: "bodyContainer", first: true, predicate: ["bodyContainer"], descendants: true, read: ViewContainerRef, isSignal: true }, { propertyName: "scrollbarViewports", predicate: KbqScrollbarViewport, descendants: true, isSignal: true }, { propertyName: "trapFocus", first: true, predicate: CdkTrapFocus, descendants: true, isSignal: true }], usesInheritance: true, usesOnChanges: true, hostDirectives: [{ directive: i1.KbqLocaleOverridesDirective, inputs: ["kbqLocaleOverrides", "localeOverrides"] }], ngImport: i0, template: "<!-- Compatible: the <ng-content> can appear only once -->\n<ng-template #tplOriginContent>\n <ng-content />\n</ng-template>\n\n<!-- `aria-modal` only hides the page behind the topmost dialog, so a dialog covered by another one\n is taken out of the accessibility tree and the tab order explicitly. -->\n<div [attr.inert]=\"inert ? '' : null\">\n @if (isMaskEnabled()) {\n <div\n class=\"kbq-modal-mask {{ maskAnimationClasses() }}\"\n [class.kbq-modal-mask-hidden]=\"hidden\"\n [style]=\"kbqMaskStyle()\"\n ></div>\n }\n\n <div\n class=\"kbq-modal-wrap {{ kbqWrapClassName() }}\"\n kbqScrollbarViewport\n tabindex=\"-1\"\n [style.display]=\"hidden ? 'none' : ''\"\n (mousedown)=\"onClickMask($event)\"\n >\n <div\n #modalContainer\n cdkTrapFocus\n role=\"dialog\"\n tabindex=\"-1\"\n [attr.aria-describedby]=\"ariaDescribedBy\"\n [attr.aria-label]=\"ariaLabel\"\n [attr.aria-labelledby]=\"ariaLabelledBy\"\n [attr.aria-modal]=\"true\"\n [class]=\"containerClasses()\"\n [class.kbq-modal_no-footer]=\"!hasFooter\"\n [style]=\"kbqStyle()\"\n [style.width]=\"kbqWidth() | toCssUnit\"\n >\n <div class=\"kbq-modal-content\">\n @switch (kbqModalType()) {\n @case ('default') {\n <ng-container [ngTemplateOutlet]=\"tplContentDefault\" />\n }\n @case ('confirm') {\n <ng-container [ngTemplateOutlet]=\"tplContentConfirm\" />\n }\n @case ('custom') {\n <ng-container [ngTemplateOutlet]=\"tplContentCustom\" />\n }\n }\n </div>\n </div>\n </div>\n</div>\n\n<ng-template #tplContentCustom>\n <ng-container #bodyContainer />\n</ng-template>\n\n<!-- The body of a predefined layout: the same three forms `kbqContent` can take, and `<ng-content>`\n when it takes none. A component body is inserted into `#bodyContainer` from `ngAfterViewInit`. -->\n<ng-template #tplContentBody>\n <ng-container #bodyContainer>\n @if (contentKind() !== 'component') {\n @switch (contentKind()) {\n @case ('template') {\n <ng-container [ngTemplateOutlet]=\"$any(kbqContent())\" />\n }\n @case ('string') {\n <div [innerHTML]=\"kbqContent()\"></div>\n }\n @default {\n <ng-container [ngTemplateOutlet]=\"tplOriginContent\" />\n }\n }\n }\n </ng-container>\n</ng-template>\n\n<!-- [Predefined] Default Modal Content -->\n<ng-template #tplContentDefault>\n @if (kbqTitle() || kbqCaption()) {\n <div class=\"kbq-modal-header\" [kbqOverflowShadowTop]=\"modalBodyOverflow\">\n <div class=\"kbq-modal-header-content\">\n @if (kbqTitle()) {\n <div class=\"kbq-modal-title\" kbq-title [attr.id]=\"titleId\">\n @switch (titleKind()) {\n @case ('template') {\n <ng-container [ngTemplateOutlet]=\"$any(kbqTitle())\" />\n }\n @case ('string') {\n <div [innerHTML]=\"kbqTitle()\"></div>\n }\n }\n </div>\n }\n @if (kbqCaption()) {\n <div class=\"kbq-modal-caption\" kbq-title [attr.id]=\"captionId\">\n @switch (captionKind()) {\n @case ('template') {\n <ng-container [ngTemplateOutlet]=\"$any(kbqCaption())\" />\n }\n @case ('string') {\n <div [innerHTML]=\"kbqCaption()\"></div>\n }\n }\n </div>\n }\n </div>\n @if (kbqClosable()) {\n <button\n kbq-button\n type=\"button\"\n class=\"kbq-modal-close kbq-button_transparent\"\n [attr.aria-label]=\"a11yLocaleConfiguration().close\"\n [color]=\"'contrast'\"\n (click)=\"onClickCloseBtn()\"\n >\n <i kbq-icon=\"kbq-xmark_16\" [color]=\"componentColors.Contrast\"></i>\n </button>\n }\n </div>\n }\n <div\n #modalBodyOverflow=\"kbqOverflowShadowContainer\"\n kbqOverflowShadowContainer\n kbqScrollbarViewport\n class=\"kbq-modal-body\"\n [style]=\"kbqBodyStyle()\"\n >\n <ng-container [ngTemplateOutlet]=\"tplContentBody\" />\n </div>\n @if (hasFooter) {\n <div class=\"kbq-modal-footer\" [kbqOverflowShadowBottom]=\"modalBodyOverflow\">\n @switch (footerKind()) {\n @case ('template') {\n <ng-container [ngTemplateOutlet]=\"$any(footer())\" />\n }\n @case ('string') {\n <div [innerHTML]=\"footer()\"></div>\n }\n @case ('buttons') {\n @for (button of $any(footer()); track button) {\n @if (getButtonCallableProp(button, 'show')) {\n <button\n kbq-button\n [attr.autofocus]=\"button.autoFocus ? '' : null\"\n [attr.kbq-modal-main-action]=\"button.kbqModalMainAction ? '' : null\"\n [class.kbq-progress]=\"getButtonCallableProp(button, 'loading')\"\n [color]=\"button.type\"\n [disabled]=\"!!getButtonCallableProp(button, 'disabled')\"\n (click)=\"onButtonClick(button)\"\n >\n {{ button.label }}\n </button>\n }\n }\n }\n @default {\n @if (kbqOkText()) {\n <button\n kbq-button\n [attr.autofocus]=\"true\"\n [class.kbq-progress]=\"loading('ok')\"\n [color]=\"componentColors.Contrast\"\n (click)=\"onClickOkCancel('ok')\"\n >\n {{ kbqOkText() }}\n </button>\n }\n @if (kbqCancelText()) {\n <button kbq-button [class.kbq-progress]=\"loading('cancel')\" (click)=\"onClickOkCancel('cancel')\">\n {{ kbqCancelText() }}\n </button>\n }\n }\n }\n </div>\n }\n</ng-template>\n<!-- /[Predefined] Default Modal Content -->\n\n<!-- [Predefined] Confirm Modal Content -->\n<ng-template #tplContentConfirm>\n <div\n #confirmBodyOverflow=\"kbqOverflowShadowContainer\"\n kbqOverflowShadowContainer\n kbqScrollbarViewport\n class=\"kbq-modal-body\"\n [style]=\"kbqBodyStyle()\"\n >\n <ng-container [ngTemplateOutlet]=\"tplContentBody\" />\n </div>\n @if (kbqOkText() || kbqCancelText()) {\n <div class=\"kbq-confirm-footer\" [kbqOverflowShadowBottom]=\"confirmBodyOverflow\">\n @if (kbqOkText()) {\n <button\n kbq-button\n [attr.autofocus]=\"true\"\n [class.kbq-progress]=\"loading('ok')\"\n [color]=\"kbqOkType()\"\n (click)=\"onClickOkCancel('ok')\"\n >\n {{ kbqOkText() }}\n </button>\n }\n @if (kbqCancelText()) {\n <button kbq-button [class.kbq-progress]=\"loading('cancel')\" (click)=\"onClickOkCancel('cancel')\">\n {{ kbqCancelText() }}\n </button>\n }\n </div>\n }\n</ng-template>\n<!-- /[Predefined] Confirm Modal Content -->\n", styles: [".kbq-confirm .kbq-modal-close{display:none}.kbq-confirm .kbq-confirm-footer{display:flex;gap:var(--kbq-modal-size-footer-content-gap-horizontal)}@keyframes mcFadeIn{0%{opacity:0}to{opacity:1}}@keyframes mcFadeOut{0%{opacity:1}to{opacity:0}}@keyframes mcZoomIn{0%{opacity:0;transform:translateY(-25%)}to{opacity:1;transform:scale(1)}}@keyframes mcZoomOut{0%{transform:scale(1)}to{opacity:0;transform:translateY(-30%)}}.fade-enter,.fade-leave{animation-duration:.3s;animation-fill-mode:both;animation-play-state:paused}.fade-enter.fade-enter-active{animation-name:mcFadeIn;animation-play-state:running}.fade-leave.fade-leave-active{animation-name:mcFadeOut;animation-play-state:running;pointer-events:none}.fade-enter{opacity:0;animation-timing-function:ease-out}.fade-leave{animation-timing-function:ease-out}.zoom-enter,.zoom-leave{animation-duration:.3s;animation-fill-mode:both;animation-play-state:paused}.zoom-enter.zoom-enter-active{animation-name:mcZoomIn;animation-play-state:running}.zoom-leave.zoom-leave-active{animation-name:mcZoomOut;animation-play-state:running;pointer-events:none}.zoom-enter{transform:translateY(-25%);animation-timing-function:cubic-bezier(.075,.82,.165,1)}.zoom-leave{transform:translate(0);animation-timing-function:cubic-bezier(.785,.135,.15,.86)}@media(prefers-reduced-motion:reduce){.fade-enter,.fade-leave{animation:none;opacity:1;transform:none}}@media(prefers-reduced-motion:reduce){.zoom-enter,.zoom-leave{animation:none;opacity:1;transform:none}}.kbq-modal-container{box-sizing:border-box;position:relative;top:var(--kbq-modal-size-viewport-inset);border-radius:var(--kbq-modal-size-border-radius)}@supports (corner-shape: squircle){.kbq-modal-container{corner-shape:squircle;border-radius:clamp(var(--kbq-modal-size-border-radius) * 1.85,var(--kbq-modal-size-border-radius) * 2.3 - 3.6px,var(--kbq-modal-size-border-radius) * 2)}}.kbq-modal-container{display:flex;flex-direction:column;width:auto;max-height:calc(100vh - 2 * var(--kbq-modal-size-viewport-inset));margin:0 auto;list-style:none}.kbq-modal-container.kbq-modal_small{width:var(--kbq-modal-size-small-width)}.kbq-modal-container.kbq-modal_medium{width:var(--kbq-modal-size-medium-width)}.kbq-modal-container.kbq-modal_large{width:var(--kbq-modal-size-large-width)}.kbq-modal-container.kbq-modal_no-footer .kbq-modal-body{padding-bottom:var(--kbq-modal-size-content-padding-bottom-without-footer)}.kbq-modal-container .kbq-modal-close{position:absolute;top:var(--kbq-size-l);right:var(--kbq-size-l)}.kbq-modal-wrap{position:fixed;inset:0;overflow:auto;-webkit-overflow-scrolling:touch;outline:0}.kbq-modal-content{position:relative;border-radius:var(--kbq-modal-size-border-radius)}@supports (corner-shape: squircle){.kbq-modal-content{corner-shape:squircle;border-radius:clamp(var(--kbq-modal-size-border-radius) * 1.85,var(--kbq-modal-size-border-radius) * 2.3 - 3.6px,var(--kbq-modal-size-border-radius) * 2)}}.kbq-modal-content{display:flex;flex:1 1 auto;flex-direction:column;min-height:0;background-clip:padding-box}.kbq-modal-content-host{display:flex;flex:1 1 auto;flex-direction:column;min-height:0}.kbq-modal-header{display:flex;flex:0 0 auto;align-items:center;justify-content:space-between;padding:var(--kbq-modal-size-header-padding-vertical) var(--kbq-modal-size-header-padding-right) var(--kbq-modal-size-header-padding-vertical) var(--kbq-modal-size-header-padding-left)}.kbq-modal-header+.kbq-modal-body{padding-top:var(--kbq-modal-size-content-padding-top)}.kbq-modal-title{display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;overflow:hidden;padding-top:var(--kbq-size-3xs);padding-bottom:var(--kbq-size-3xs)}.kbq-modal-header-content{display:flex;flex:1;flex-direction:column;min-width:0}.kbq-modal-caption{display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;overflow:hidden;text-overflow:ellipsis}.kbq-modal-body{display:block;flex:1 1 auto;min-height:0;overflow-y:auto;padding:var(--kbq-modal-size-content-padding-top-without-header) var(--kbq-modal-size-content-padding-horizontal) var(--kbq-modal-size-content-padding-bottom) var(--kbq-modal-size-content-padding-horizontal);overflow-wrap:break-word}.kbq-modal-footer,.kbq-confirm-footer{display:flex;flex:0 0 auto;align-items:center;padding:var(--kbq-modal-size-footer-padding-vertical) var(--kbq-modal-size-footer-padding-horizontal);gap:var(--kbq-modal-size-footer-content-gap-horizontal)}.kbq-modal-mask{position:fixed;inset:0;height:100%}.kbq-modal-mask.kbq-modal-mask-hidden{display:none}.kbq-modal-container{background:var(--kbq-modal-container-background);box-shadow:var(--kbq-modal-container-shadow)}.kbq-modal-container .kbq-modal-header .kbq-modal-title{color:var(--kbq-modal-header-text-color)}.kbq-modal-container .kbq-modal-header .kbq-modal-close{color:var(--kbq-modal-close-button-color)}.kbq-modal-container .kbq-modal-content{color:var(--kbq-modal-content-text-color)}.kbq-modal-container .kbq-modal-caption{color:var(--kbq-foreground-contrast-secondary)}.kbq-modal-mask{background-color:var(--kbq-modal-overlay-background)}.kbq-modal-title{font-size:var(--kbq-typography-title-font-size);font-style:var(--kbq-typography-title-font-style);font-weight:var(--kbq-typography-title-font-weight);line-height:var(--kbq-typography-title-line-height);font-family:var(--kbq-typography-title-font-family);text-transform:var(--kbq-typography-title-text-transform);font-feature-settings:var(--kbq-typography-title-font-feature-settings);letter-spacing:var(--kbq-typography-title-letter-spacing)}.kbq-modal-caption,.kbq-modal-body{font-size:var(--kbq-typography-text-normal-font-size);font-style:var(--kbq-typography-text-normal-font-style);font-weight:var(--kbq-typography-text-normal-font-weight);line-height:var(--kbq-typography-text-normal-line-height);font-family:var(--kbq-typography-text-normal-font-family);text-transform:var(--kbq-typography-text-normal-text-transform);font-feature-settings:var(--kbq-typography-text-normal-font-feature-settings);letter-spacing:var(--kbq-typography-text-normal-letter-spacing)}\n", ".kbq-modal{--kbq-modal-size-small-width: 400px;--kbq-modal-size-medium-width: 640px;--kbq-modal-size-large-width: 960px;--kbq-modal-size-border-radius: var(--kbq-size-m);--kbq-modal-size-header-padding-vertical: var(--kbq-size-l);--kbq-modal-size-header-padding-left: var(--kbq-size-xxl);--kbq-modal-size-header-padding-right: var(--kbq-size-6xl);--kbq-modal-size-content-padding-horizontal: var(--kbq-size-xxl);--kbq-modal-size-viewport-inset: var(--kbq-size-5xl);--kbq-modal-size-content-padding-top: 1px;--kbq-modal-size-content-padding-bottom: var(--kbq-size-s);--kbq-modal-size-content-padding-top-without-header: var(--kbq-size-xxl);--kbq-modal-size-content-padding-bottom-without-footer: var(--kbq-size-4xl);--kbq-modal-size-footer-padding-horizontal: var(--kbq-size-xxl);--kbq-modal-size-footer-padding-vertical: var(--kbq-size-xl);--kbq-modal-size-footer-content-gap-horizontal: var(--kbq-size-l);--kbq-modal-overlay-background: var(--kbq-background-overlay);--kbq-modal-container-background: var(--kbq-background-card);--kbq-modal-container-shadow: var(--kbq-shadow-overlay);--kbq-modal-close-button-color: var(--kbq-icon-contrast);--kbq-modal-header-text-color: var(--kbq-foreground-contrast);--kbq-modal-content-text-color: var(--kbq-foreground-contrast)}\n"], dependencies: [{ kind: "directive", type: CdkTrapFocus, selector: "[cdkTrapFocus]", inputs: ["cdkTrapFocus", "cdkTrapFocusAutoCapture"], exportAs: ["cdkTrapFocus"] }, { kind: "ngmodule", type: KbqButtonModule }, { kind: "component", type: i2.KbqButton, selector: "[kbq-button]", inputs: ["kbqStyle", "disabled", "tabIndex"] }, { kind: "directive", type: i2.KbqButtonCssStyler, selector: "[kbq-button]" }, { kind: "ngmodule", type: KbqIconModule }, { kind: "component", type: i3.KbqIcon, selector: "[kbq-icon]", inputs: ["aria-hidden", "iconSize", "autoColor", "kbq-icon"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: KbqScrollbarViewport, selector: "[kbqScrollbarViewport]", inputs: ["kbqScrollbarMode", "kbqScrollbarHideDelay"] }, { kind: "directive", type: KbqOverflowShadowContainer, selector: "[kbqOverflowShadowContainer]", inputs: ["debounce"], exportAs: ["kbqOverflowShadowContainer"] }, { kind: "directive", type: KbqOverflowShadowTop, selector: "[kbqOverflowShadowTop]", inputs: ["kbqOverflowShadowTop", "shadow"], exportAs: ["kbqOverflowShadowTop"] }, { kind: "directive", type: KbqOverflowShadowBottom, selector: "[kbqOverflowShadowBottom]", inputs: ["kbqOverflowShadowBottom", "shadow"], exportAs: ["kbqOverflowShadowBottom"] }, { kind: "ngmodule", type: KbqTitleModule }, { kind: "directive", type: i4.KbqTitleDirective, selector: "[kbq-title]", inputs: ["kbq-title", "ignoreTooltipPointerEvents"], exportAs: ["kbqTitle"] }, { kind: "pipe", type: CssUnitPipe, name: "toCssUnit" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
665
1068
  }
666
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.30", ngImport: i0, type: KbqModalComponent, decorators: [{
1069
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: KbqModalComponent, decorators: [{
667
1070
  type: Component,
668
1071
  args: [{ selector: 'kbq-modal', imports: [
669
1072
  CdkTrapFocus,
@@ -671,79 +1074,18 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.30", ngImpo
671
1074
  KbqIconModule,
672
1075
  CssUnitPipe,
673
1076
  NgTemplateOutlet,
1077
+ KbqScrollbarViewport,
674
1078
  KbqOverflowShadowContainer,
675
1079
  KbqOverflowShadowTop,
676
1080
  KbqOverflowShadowBottom,
677
1081
  KbqTitleModule
678
- ], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, host: {
1082
+ ], providers: [{ provide: KBQ_MODAL, useExisting: KbqModalComponent }], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, host: {
679
1083
  class: 'kbq-modal',
680
1084
  '(keydown)': 'onKeyDown($event)'
681
- }, template: "<!-- Compatible: the <ng-content> can appear only once -->\n<ng-template #tplOriginContent>\n <ng-content />\n</ng-template>\n\n<div>\n @if (kbqMask) {\n <div\n class=\"kbq-modal-mask\"\n [class.kbq-modal-mask-hidden]=\"hidden\"\n [class]=\"maskAnimationClassMap\"\n [style]=\"kbqMaskStyle\"\n ></div>\n }\n\n <div\n class=\"kbq-modal-wrap {{ kbqWrapClassName }}\"\n tabindex=\"-1\"\n [style.display]=\"hidden ? 'none' : ''\"\n (mousedown)=\"onClickMask($event)\"\n >\n <div\n #modalContainer\n [class]=\"getContainerClasses()\"\n [class.kbq-modal_no-footer]=\"!kbqFooter\"\n [style]=\"kbqStyle\"\n [style.transform-origin]=\"transformOrigin\"\n [style.width]=\"kbqWidth | toCssUnit\"\n >\n <div cdkTrapFocus class=\"kbq-modal-content\">\n @switch (true) {\n @case (isModalType('default')) {\n <ng-container [ngTemplateOutlet]=\"tplContentDefault\" />\n }\n @case (isModalType('confirm')) {\n <ng-container [ngTemplateOutlet]=\"tplContentConfirm\" />\n }\n @case (isModalType('custom')) {\n <ng-container [ngTemplateOutlet]=\"tplContentCustom\" />\n }\n }\n </div>\n </div>\n </div>\n</div>\n\n<ng-template #tplContentCustom>\n <ng-container #bodyContainer />\n</ng-template>\n\n<!-- [Predefined] Default Modal Content -->\n<ng-template #tplContentDefault>\n @if (kbqTitle || kbqCaption) {\n <div class=\"kbq-modal-header\" [kbqOverflowShadowTop]=\"modalBodyOverflow\">\n <div class=\"kbq-modal-header-content\">\n @if (kbqTitle) {\n <div class=\"kbq-modal-title\" kbq-title>\n @switch (true) {\n @case (isTemplateRef(kbqTitle)) {\n <ng-container [ngTemplateOutlet]=\"$any(kbqTitle)\" />\n }\n @case (isNonEmptyString(kbqTitle)) {\n <div #kbqTitleText [innerHTML]=\"kbqTitle\"></div>\n }\n }\n </div>\n }\n @if (kbqCaption) {\n <div class=\"kbq-modal-caption\" kbq-title>\n @switch (true) {\n @case (isTemplateRef(kbqCaption)) {\n <ng-container [ngTemplateOutlet]=\"$any(kbqCaption)\" />\n }\n @case (isNonEmptyString(kbqCaption)) {\n <div #kbqTitleText [innerHTML]=\"kbqCaption\"></div>\n }\n }\n </div>\n }\n </div>\n @if (kbqClosable) {\n <button\n kbq-button\n type=\"button\"\n class=\"kbq-modal-close kbq-button_transparent\"\n [color]=\"'contrast'\"\n (click)=\"onClickCloseBtn()\"\n >\n <i kbq-icon=\"kbq-xmark_16\" [color]=\"componentColors.Contrast\"></i>\n </button>\n }\n </div>\n }\n <div\n #modalBodyOverflow=\"kbqOverflowShadowContainer\"\n kbqOverflowShadowContainer\n class=\"kbq-modal-body kbq-scrollbar\"\n [style]=\"kbqBodyStyle\"\n >\n <ng-container #bodyContainer>\n @if (!isComponent(kbqContent)) {\n @switch (true) {\n @case (isTemplateRef(kbqContent)) {\n <ng-container [ngTemplateOutlet]=\"$any(kbqContent)\" />\n }\n @case (isNonEmptyString(kbqContent)) {\n <div [innerHTML]=\"kbqContent\"></div>\n }\n @default {\n <ng-container [ngTemplateOutlet]=\"tplOriginContent\" />\n }\n }\n }\n </ng-container>\n </div>\n @if (kbqFooter || kbqOkText || kbqCancelText) {\n <div class=\"kbq-modal-footer\" [kbqOverflowShadowBottom]=\"modalBodyOverflow\">\n @switch (true) {\n @case (isTemplateRef(kbqFooter)) {\n <ng-container [ngTemplateOutlet]=\"$any(kbqFooter)\" />\n }\n @case (isNonEmptyString(kbqFooter)) {\n <div [innerHTML]=\"kbqFooter\"></div>\n }\n @case (isModalButtons(kbqFooter)) {\n @for (button of $any(kbqFooter); track button) {\n @if (getButtonCallableProp(button, 'show')) {\n <button\n kbq-button\n [attr.autofocus]=\"button.autoFocus\"\n [attr.kbq-modal-main-action]=\"button.kbqModalMainAction\"\n [class.kbq-progress]=\"getButtonCallableProp(button, 'loading')\"\n [color]=\"button.type\"\n [disabled]=\"getButtonCallableProp(button, 'disabled')\"\n (click)=\"onButtonClick(button)\"\n >\n {{ button.label }}\n </button>\n }\n }\n }\n @default {\n @if (kbqOkText) {\n <button\n kbq-button\n [attr.autofocus]=\"true\"\n [color]=\"componentColors.Contrast\"\n (click)=\"onClickOkCancel('ok')\"\n >\n {{ okText }}\n </button>\n }\n @if (kbqCancelText) {\n <button kbq-button (click)=\"onClickOkCancel('cancel')\">\n {{ cancelText }}\n </button>\n }\n }\n }\n </div>\n }\n</ng-template>\n<!-- /[Predefined] Default Modal Content -->\n\n<!-- [Predefined] Confirm Modal Content -->\n<ng-template #tplContentConfirm>\n <div class=\"kbq-modal-body\" [style]=\"kbqBodyStyle\">\n <ng-container #bodyContainer>\n @if (!isComponent(kbqContent)) {\n @switch (true) {\n @case (isTemplateRef(kbqContent)) {\n <ng-container [ngTemplateOutlet]=\"$any(kbqContent)\" />\n }\n @case (isNonEmptyString(kbqContent)) {\n <div [innerHTML]=\"kbqContent\"></div>\n }\n @default {\n <ng-container [ngTemplateOutlet]=\"tplOriginContent\" />\n }\n }\n }\n </ng-container>\n </div>\n @if (kbqOkText || kbqCancelText) {\n <div class=\"kbq-confirm-footer\">\n @if (kbqOkText) {\n <button kbq-button [attr.autofocus]=\"true\" [color]=\"kbqOkType\" (click)=\"onClickOkCancel('ok')\">\n {{ okText }}\n </button>\n }\n @if (kbqCancelText) {\n <button kbq-button (click)=\"onClickOkCancel('cancel')\">\n {{ cancelText }}\n </button>\n }\n </div>\n }\n</ng-template>\n<!-- /[Predefined] Confirm Modal Content -->\n", styles: [".kbq-confirm .kbq-modal-close{display:none}.kbq-confirm .kbq-confirm-footer{display:flex;gap:var(--kbq-modal-size-footer-content-gap-horizontal)}@keyframes mcFadeIn{0%{opacity:0}to{opacity:1}}@keyframes mcFadeOut{0%{opacity:1}to{opacity:0}}@keyframes mcZoomIn{0%{opacity:0;transform:translateY(-25%)}to{opacity:1;transform:scale(1)}}@keyframes mcZoomOut{0%{transform:scale(1)}to{opacity:0;transform:translateY(-30%)}}.fade-enter,.fade-appear,.fade-leave{animation-duration:.3s;animation-fill-mode:both;animation-play-state:paused}.fade-enter.fade-enter-active,.fade-appear.fade-appear-active{animation-name:mcFadeIn;animation-play-state:running}.fade-leave.fade-leave-active{animation-name:mcFadeOut;animation-play-state:running;pointer-events:none}.fade-enter,.fade-appear{opacity:0;animation-timing-function:ease-out}.fade-leave{animation-timing-function:ease-out}.zoom-enter,.zoom-appear,.zoom-leave{animation-duration:.3s;animation-fill-mode:both;animation-play-state:paused}.zoom-enter.zoom-enter-active,.zoom-appear.zoom-appear-active{animation-name:mcZoomIn;animation-play-state:running}.zoom-leave.zoom-leave-active{animation-name:mcZoomOut;animation-play-state:running;pointer-events:none}.zoom-enter,.zoom-appear{transform:translateY(-25%);animation-timing-function:cubic-bezier(.075,.82,.165,1)}.zoom-leave{transform:translate(0);animation-timing-function:cubic-bezier(.785,.135,.15,.86)}.kbq-modal-container{box-sizing:border-box;position:relative;top:var(--kbq-size-5xl);border-radius:var(--kbq-modal-size-border-radius);width:auto;margin:0 auto;list-style:none}.kbq-modal-container.zoom-enter,.kbq-modal-container.zoom-appear{animation-duration:.3s;transform:none;opacity:0}.kbq-modal-container.kbq-modal_small{width:var(--kbq-modal-size-small-width)}.kbq-modal-container.kbq-modal_medium{width:var(--kbq-modal-size-medium-width)}.kbq-modal-container.kbq-modal_large{width:var(--kbq-modal-size-large-width)}.kbq-modal-container .kbq-modal-close{position:absolute;top:var(--kbq-size-l);right:var(--kbq-size-l)}.kbq-modal-wrap{position:fixed;inset:0;overflow:auto;-webkit-overflow-scrolling:touch;outline:0}.kbq-modal-content{position:relative;border-radius:var(--kbq-modal-size-border-radius);background-clip:padding-box}.kbq-modal-header{display:flex;align-items:center;justify-content:space-between;padding:var(--kbq-modal-size-header-padding-vertical) var(--kbq-modal-size-header-padding-right) var(--kbq-modal-size-header-padding-vertical) var(--kbq-modal-size-header-padding-left)}.kbq-modal-header+.kbq-modal-body{padding-top:var(--kbq-modal-size-content-padding-top)}.kbq-modal-title{display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;overflow:hidden;padding-top:var(--kbq-size-3xs);padding-bottom:var(--kbq-size-3xs)}.kbq-modal-header-content{display:flex;flex:1;flex-direction:column;min-width:0}.kbq-modal-caption{display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;overflow:hidden;text-overflow:ellipsis}.kbq-modal-body{display:block;overflow-y:auto;max-height:calc(100vh - 260px);padding:var(--kbq-modal-size-content-padding-top-without-header) var(--kbq-modal-size-content-padding-horizontal) var(--kbq-modal-size-content-padding-bottom) var(--kbq-modal-size-content-padding-horizontal);overflow-wrap:break-word}.kbq-modal-body>*{position:relative}.kbq-modal-footer,.kbq-confirm-footer{display:flex;align-items:center;padding:var(--kbq-modal-size-footer-padding-vertical) var(--kbq-modal-size-footer-padding-horizontal);gap:var(--kbq-modal-size-footer-content-gap-horizontal)}.kbq-modal-mask{position:fixed;inset:0;height:100%}.kbq-modal-mask.kbq-modal-mask-hidden{display:none}.kbq-modal-open{overflow:hidden}.kbq-modal-container{background:var(--kbq-modal-container-background);box-shadow:var(--kbq-modal-container-shadow)}.kbq-modal-container .kbq-modal-header .kbq-modal-title{color:var(--kbq-modal-header-text-color)}.kbq-modal-container .kbq-modal-header .kbq-modal-close{color:var(--kbq-modal-close-button-color)}.kbq-modal-container .kbq-modal-content{color:var(--kbq-modal-content-text-color)}.kbq-modal-container .kbq-modal-caption{color:var(--kbq-foreground-contrast-secondary)}.kbq-modal-mask{background-color:var(--kbq-modal-overlay-background)}.kbq-modal-title{font-size:var(--kbq-typography-title-font-size);font-style:var(--kbq-typography-title-font-style);font-weight:var(--kbq-typography-title-font-weight);line-height:var(--kbq-typography-title-line-height);font-family:var(--kbq-typography-title-font-family);text-transform:var(--kbq-typography-title-text-transform);font-feature-settings:var(--kbq-typography-title-font-feature-settings);letter-spacing:var(--kbq-typography-title-letter-spacing)}.kbq-modal-caption,.kbq-modal-body{font-size:var(--kbq-typography-text-normal-font-size);font-style:var(--kbq-typography-text-normal-font-style);font-weight:var(--kbq-typography-text-normal-font-weight);line-height:var(--kbq-typography-text-normal-line-height);font-family:var(--kbq-typography-text-normal-font-family);text-transform:var(--kbq-typography-text-normal-text-transform);font-feature-settings:var(--kbq-typography-text-normal-font-feature-settings);letter-spacing:var(--kbq-typography-text-normal-letter-spacing)}\n", ".kbq-modal{--kbq-modal-size-small-width: 400px;--kbq-modal-size-medium-width: 640px;--kbq-modal-size-large-width: 960px;--kbq-modal-size-border-radius: var(--kbq-size-m);--kbq-modal-size-header-padding-vertical: var(--kbq-size-l);--kbq-modal-size-header-padding-left: var(--kbq-size-xxl);--kbq-modal-size-header-padding-right: var(--kbq-size-6xl);--kbq-modal-size-close-button-margin-left: var(--kbq-size-s);--kbq-modal-size-content-padding-horizontal: var(--kbq-size-xxl);--kbq-modal-size-content-padding-top: 1px;--kbq-modal-size-content-padding-bottom: var(--kbq-size-s);--kbq-modal-size-content-padding-top-without-header: var(--kbq-size-xxl);--kbq-modal-size-content-padding-bottom-without-footer: var(--kbq-size-4xl);--kbq-modal-size-footer-padding-horizontal: var(--kbq-size-xxl);--kbq-modal-size-footer-padding-vertical: var(--kbq-size-xl);--kbq-modal-size-footer-content-gap-horizontal: var(--kbq-size-l);--kbq-modal-overlay-background: var(--kbq-background-overlay);--kbq-modal-container-background: var(--kbq-background-card);--kbq-modal-container-shadow: var(--kbq-shadow-overlay);--kbq-modal-close-button-color: var(--kbq-icon-contrast);--kbq-modal-header-text-color: var(--kbq-foreground-contrast);--kbq-modal-content-text-color: var(--kbq-foreground-contrast)}\n"] }]
682
- }], propDecorators: { kbqModalType: [{
683
- type: Input
684
- }], kbqComponent: [{
685
- type: Input
686
- }], kbqContent: [{
687
- type: Input
688
- }], kbqFooter: [{
689
- type: Input
690
- }], kbqVisible: [{
691
- type: Input
692
- }], kbqVisibleChange: [{ type: i0.Output, args: ["kbqVisibleChange"] }], kbqWidth: [{
693
- type: Input
694
- }], kbqSize: [{
695
- type: Input
696
- }], kbqWrapClassName: [{
697
- type: Input
698
- }], kbqClassName: [{
699
- type: Input
700
- }], kbqStyle: [{
701
- type: Input
702
- }], kbqTitle: [{
703
- type: Input
704
- }], kbqCaption: [{
705
- type: Input
706
- }], kbqCloseByESC: [{
707
- type: Input
708
- }], kbqClosable: [{
709
- type: Input
710
- }], kbqMask: [{
711
- type: Input
712
- }], kbqMaskClosable: [{
713
- type: Input
714
- }], kbqMaskStyle: [{
715
- type: Input
716
- }], kbqBodyStyle: [{
717
- type: Input
718
- }], kbqAfterOpen: [{
719
- type: Output
720
- }], kbqAfterClose: [{
721
- type: Output
722
- }], kbqBeforeClose: [{
723
- type: Output
724
- }], kbqOkText: [{
725
- type: Input
726
- }], kbqOkType: [{
727
- type: Input
728
- }], kbqRestoreFocus: [{
729
- type: Input
730
- }], kbqOkLoading: [{
731
- type: Input
732
- }], kbqOnOk: [{
733
- type: Input
734
- }, {
735
- type: Output
736
- }], kbqCancelText: [{
737
- type: Input
738
- }], kbqCancelLoading: [{
739
- type: Input
740
- }], kbqOnCancel: [{
741
- type: Input
742
- }, {
743
- type: Output
744
- }], modalContainer: [{ type: i0.ViewChild, args: ['modalContainer', { isSignal: true }] }], bodyContainer: [{ type: i0.ViewChild, args: ['bodyContainer', { ...{ read: ViewContainerRef }, isSignal: true }] }], autoFocusedButtons: [{ type: i0.ViewChildren, args: ['autoFocusedButton', { ...{ read: ElementRef }, isSignal: true }] }], kbqGetContainer: [{
745
- type: Input
746
- }] } });
1085
+ }, hostDirectives: [
1086
+ { directive: KbqLocaleOverridesDirective, inputs: ['kbqLocaleOverrides: localeOverrides'] }
1087
+ ], template: "<!-- Compatible: the <ng-content> can appear only once -->\n<ng-template #tplOriginContent>\n <ng-content />\n</ng-template>\n\n<!-- `aria-modal` only hides the page behind the topmost dialog, so a dialog covered by another one\n is taken out of the accessibility tree and the tab order explicitly. -->\n<div [attr.inert]=\"inert ? '' : null\">\n @if (isMaskEnabled()) {\n <div\n class=\"kbq-modal-mask {{ maskAnimationClasses() }}\"\n [class.kbq-modal-mask-hidden]=\"hidden\"\n [style]=\"kbqMaskStyle()\"\n ></div>\n }\n\n <div\n class=\"kbq-modal-wrap {{ kbqWrapClassName() }}\"\n kbqScrollbarViewport\n tabindex=\"-1\"\n [style.display]=\"hidden ? 'none' : ''\"\n (mousedown)=\"onClickMask($event)\"\n >\n <div\n #modalContainer\n cdkTrapFocus\n role=\"dialog\"\n tabindex=\"-1\"\n [attr.aria-describedby]=\"ariaDescribedBy\"\n [attr.aria-label]=\"ariaLabel\"\n [attr.aria-labelledby]=\"ariaLabelledBy\"\n [attr.aria-modal]=\"true\"\n [class]=\"containerClasses()\"\n [class.kbq-modal_no-footer]=\"!hasFooter\"\n [style]=\"kbqStyle()\"\n [style.width]=\"kbqWidth() | toCssUnit\"\n >\n <div class=\"kbq-modal-content\">\n @switch (kbqModalType()) {\n @case ('default') {\n <ng-container [ngTemplateOutlet]=\"tplContentDefault\" />\n }\n @case ('confirm') {\n <ng-container [ngTemplateOutlet]=\"tplContentConfirm\" />\n }\n @case ('custom') {\n <ng-container [ngTemplateOutlet]=\"tplContentCustom\" />\n }\n }\n </div>\n </div>\n </div>\n</div>\n\n<ng-template #tplContentCustom>\n <ng-container #bodyContainer />\n</ng-template>\n\n<!-- The body of a predefined layout: the same three forms `kbqContent` can take, and `<ng-content>`\n when it takes none. A component body is inserted into `#bodyContainer` from `ngAfterViewInit`. -->\n<ng-template #tplContentBody>\n <ng-container #bodyContainer>\n @if (contentKind() !== 'component') {\n @switch (contentKind()) {\n @case ('template') {\n <ng-container [ngTemplateOutlet]=\"$any(kbqContent())\" />\n }\n @case ('string') {\n <div [innerHTML]=\"kbqContent()\"></div>\n }\n @default {\n <ng-container [ngTemplateOutlet]=\"tplOriginContent\" />\n }\n }\n }\n </ng-container>\n</ng-template>\n\n<!-- [Predefined] Default Modal Content -->\n<ng-template #tplContentDefault>\n @if (kbqTitle() || kbqCaption()) {\n <div class=\"kbq-modal-header\" [kbqOverflowShadowTop]=\"modalBodyOverflow\">\n <div class=\"kbq-modal-header-content\">\n @if (kbqTitle()) {\n <div class=\"kbq-modal-title\" kbq-title [attr.id]=\"titleId\">\n @switch (titleKind()) {\n @case ('template') {\n <ng-container [ngTemplateOutlet]=\"$any(kbqTitle())\" />\n }\n @case ('string') {\n <div [innerHTML]=\"kbqTitle()\"></div>\n }\n }\n </div>\n }\n @if (kbqCaption()) {\n <div class=\"kbq-modal-caption\" kbq-title [attr.id]=\"captionId\">\n @switch (captionKind()) {\n @case ('template') {\n <ng-container [ngTemplateOutlet]=\"$any(kbqCaption())\" />\n }\n @case ('string') {\n <div [innerHTML]=\"kbqCaption()\"></div>\n }\n }\n </div>\n }\n </div>\n @if (kbqClosable()) {\n <button\n kbq-button\n type=\"button\"\n class=\"kbq-modal-close kbq-button_transparent\"\n [attr.aria-label]=\"a11yLocaleConfiguration().close\"\n [color]=\"'contrast'\"\n (click)=\"onClickCloseBtn()\"\n >\n <i kbq-icon=\"kbq-xmark_16\" [color]=\"componentColors.Contrast\"></i>\n </button>\n }\n </div>\n }\n <div\n #modalBodyOverflow=\"kbqOverflowShadowContainer\"\n kbqOverflowShadowContainer\n kbqScrollbarViewport\n class=\"kbq-modal-body\"\n [style]=\"kbqBodyStyle()\"\n >\n <ng-container [ngTemplateOutlet]=\"tplContentBody\" />\n </div>\n @if (hasFooter) {\n <div class=\"kbq-modal-footer\" [kbqOverflowShadowBottom]=\"modalBodyOverflow\">\n @switch (footerKind()) {\n @case ('template') {\n <ng-container [ngTemplateOutlet]=\"$any(footer())\" />\n }\n @case ('string') {\n <div [innerHTML]=\"footer()\"></div>\n }\n @case ('buttons') {\n @for (button of $any(footer()); track button) {\n @if (getButtonCallableProp(button, 'show')) {\n <button\n kbq-button\n [attr.autofocus]=\"button.autoFocus ? '' : null\"\n [attr.kbq-modal-main-action]=\"button.kbqModalMainAction ? '' : null\"\n [class.kbq-progress]=\"getButtonCallableProp(button, 'loading')\"\n [color]=\"button.type\"\n [disabled]=\"!!getButtonCallableProp(button, 'disabled')\"\n (click)=\"onButtonClick(button)\"\n >\n {{ button.label }}\n </button>\n }\n }\n }\n @default {\n @if (kbqOkText()) {\n <button\n kbq-button\n [attr.autofocus]=\"true\"\n [class.kbq-progress]=\"loading('ok')\"\n [color]=\"componentColors.Contrast\"\n (click)=\"onClickOkCancel('ok')\"\n >\n {{ kbqOkText() }}\n </button>\n }\n @if (kbqCancelText()) {\n <button kbq-button [class.kbq-progress]=\"loading('cancel')\" (click)=\"onClickOkCancel('cancel')\">\n {{ kbqCancelText() }}\n </button>\n }\n }\n }\n </div>\n }\n</ng-template>\n<!-- /[Predefined] Default Modal Content -->\n\n<!-- [Predefined] Confirm Modal Content -->\n<ng-template #tplContentConfirm>\n <div\n #confirmBodyOverflow=\"kbqOverflowShadowContainer\"\n kbqOverflowShadowContainer\n kbqScrollbarViewport\n class=\"kbq-modal-body\"\n [style]=\"kbqBodyStyle()\"\n >\n <ng-container [ngTemplateOutlet]=\"tplContentBody\" />\n </div>\n @if (kbqOkText() || kbqCancelText()) {\n <div class=\"kbq-confirm-footer\" [kbqOverflowShadowBottom]=\"confirmBodyOverflow\">\n @if (kbqOkText()) {\n <button\n kbq-button\n [attr.autofocus]=\"true\"\n [class.kbq-progress]=\"loading('ok')\"\n [color]=\"kbqOkType()\"\n (click)=\"onClickOkCancel('ok')\"\n >\n {{ kbqOkText() }}\n </button>\n }\n @if (kbqCancelText()) {\n <button kbq-button [class.kbq-progress]=\"loading('cancel')\" (click)=\"onClickOkCancel('cancel')\">\n {{ kbqCancelText() }}\n </button>\n }\n </div>\n }\n</ng-template>\n<!-- /[Predefined] Confirm Modal Content -->\n", styles: [".kbq-confirm .kbq-modal-close{display:none}.kbq-confirm .kbq-confirm-footer{display:flex;gap:var(--kbq-modal-size-footer-content-gap-horizontal)}@keyframes mcFadeIn{0%{opacity:0}to{opacity:1}}@keyframes mcFadeOut{0%{opacity:1}to{opacity:0}}@keyframes mcZoomIn{0%{opacity:0;transform:translateY(-25%)}to{opacity:1;transform:scale(1)}}@keyframes mcZoomOut{0%{transform:scale(1)}to{opacity:0;transform:translateY(-30%)}}.fade-enter,.fade-leave{animation-duration:.3s;animation-fill-mode:both;animation-play-state:paused}.fade-enter.fade-enter-active{animation-name:mcFadeIn;animation-play-state:running}.fade-leave.fade-leave-active{animation-name:mcFadeOut;animation-play-state:running;pointer-events:none}.fade-enter{opacity:0;animation-timing-function:ease-out}.fade-leave{animation-timing-function:ease-out}.zoom-enter,.zoom-leave{animation-duration:.3s;animation-fill-mode:both;animation-play-state:paused}.zoom-enter.zoom-enter-active{animation-name:mcZoomIn;animation-play-state:running}.zoom-leave.zoom-leave-active{animation-name:mcZoomOut;animation-play-state:running;pointer-events:none}.zoom-enter{transform:translateY(-25%);animation-timing-function:cubic-bezier(.075,.82,.165,1)}.zoom-leave{transform:translate(0);animation-timing-function:cubic-bezier(.785,.135,.15,.86)}@media(prefers-reduced-motion:reduce){.fade-enter,.fade-leave{animation:none;opacity:1;transform:none}}@media(prefers-reduced-motion:reduce){.zoom-enter,.zoom-leave{animation:none;opacity:1;transform:none}}.kbq-modal-container{box-sizing:border-box;position:relative;top:var(--kbq-modal-size-viewport-inset);border-radius:var(--kbq-modal-size-border-radius)}@supports (corner-shape: squircle){.kbq-modal-container{corner-shape:squircle;border-radius:clamp(var(--kbq-modal-size-border-radius) * 1.85,var(--kbq-modal-size-border-radius) * 2.3 - 3.6px,var(--kbq-modal-size-border-radius) * 2)}}.kbq-modal-container{display:flex;flex-direction:column;width:auto;max-height:calc(100vh - 2 * var(--kbq-modal-size-viewport-inset));margin:0 auto;list-style:none}.kbq-modal-container.kbq-modal_small{width:var(--kbq-modal-size-small-width)}.kbq-modal-container.kbq-modal_medium{width:var(--kbq-modal-size-medium-width)}.kbq-modal-container.kbq-modal_large{width:var(--kbq-modal-size-large-width)}.kbq-modal-container.kbq-modal_no-footer .kbq-modal-body{padding-bottom:var(--kbq-modal-size-content-padding-bottom-without-footer)}.kbq-modal-container .kbq-modal-close{position:absolute;top:var(--kbq-size-l);right:var(--kbq-size-l)}.kbq-modal-wrap{position:fixed;inset:0;overflow:auto;-webkit-overflow-scrolling:touch;outline:0}.kbq-modal-content{position:relative;border-radius:var(--kbq-modal-size-border-radius)}@supports (corner-shape: squircle){.kbq-modal-content{corner-shape:squircle;border-radius:clamp(var(--kbq-modal-size-border-radius) * 1.85,var(--kbq-modal-size-border-radius) * 2.3 - 3.6px,var(--kbq-modal-size-border-radius) * 2)}}.kbq-modal-content{display:flex;flex:1 1 auto;flex-direction:column;min-height:0;background-clip:padding-box}.kbq-modal-content-host{display:flex;flex:1 1 auto;flex-direction:column;min-height:0}.kbq-modal-header{display:flex;flex:0 0 auto;align-items:center;justify-content:space-between;padding:var(--kbq-modal-size-header-padding-vertical) var(--kbq-modal-size-header-padding-right) var(--kbq-modal-size-header-padding-vertical) var(--kbq-modal-size-header-padding-left)}.kbq-modal-header+.kbq-modal-body{padding-top:var(--kbq-modal-size-content-padding-top)}.kbq-modal-title{display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;overflow:hidden;padding-top:var(--kbq-size-3xs);padding-bottom:var(--kbq-size-3xs)}.kbq-modal-header-content{display:flex;flex:1;flex-direction:column;min-width:0}.kbq-modal-caption{display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;overflow:hidden;text-overflow:ellipsis}.kbq-modal-body{display:block;flex:1 1 auto;min-height:0;overflow-y:auto;padding:var(--kbq-modal-size-content-padding-top-without-header) var(--kbq-modal-size-content-padding-horizontal) var(--kbq-modal-size-content-padding-bottom) var(--kbq-modal-size-content-padding-horizontal);overflow-wrap:break-word}.kbq-modal-footer,.kbq-confirm-footer{display:flex;flex:0 0 auto;align-items:center;padding:var(--kbq-modal-size-footer-padding-vertical) var(--kbq-modal-size-footer-padding-horizontal);gap:var(--kbq-modal-size-footer-content-gap-horizontal)}.kbq-modal-mask{position:fixed;inset:0;height:100%}.kbq-modal-mask.kbq-modal-mask-hidden{display:none}.kbq-modal-container{background:var(--kbq-modal-container-background);box-shadow:var(--kbq-modal-container-shadow)}.kbq-modal-container .kbq-modal-header .kbq-modal-title{color:var(--kbq-modal-header-text-color)}.kbq-modal-container .kbq-modal-header .kbq-modal-close{color:var(--kbq-modal-close-button-color)}.kbq-modal-container .kbq-modal-content{color:var(--kbq-modal-content-text-color)}.kbq-modal-container .kbq-modal-caption{color:var(--kbq-foreground-contrast-secondary)}.kbq-modal-mask{background-color:var(--kbq-modal-overlay-background)}.kbq-modal-title{font-size:var(--kbq-typography-title-font-size);font-style:var(--kbq-typography-title-font-style);font-weight:var(--kbq-typography-title-font-weight);line-height:var(--kbq-typography-title-line-height);font-family:var(--kbq-typography-title-font-family);text-transform:var(--kbq-typography-title-text-transform);font-feature-settings:var(--kbq-typography-title-font-feature-settings);letter-spacing:var(--kbq-typography-title-letter-spacing)}.kbq-modal-caption,.kbq-modal-body{font-size:var(--kbq-typography-text-normal-font-size);font-style:var(--kbq-typography-text-normal-font-style);font-weight:var(--kbq-typography-text-normal-font-weight);line-height:var(--kbq-typography-text-normal-line-height);font-family:var(--kbq-typography-text-normal-font-family);text-transform:var(--kbq-typography-text-normal-text-transform);font-feature-settings:var(--kbq-typography-text-normal-font-feature-settings);letter-spacing:var(--kbq-typography-text-normal-letter-spacing)}\n", ".kbq-modal{--kbq-modal-size-small-width: 400px;--kbq-modal-size-medium-width: 640px;--kbq-modal-size-large-width: 960px;--kbq-modal-size-border-radius: var(--kbq-size-m);--kbq-modal-size-header-padding-vertical: var(--kbq-size-l);--kbq-modal-size-header-padding-left: var(--kbq-size-xxl);--kbq-modal-size-header-padding-right: var(--kbq-size-6xl);--kbq-modal-size-content-padding-horizontal: var(--kbq-size-xxl);--kbq-modal-size-viewport-inset: var(--kbq-size-5xl);--kbq-modal-size-content-padding-top: 1px;--kbq-modal-size-content-padding-bottom: var(--kbq-size-s);--kbq-modal-size-content-padding-top-without-header: var(--kbq-size-xxl);--kbq-modal-size-content-padding-bottom-without-footer: var(--kbq-size-4xl);--kbq-modal-size-footer-padding-horizontal: var(--kbq-size-xxl);--kbq-modal-size-footer-padding-vertical: var(--kbq-size-xl);--kbq-modal-size-footer-content-gap-horizontal: var(--kbq-size-l);--kbq-modal-overlay-background: var(--kbq-background-overlay);--kbq-modal-container-background: var(--kbq-background-card);--kbq-modal-container-shadow: var(--kbq-shadow-overlay);--kbq-modal-close-button-color: var(--kbq-icon-contrast);--kbq-modal-header-text-color: var(--kbq-foreground-contrast);--kbq-modal-content-text-color: var(--kbq-foreground-contrast)}\n"] }]
1088
+ }], propDecorators: { kbqModalType: [{ type: i0.Input, args: [{ isSignal: true, alias: "kbqModalType", required: false }] }], kbqComponent: [{ type: i0.Input, args: [{ isSignal: true, alias: "kbqComponent", required: false }] }], kbqContent: [{ type: i0.Input, args: [{ isSignal: true, alias: "kbqContent", required: false }] }], kbqFooter: [{ type: i0.Input, args: [{ isSignal: true, alias: "kbqFooter", required: false }] }], kbqVisible: [{ type: i0.Input, args: [{ isSignal: true, alias: "kbqVisible", required: false }] }, { type: i0.Output, args: ["kbqVisibleChange"] }], kbqWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "kbqWidth", required: false }] }], kbqSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "kbqSize", required: false }] }], kbqWrapClassName: [{ type: i0.Input, args: [{ isSignal: true, alias: "kbqWrapClassName", required: false }] }], kbqClassName: [{ type: i0.Input, args: [{ isSignal: true, alias: "kbqClassName", required: false }] }], kbqStyle: [{ type: i0.Input, args: [{ isSignal: true, alias: "kbqStyle", required: false }] }], kbqTitle: [{ type: i0.Input, args: [{ isSignal: true, alias: "kbqTitle", required: false }] }], kbqCaption: [{ type: i0.Input, args: [{ isSignal: true, alias: "kbqCaption", required: false }] }], kbqCloseByESC: [{ type: i0.Input, args: [{ isSignal: true, alias: "kbqCloseByESC", required: false }] }], kbqAutoFocus: [{ type: i0.Input, args: [{ isSignal: true, alias: "kbqAutoFocus", required: false }] }], kbqAriaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "kbqAriaLabel", required: false }] }], kbqClosable: [{ type: i0.Input, args: [{ isSignal: true, alias: "kbqClosable", required: false }] }], kbqMask: [{ type: i0.Input, args: [{ isSignal: true, alias: "kbqMask", required: false }] }], kbqMaskClosable: [{ type: i0.Input, args: [{ isSignal: true, alias: "kbqMaskClosable", required: false }] }], kbqMaskStyle: [{ type: i0.Input, args: [{ isSignal: true, alias: "kbqMaskStyle", required: false }] }], kbqBodyStyle: [{ type: i0.Input, args: [{ isSignal: true, alias: "kbqBodyStyle", required: false }] }], kbqAfterOpenOutput: [{ type: i0.Output, args: ["kbqAfterOpen"] }], kbqAfterCloseOutput: [{ type: i0.Output, args: ["kbqAfterClose"] }], kbqBeforeCloseOutput: [{ type: i0.Output, args: ["kbqBeforeClose"] }], kbqOkText: [{ type: i0.Input, args: [{ isSignal: true, alias: "kbqOkText", required: false }] }], kbqOkType: [{ type: i0.Input, args: [{ isSignal: true, alias: "kbqOkType", required: false }] }], kbqRestoreFocus: [{ type: i0.Input, args: [{ isSignal: true, alias: "kbqRestoreFocus", required: false }] }], kbqOkLoading: [{ type: i0.Input, args: [{ isSignal: true, alias: "kbqOkLoading", required: false }] }], kbqOkClick: [{ type: i0.Input, args: [{ isSignal: true, alias: "kbqOkClick", required: false }] }], kbqOnOkOutput: [{ type: i0.Output, args: ["kbqOnOk"] }], kbqCancelText: [{ type: i0.Input, args: [{ isSignal: true, alias: "kbqCancelText", required: false }] }], kbqCancelLoading: [{ type: i0.Input, args: [{ isSignal: true, alias: "kbqCancelLoading", required: false }] }], kbqCancelClick: [{ type: i0.Input, args: [{ isSignal: true, alias: "kbqCancelClick", required: false }] }], kbqOnCancelOutput: [{ type: i0.Output, args: ["kbqOnCancel"] }], modalContainer: [{ type: i0.ViewChild, args: ['modalContainer', { isSignal: true }] }], bodyContainer: [{ type: i0.ViewChild, args: ['bodyContainer', { ...{ read: ViewContainerRef }, isSignal: true }] }], scrollbarViewports: [{ type: i0.ViewChildren, args: [i0.forwardRef(() => KbqScrollbarViewport), { isSignal: true }] }], trapFocus: [{ type: i0.ViewChild, args: [i0.forwardRef(() => CdkTrapFocus), { isSignal: true }] }], kbqGetContainer: [{ type: i0.Input, args: [{ isSignal: true, alias: "kbqGetContainer", required: false }] }] } });
747
1089
  function isPromise(obj) {
748
1090
  return (!!obj &&
749
1091
  (typeof obj === 'object' || typeof obj === 'function') &&
@@ -753,32 +1095,41 @@ function isPromise(obj) {
753
1095
 
754
1096
  class KbqModalTitle {
755
1097
  constructor() {
756
- this.modal = inject(KbqModalComponent);
757
- }
758
- /** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.30", ngImport: i0, type: KbqModalTitle, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
759
- /** @nocollapse */ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.30", type: KbqModalTitle, isStandalone: true, selector: "[kbq-modal-title], kbq-modal-title, [kbqModalTitle]", host: { properties: { "class.kbq-modal-header_closable": "modal.kbqClosable", "style.box-shadow": "modal.bodyOverflow().top ? \"var(--kbq-shadow-overflow-normal-bottom)\" : null" }, classAttribute: "kbq-modal-header" }, ngImport: i0, template: `
1098
+ this.modal = inject(KBQ_MODAL);
1099
+ /** Accessible name for the icon-only close button. */
1100
+ this.a11yLocaleConfiguration = inject(KbqLocaleOverridesDirective, { self: true }).read('a11y', KBQ_A11Y_LOCALE_CONFIGURATION);
1101
+ // Lets the dialog point `aria-labelledby` at this heading instead of going unnamed.
1102
+ this.modal.registerTitle();
1103
+ }
1104
+ /** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: KbqModalTitle, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1105
+ /** @nocollapse */ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.25", type: KbqModalTitle, isStandalone: true, selector: "[kbq-modal-title], kbq-modal-title, [kbqModalTitle]", host: { properties: { "style.box-shadow": "modal.bodyOverflow().top ? \"var(--kbq-shadow-overflow-normal-bottom)\" : null" }, classAttribute: "kbq-modal-header" }, hostDirectives: [{ directive: i1.KbqLocaleOverridesDirective, inputs: ["kbqLocaleOverrides", "localeOverrides"] }], ngImport: i0, template: `
760
1106
  <div class="kbq-modal-header-content">
761
- <div class="kbq-modal-title" kbq-title>
1107
+ <div class="kbq-modal-title" kbq-title [attr.id]="modal.titleId">
762
1108
  <ng-content />
763
1109
  </div>
764
1110
 
765
1111
  <ng-content select="kbq-modal-caption, [kbq-modal-caption], [kbqModalCaption]" />
766
1112
  </div>
767
1113
 
768
- @if (modal.kbqClosable) {
1114
+ <!-- Outside the two-line clamp of the title, so actions next to the heading do not need
1115
+ to pierce encapsulation to escape it. -->
1116
+ <ng-content select="[kbqModalTitleActions]" />
1117
+
1118
+ @if (modal.kbqClosable()) {
769
1119
  <button
770
1120
  class="kbq-modal-close kbq-button_transparent"
771
1121
  type="button"
772
1122
  kbq-button
1123
+ [attr.aria-label]="a11yLocaleConfiguration().close"
773
1124
  [color]="'contrast'"
774
1125
  (click)="modal.onClickCloseBtn()"
775
1126
  >
776
1127
  <i kbq-icon="kbq-xmark_16" [color]="modal.componentColors.Contrast"></i>
777
1128
  </button>
778
1129
  }
779
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: KbqIconModule }, { kind: "component", type: i2.KbqIcon, selector: "[kbq-icon]", inputs: ["small", "autoColor", "kbq-icon"] }, { kind: "ngmodule", type: KbqButtonModule }, { kind: "component", type: i1.KbqButton, selector: "[kbq-button]", inputs: ["kbqStyle", "disabled", "tabIndex"] }, { kind: "directive", type: i1.KbqButtonCssStyler, selector: "[kbq-button]" }, { kind: "directive", type: KbqTitleDirective, selector: "[kbq-title]", inputs: ["kbq-title"], exportAs: ["kbqTitle"] }] }); }
1130
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: KbqIconModule }, { kind: "component", type: i3.KbqIcon, selector: "[kbq-icon]", inputs: ["aria-hidden", "iconSize", "autoColor", "kbq-icon"] }, { kind: "ngmodule", type: KbqButtonModule }, { kind: "component", type: i2.KbqButton, selector: "[kbq-button]", inputs: ["kbqStyle", "disabled", "tabIndex"] }, { kind: "directive", type: i2.KbqButtonCssStyler, selector: "[kbq-button]" }, { kind: "directive", type: KbqTitleDirective, selector: "[kbq-title]", inputs: ["kbq-title", "ignoreTooltipPointerEvents"], exportAs: ["kbqTitle"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
780
1131
  }
781
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.30", ngImport: i0, type: KbqModalTitle, decorators: [{
1132
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: KbqModalTitle, decorators: [{
782
1133
  type: Component,
783
1134
  args: [{
784
1135
  selector: `[kbq-modal-title], kbq-modal-title, [kbqModalTitle]`,
@@ -789,18 +1140,23 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.30", ngImpo
789
1140
  ],
790
1141
  template: `
791
1142
  <div class="kbq-modal-header-content">
792
- <div class="kbq-modal-title" kbq-title>
1143
+ <div class="kbq-modal-title" kbq-title [attr.id]="modal.titleId">
793
1144
  <ng-content />
794
1145
  </div>
795
1146
 
796
1147
  <ng-content select="kbq-modal-caption, [kbq-modal-caption], [kbqModalCaption]" />
797
1148
  </div>
798
1149
 
799
- @if (modal.kbqClosable) {
1150
+ <!-- Outside the two-line clamp of the title, so actions next to the heading do not need
1151
+ to pierce encapsulation to escape it. -->
1152
+ <ng-content select="[kbqModalTitleActions]" />
1153
+
1154
+ @if (modal.kbqClosable()) {
800
1155
  <button
801
1156
  class="kbq-modal-close kbq-button_transparent"
802
1157
  type="button"
803
1158
  kbq-button
1159
+ [attr.aria-label]="a11yLocaleConfiguration().close"
804
1160
  [color]="'contrast'"
805
1161
  (click)="modal.onClickCloseBtn()"
806
1162
  >
@@ -808,25 +1164,34 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.30", ngImpo
808
1164
  </button>
809
1165
  }
810
1166
  `,
1167
+ changeDetection: ChangeDetectionStrategy.OnPush,
811
1168
  host: {
812
1169
  class: 'kbq-modal-header',
813
- '[class.kbq-modal-header_closable]': 'modal.kbqClosable',
814
1170
  '[style.box-shadow]': 'modal.bodyOverflow().top ? "var(--kbq-shadow-overflow-normal-bottom)" : null'
815
- }
1171
+ },
1172
+ hostDirectives: [
1173
+ { directive: KbqLocaleOverridesDirective, inputs: ['kbqLocaleOverrides: localeOverrides'] }
1174
+ ]
816
1175
  }]
817
- }] });
1176
+ }], ctorParameters: () => [] });
818
1177
  /**
819
1178
  * Caption of a manually composed modal (`kbqComponent`). Projected into the header rendered by
820
1179
  * `KbqModalTitle`, below the title, and clamped to two lines. The resulting markup matches the
821
1180
  * header of a modal created via `KbqModalService.create`.
822
1181
  */
823
1182
  class KbqModalCaption {
824
- /** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.30", ngImport: i0, type: KbqModalCaption, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
825
- /** @nocollapse */ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.30", type: KbqModalCaption, isStandalone: true, selector: "[kbq-modal-caption], kbq-modal-caption, [kbqModalCaption]", host: { classAttribute: "kbq-modal-caption" }, hostDirectives: [{ directive: i3.KbqTitleDirective }], ngImport: i0, template: `
1183
+ constructor() {
1184
+ this.modal = inject(KBQ_MODAL);
1185
+ // Lets the dialog point `aria-describedby` at this caption; without it the composed path
1186
+ // renders a description no screen reader is told about.
1187
+ this.modal.registerCaption();
1188
+ }
1189
+ /** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: KbqModalCaption, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1190
+ /** @nocollapse */ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.25", type: KbqModalCaption, isStandalone: true, selector: "[kbq-modal-caption], kbq-modal-caption, [kbqModalCaption]", host: { properties: { "attr.id": "modal.captionId" }, classAttribute: "kbq-modal-caption" }, hostDirectives: [{ directive: i4.KbqTitleDirective }], ngImport: i0, template: `
826
1191
  <ng-content />
827
1192
  `, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
828
1193
  }
829
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.30", ngImport: i0, type: KbqModalCaption, decorators: [{
1194
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: KbqModalCaption, decorators: [{
830
1195
  type: Component,
831
1196
  args: [{
832
1197
  selector: `[kbq-modal-caption], kbq-modal-caption, [kbqModalCaption]`,
@@ -835,11 +1200,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.30", ngImpo
835
1200
  `,
836
1201
  changeDetection: ChangeDetectionStrategy.OnPush,
837
1202
  host: {
838
- class: 'kbq-modal-caption'
1203
+ class: 'kbq-modal-caption',
1204
+ '[attr.id]': 'modal.captionId'
839
1205
  },
840
1206
  hostDirectives: [KbqTitleDirective]
841
1207
  }]
842
- }] });
1208
+ }], ctorParameters: () => [] });
843
1209
  /**
844
1210
  * Scrollable body of a manually composed modal (`kbqComponent`). Publishes its scroll-shadow
845
1211
  * state onto the modal instance so a sibling `KbqModalTitle`/`KbqModalFooter` can render the
@@ -847,31 +1213,36 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.30", ngImpo
847
1213
  */
848
1214
  class KbqModalBody {
849
1215
  constructor() {
850
- this.modal = inject(KbqModalComponent);
1216
+ this.modal = inject(KBQ_MODAL);
851
1217
  this.overflowContainer = inject(KbqOverflowShadowContainer);
852
- effect(() => this.modal.bodyOverflow.set(this.overflowContainer.overflow()));
1218
+ this.scrollbarViewport = inject(KbqScrollbarViewport);
1219
+ effect(() => this.modal.setBodyOverflow(this.overflowContainer.overflow()));
1220
+ this.modal.afterOpen.pipe(takeUntilDestroyed()).subscribe(() => this.scrollbarViewport.flashScrollIndicators());
853
1221
  }
854
- /** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.30", ngImport: i0, type: KbqModalBody, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
855
- /** @nocollapse */ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.30", type: KbqModalBody, isStandalone: true, selector: "[kbq-modal-body], kbq-modal-body, [kbqModalBody]", host: { classAttribute: "kbq-modal-body kbq-scrollbar" }, hostDirectives: [{ directive: i4.KbqOverflowShadowContainer }], ngImport: i0 }); }
1222
+ /** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: KbqModalBody, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
1223
+ /** @nocollapse */ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.25", type: KbqModalBody, isStandalone: true, selector: "[kbq-modal-body], kbq-modal-body, [kbqModalBody]", host: { classAttribute: "kbq-modal-body" }, hostDirectives: [{ directive: i1.KbqOverflowShadowContainer }, { directive: i5.KbqScrollbarViewport }], ngImport: i0 }); }
856
1224
  }
857
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.30", ngImport: i0, type: KbqModalBody, decorators: [{
1225
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: KbqModalBody, decorators: [{
858
1226
  type: Directive,
859
1227
  args: [{
860
1228
  selector: `[kbq-modal-body], kbq-modal-body, [kbqModalBody]`,
861
1229
  host: {
862
- class: 'kbq-modal-body kbq-scrollbar'
1230
+ class: 'kbq-modal-body'
863
1231
  },
864
- hostDirectives: [KbqOverflowShadowContainer]
1232
+ hostDirectives: [KbqOverflowShadowContainer, KbqScrollbarViewport]
865
1233
  }]
866
1234
  }], ctorParameters: () => [] });
867
1235
  class KbqModalFooter {
868
1236
  constructor() {
869
- this.modal = inject(KbqModalComponent);
1237
+ this.modal = inject(KBQ_MODAL);
1238
+ // Without this the dialog cannot tell a composed footer from no footer at all, and would
1239
+ // add the no-footer bottom padding underneath one.
1240
+ this.modal.registerFooter();
870
1241
  }
871
- /** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.30", ngImport: i0, type: KbqModalFooter, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
872
- /** @nocollapse */ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.30", type: KbqModalFooter, isStandalone: true, selector: "[kbq-modal-footer], kbq-modal-footer, [kbqModalFooter]", host: { properties: { "style.box-shadow": "modal.bodyOverflow().bottom ? \"var(--kbq-shadow-overflow-normal-top)\" : null" }, classAttribute: "kbq-modal-footer" }, ngImport: i0 }); }
1242
+ /** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: KbqModalFooter, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
1243
+ /** @nocollapse */ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.25", type: KbqModalFooter, isStandalone: true, selector: "[kbq-modal-footer], kbq-modal-footer, [kbqModalFooter]", host: { properties: { "style.box-shadow": "modal.bodyOverflow().bottom ? \"var(--kbq-shadow-overflow-normal-top)\" : null" }, classAttribute: "kbq-modal-footer" }, ngImport: i0 }); }
873
1244
  }
874
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.30", ngImport: i0, type: KbqModalFooter, decorators: [{
1245
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: KbqModalFooter, decorators: [{
875
1246
  type: Directive,
876
1247
  args: [{
877
1248
  selector: `[kbq-modal-footer], kbq-modal-footer, [kbqModalFooter]`,
@@ -880,12 +1251,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.30", ngImpo
880
1251
  '[style.box-shadow]': 'modal.bodyOverflow().bottom ? "var(--kbq-shadow-overflow-normal-top)" : null'
881
1252
  }
882
1253
  }]
883
- }] });
1254
+ }], ctorParameters: () => [] });
884
1255
  class KbqModalMainAction {
885
- /** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.30", ngImport: i0, type: KbqModalMainAction, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
886
- /** @nocollapse */ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.30", type: KbqModalMainAction, isStandalone: true, selector: "[kbq-modal-main-action]", ngImport: i0 }); }
1256
+ /** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: KbqModalMainAction, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
1257
+ /** @nocollapse */ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.25", type: KbqModalMainAction, isStandalone: true, selector: "[kbq-modal-main-action]", ngImport: i0 }); }
887
1258
  }
888
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.30", ngImport: i0, type: KbqModalMainAction, decorators: [{
1259
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: KbqModalMainAction, decorators: [{
889
1260
  type: Directive,
890
1261
  args: [{
891
1262
  selector: `[kbq-modal-main-action]`
@@ -896,22 +1267,21 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.30", ngImpo
896
1267
  const KBQ_MODAL_DATA = new InjectionToken('KbqModalData');
897
1268
  /**
898
1269
  * A builder used for managing service creating modals
1270
+ *
899
1271
  * @docs-private
900
1272
  */
901
1273
  class ModalBuilderForService {
902
- constructor(overlay, options = {}, injector) {
1274
+ constructor(overlay, options = {}, injector,
1275
+ /** Lifetime of the caller. The dialog is destroyed with it. */
1276
+ openerDestroyRef = null) {
903
1277
  this.overlay = overlay;
904
1278
  this.options = options;
905
1279
  this.injector = injector;
906
1280
  this.createModal();
907
- if (!('kbqGetContainer' in options)) {
908
- options.kbqGetContainer = undefined;
909
- }
910
- this.changeProps(options);
911
- // Defers ESC handling until the modal is fully open, avoiding premature close during the opening animation.
912
- this.modalRef.instance.kbqAfterOpen.pipe(switchMap(() => this.overlayRef.keydownEvents()), filter((event) => {
913
- return !!(event.keyCode === ESCAPE && options.kbqCloseByESC);
914
- })).subscribe(() => this.getInstance()?.handleCloseResult('cancel', () => true));
1281
+ this.mirrorEmitters(options);
1282
+ // Nobody owns the builder, so without this the dialog outlives whatever opened it: it stays
1283
+ // painted over the next view, `afterClose` never emits, and the body scroll lock is kept.
1284
+ this.detachFromOpener = openerDestroyRef?.onDestroy(() => this.destroyModal());
915
1285
  this.modalRef.instance.open();
916
1286
  this.modalRef.instance.kbqAfterClose.subscribe(() => this.destroyModal());
917
1287
  }
@@ -920,19 +1290,41 @@ class ModalBuilderForService {
920
1290
  }
921
1291
  destroyModal() {
922
1292
  if (this.modalRef) {
1293
+ this.detachFromOpener?.();
1294
+ this.detachFromOpener = undefined;
923
1295
  this.overlayRef.dispose();
924
1296
  this.modalRef = null;
925
1297
  }
926
1298
  }
927
- changeProps(options) {
928
- if (this.modalRef) {
929
- // here not limit user's inputs at runtime
930
- Object.assign(this.modalRef.instance, options);
1299
+ /**
1300
+ * Mirrors the caller's emitters onto the dialog's own outputs. The option values themselves
1301
+ * reach the dialog through `KBQ_MODAL_OPTIONS`, as the initial values of its inputs — a dialog
1302
+ * created by the service has no template bindings to carry them.
1303
+ */
1304
+ mirrorEmitters(options) {
1305
+ if (!this.modalRef)
1306
+ return;
1307
+ const { kbqAfterOpen, kbqAfterClose, kbqOnOk, kbqOnCancel } = options;
1308
+ // Mirrored, never substituted, so `afterOpen`/`afterClose` on the returned ref keep working
1309
+ // and the overlay teardown does not hang off an emitter the caller owns and can complete.
1310
+ if (kbqAfterOpen) {
1311
+ this.modalRef.instance.kbqAfterOpen.subscribe(() => kbqAfterOpen.emit());
1312
+ }
1313
+ if (kbqAfterClose) {
1314
+ this.modalRef.instance.kbqAfterClose.subscribe((result) => kbqAfterClose.emit(result));
1315
+ }
1316
+ if (kbqOnOk) {
1317
+ this.modalRef.instance.kbqOnOk.subscribe((instance) => kbqOnOk.emit(instance));
1318
+ }
1319
+ if (kbqOnCancel) {
1320
+ this.modalRef.instance.kbqOnCancel.subscribe((instance) => kbqOnCancel.emit(instance));
931
1321
  }
932
1322
  }
933
1323
  // Create component to ApplicationRef
934
1324
  createModal() {
935
- this.overlayRef = this.overlay.create();
1325
+ // Second line of defence behind the `DestroyRef` above: a router navigation disposes the
1326
+ // overlay even when the dialog was opened from a longer-lived injector.
1327
+ this.overlayRef = this.overlay.create(new OverlayConfig({ disposeOnNavigation: true }));
936
1328
  this.overlayRef.hostElement.classList.add('kbq-modal-overlay');
937
1329
  this.modalRef = this.overlayRef.attach(new ComponentPortal(KbqModalComponent, undefined, this.injector));
938
1330
  }
@@ -954,46 +1346,31 @@ class KbqModalService {
954
1346
  closeAll() {
955
1347
  this.modalControl.closeAll();
956
1348
  }
1349
+ /**
1350
+ * Opens a dialog. Its lifetime is bound to `options.injector` — the caller's injector when one
1351
+ * is passed, the root environment injector otherwise — so destroying the opener closes it.
1352
+ */
957
1353
  create(options = {}) {
958
- if (typeof options.kbqOnCancel !== 'function') {
959
- // Leave an empty function to close this modal by default
960
- options.kbqOnCancel = () => { };
961
- }
962
- if (typeof options.kbqOnOk !== 'function') {
963
- // Leave an empty function to close this modal by default
964
- options.kbqOnOk = () => { };
965
- }
966
- if (!('kbqCloseByESC' in options)) {
967
- options.kbqCloseByESC = true;
968
- }
969
- // Remove the Cancel button if the user not specify a Cancel button
970
- if (!('kbqCancelText' in options)) {
971
- options.kbqCancelText = undefined;
972
- }
973
- // Remove the Ok button if the user not specify an Ok button
974
- if (!('kbqOkText' in options)) {
975
- options.kbqOkText = undefined;
976
- }
977
- // Remove the footer if the user not specify a footer
978
- if (!('kbqFooter' in options)) {
979
- options.kbqFooter = undefined;
980
- }
1354
+ const parentInjector = options.injector || this.injector;
981
1355
  const injector = Injector.create({
982
- parent: options.injector || this.injector,
983
- providers: [{ provide: KBQ_MODAL_DATA, useValue: options.data }]
1356
+ parent: parentInjector,
1357
+ providers: [
1358
+ { provide: KBQ_MODAL_DATA, useValue: options.data },
1359
+ // The dialog reads these as the initial values of its inputs. A service-created
1360
+ // dialog has no template bindings, so that is the only way in.
1361
+ { provide: KBQ_MODAL_OPTIONS, useValue: options }
1362
+ ]
984
1363
  });
985
- return new ModalBuilderForService(this.overlay, options, injector).getInstance();
1364
+ // Read from the caller's injector, not the derived one: `Injector.create` provides a
1365
+ // `DestroyRef` of its own, and nothing ever destroys that.
1366
+ const openerDestroyRef = parentInjector.get(DestroyRef, null);
1367
+ return new ModalBuilderForService(this.overlay, options, injector, openerDestroyRef).getInstance();
986
1368
  }
987
1369
  confirm(options = {}, confirmType = 'confirm') {
988
1370
  if ('kbqFooter' in options && isDevMode()) {
989
1371
  // eslint-disable-next-line no-console
990
1372
  console.warn(`The Confirm-Modal doesn't support "kbqFooter", this property will be ignored.`);
991
1373
  }
992
- // NOTE: only support function currently by calling confirm()
993
- if (typeof options.kbqOnOk !== 'function') {
994
- // Leave an empty function to close this modal by default
995
- options.kbqOnOk = () => { };
996
- }
997
1374
  options.kbqModalType = 'confirm';
998
1375
  options.kbqClassName = `kbq-confirm kbq-confirm-${confirmType} ${options.kbqClassName || ''}`;
999
1376
  return this.create(options);
@@ -1005,20 +1382,21 @@ class KbqModalService {
1005
1382
  success(options = {}) {
1006
1383
  return this.confirm(options, 'success');
1007
1384
  }
1385
+ /** Opens a confirm dialog styled for a destructive action — the `warn` confirm type. */
1008
1386
  delete(options = {}) {
1009
1387
  return this.confirm(options, 'warn');
1010
1388
  }
1011
- /** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.30", ngImport: i0, type: KbqModalService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1012
- /** @nocollapse */ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.30", ngImport: i0, type: KbqModalService, providedIn: 'root' }); }
1389
+ /** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: KbqModalService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1390
+ /** @nocollapse */ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: KbqModalService, providedIn: 'root' }); }
1013
1391
  }
1014
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.30", ngImport: i0, type: KbqModalService, decorators: [{
1392
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: KbqModalService, decorators: [{
1015
1393
  type: Injectable,
1016
1394
  args: [{ providedIn: 'root' }]
1017
1395
  }] });
1018
1396
 
1019
1397
  class KbqModalModule {
1020
- /** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.30", ngImport: i0, type: KbqModalModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
1021
- /** @nocollapse */ static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.30", ngImport: i0, type: KbqModalModule, imports: [OverlayModule,
1398
+ /** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: KbqModalModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
1399
+ /** @nocollapse */ static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.2.25", ngImport: i0, type: KbqModalModule, imports: [OverlayModule,
1022
1400
  A11yModule,
1023
1401
  KbqButtonModule,
1024
1402
  KbqIconModule,
@@ -1036,7 +1414,7 @@ class KbqModalModule {
1036
1414
  KbqModalBody,
1037
1415
  KbqModalFooter,
1038
1416
  KbqModalMainAction] }); }
1039
- /** @nocollapse */ static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.30", ngImport: i0, type: KbqModalModule, providers: [
1417
+ /** @nocollapse */ static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: KbqModalModule, providers: [
1040
1418
  KbqModalControlService,
1041
1419
  KbqModalService,
1042
1420
  { provide: FocusTrapFactory, useClass: ConfigurableFocusTrapFactory }
@@ -1048,7 +1426,7 @@ class KbqModalModule {
1048
1426
  KbqModalComponent,
1049
1427
  KbqModalTitle] }); }
1050
1428
  }
1051
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.30", ngImport: i0, type: KbqModalModule, decorators: [{
1429
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: KbqModalModule, decorators: [{
1052
1430
  type: NgModule,
1053
1431
  args: [{
1054
1432
  imports: [
@@ -1086,5 +1464,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.30", ngImpo
1086
1464
  * Generated bundle index. Do not edit.
1087
1465
  */
1088
1466
 
1089
- export { KBQ_MODAL_DATA, KbqModalBody, KbqModalCaption, KbqModalComponent, KbqModalFooter, KbqModalMainAction, KbqModalModule, KbqModalRef, KbqModalService, KbqModalTitle, MODAL_ANIMATE_DURATION, ModalBuilderForService, ModalSize };
1467
+ export { CssUnitPipe, KBQ_MODAL, KBQ_MODAL_DATA, KBQ_MODAL_OPTIONS, KbqModalBody, KbqModalCaption, KbqModalComponent, KbqModalFooter, KbqModalMainAction, KbqModalModule, KbqModalRef, KbqModalService, KbqModalTitle, MODAL_ANIMATE_DURATION, ModalBuilderForService, ModalSize };
1090
1468
  //# sourceMappingURL=koobiq-components-modal.mjs.map