@testgorilla/tgo-ui 11.22.3 → 12.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 (225) hide show
  1. package/fesm2022/testgorilla-tgo-ui-components-accordion.mjs +335 -229
  2. package/fesm2022/testgorilla-tgo-ui-components-accordion.mjs.map +1 -1
  3. package/fesm2022/testgorilla-tgo-ui-components-ai-audio-circle.mjs +547 -465
  4. package/fesm2022/testgorilla-tgo-ui-components-ai-audio-circle.mjs.map +1 -1
  5. package/fesm2022/testgorilla-tgo-ui-components-ai-caveat.mjs +160 -75
  6. package/fesm2022/testgorilla-tgo-ui-components-ai-caveat.mjs.map +1 -1
  7. package/fesm2022/testgorilla-tgo-ui-components-ai-feedback.mjs +678 -278
  8. package/fesm2022/testgorilla-tgo-ui-components-ai-feedback.mjs.map +1 -1
  9. package/fesm2022/testgorilla-tgo-ui-components-alert-banner.mjs +337 -274
  10. package/fesm2022/testgorilla-tgo-ui-components-alert-banner.mjs.map +1 -1
  11. package/fesm2022/testgorilla-tgo-ui-components-audio-waveform.mjs +351 -192
  12. package/fesm2022/testgorilla-tgo-ui-components-audio-waveform.mjs.map +1 -1
  13. package/fesm2022/testgorilla-tgo-ui-components-autocomplete-v2.mjs +1950 -960
  14. package/fesm2022/testgorilla-tgo-ui-components-autocomplete-v2.mjs.map +1 -1
  15. package/fesm2022/testgorilla-tgo-ui-components-autocomplete.mjs +1206 -1044
  16. package/fesm2022/testgorilla-tgo-ui-components-autocomplete.mjs.map +1 -1
  17. package/fesm2022/testgorilla-tgo-ui-components-avatar.mjs +328 -182
  18. package/fesm2022/testgorilla-tgo-ui-components-avatar.mjs.map +1 -1
  19. package/fesm2022/testgorilla-tgo-ui-components-badge.mjs +383 -203
  20. package/fesm2022/testgorilla-tgo-ui-components-badge.mjs.map +1 -1
  21. package/fesm2022/testgorilla-tgo-ui-components-breadcrumb.mjs +553 -261
  22. package/fesm2022/testgorilla-tgo-ui-components-breadcrumb.mjs.map +1 -1
  23. package/fesm2022/testgorilla-tgo-ui-components-button.mjs +709 -739
  24. package/fesm2022/testgorilla-tgo-ui-components-button.mjs.map +1 -1
  25. package/fesm2022/testgorilla-tgo-ui-components-card.mjs +219 -184
  26. package/fesm2022/testgorilla-tgo-ui-components-card.mjs.map +1 -1
  27. package/fesm2022/testgorilla-tgo-ui-components-checkbox.mjs +515 -458
  28. package/fesm2022/testgorilla-tgo-ui-components-checkbox.mjs.map +1 -1
  29. package/fesm2022/testgorilla-tgo-ui-components-checklist.mjs +423 -162
  30. package/fesm2022/testgorilla-tgo-ui-components-checklist.mjs.map +1 -1
  31. package/fesm2022/testgorilla-tgo-ui-components-core.mjs +10784 -10996
  32. package/fesm2022/testgorilla-tgo-ui-components-core.mjs.map +1 -1
  33. package/fesm2022/testgorilla-tgo-ui-components-datepicker.mjs +810 -533
  34. package/fesm2022/testgorilla-tgo-ui-components-datepicker.mjs.map +1 -1
  35. package/fesm2022/testgorilla-tgo-ui-components-device-control.mjs +473 -116
  36. package/fesm2022/testgorilla-tgo-ui-components-device-control.mjs.map +1 -1
  37. package/fesm2022/testgorilla-tgo-ui-components-dialog.mjs +1149 -540
  38. package/fesm2022/testgorilla-tgo-ui-components-dialog.mjs.map +1 -1
  39. package/fesm2022/testgorilla-tgo-ui-components-divider.mjs +148 -84
  40. package/fesm2022/testgorilla-tgo-ui-components-divider.mjs.map +1 -1
  41. package/fesm2022/testgorilla-tgo-ui-components-donut-chart.mjs +239 -142
  42. package/fesm2022/testgorilla-tgo-ui-components-donut-chart.mjs.map +1 -1
  43. package/fesm2022/testgorilla-tgo-ui-components-dropdown.mjs +599 -467
  44. package/fesm2022/testgorilla-tgo-ui-components-dropdown.mjs.map +1 -1
  45. package/fesm2022/testgorilla-tgo-ui-components-elevation-shadow.mjs +126 -70
  46. package/fesm2022/testgorilla-tgo-ui-components-elevation-shadow.mjs.map +1 -1
  47. package/fesm2022/testgorilla-tgo-ui-components-empty-state.mjs +324 -329
  48. package/fesm2022/testgorilla-tgo-ui-components-empty-state.mjs.map +1 -1
  49. package/fesm2022/testgorilla-tgo-ui-components-field.mjs +969 -648
  50. package/fesm2022/testgorilla-tgo-ui-components-field.mjs.map +1 -1
  51. package/fesm2022/testgorilla-tgo-ui-components-file-upload.mjs +553 -419
  52. package/fesm2022/testgorilla-tgo-ui-components-file-upload.mjs.map +1 -1
  53. package/fesm2022/testgorilla-tgo-ui-components-filter-button.mjs +847 -452
  54. package/fesm2022/testgorilla-tgo-ui-components-filter-button.mjs.map +1 -1
  55. package/fesm2022/testgorilla-tgo-ui-components-gaussian-chart.mjs +398 -302
  56. package/fesm2022/testgorilla-tgo-ui-components-gaussian-chart.mjs.map +1 -1
  57. package/fesm2022/testgorilla-tgo-ui-components-icon-label.mjs +162 -95
  58. package/fesm2022/testgorilla-tgo-ui-components-icon-label.mjs.map +1 -1
  59. package/fesm2022/testgorilla-tgo-ui-components-icon.mjs +1825 -1795
  60. package/fesm2022/testgorilla-tgo-ui-components-icon.mjs.map +1 -1
  61. package/fesm2022/testgorilla-tgo-ui-components-infinite-scroll-table.mjs +1018 -672
  62. package/fesm2022/testgorilla-tgo-ui-components-infinite-scroll-table.mjs.map +1 -1
  63. package/fesm2022/testgorilla-tgo-ui-components-inline-field.mjs +758 -368
  64. package/fesm2022/testgorilla-tgo-ui-components-inline-field.mjs.map +1 -1
  65. package/fesm2022/testgorilla-tgo-ui-components-logo.mjs +204 -212
  66. package/fesm2022/testgorilla-tgo-ui-components-logo.mjs.map +1 -1
  67. package/fesm2022/testgorilla-tgo-ui-components-media-card.mjs +183 -48
  68. package/fesm2022/testgorilla-tgo-ui-components-media-card.mjs.map +1 -1
  69. package/fesm2022/testgorilla-tgo-ui-components-media-dialog.mjs +243 -79
  70. package/fesm2022/testgorilla-tgo-ui-components-media-dialog.mjs.map +1 -1
  71. package/fesm2022/testgorilla-tgo-ui-components-multi-input.mjs +751 -361
  72. package/fesm2022/testgorilla-tgo-ui-components-multi-input.mjs.map +1 -1
  73. package/fesm2022/testgorilla-tgo-ui-components-navbar.mjs +1122 -385
  74. package/fesm2022/testgorilla-tgo-ui-components-navbar.mjs.map +1 -1
  75. package/fesm2022/testgorilla-tgo-ui-components-overflow-menu.mjs +689 -413
  76. package/fesm2022/testgorilla-tgo-ui-components-overflow-menu.mjs.map +1 -1
  77. package/fesm2022/testgorilla-tgo-ui-components-page-header.mjs +227 -92
  78. package/fesm2022/testgorilla-tgo-ui-components-page-header.mjs.map +1 -1
  79. package/fesm2022/testgorilla-tgo-ui-components-paginator.mjs +174 -113
  80. package/fesm2022/testgorilla-tgo-ui-components-paginator.mjs.map +1 -1
  81. package/fesm2022/testgorilla-tgo-ui-components-password-criteria.mjs +367 -165
  82. package/fesm2022/testgorilla-tgo-ui-components-password-criteria.mjs.map +1 -1
  83. package/fesm2022/testgorilla-tgo-ui-components-password-strength.mjs +253 -118
  84. package/fesm2022/testgorilla-tgo-ui-components-password-strength.mjs.map +1 -1
  85. package/fesm2022/testgorilla-tgo-ui-components-phone-input.mjs +730 -444
  86. package/fesm2022/testgorilla-tgo-ui-components-phone-input.mjs.map +1 -1
  87. package/fesm2022/testgorilla-tgo-ui-components-popover.mjs +533 -221
  88. package/fesm2022/testgorilla-tgo-ui-components-popover.mjs.map +1 -1
  89. package/fesm2022/testgorilla-tgo-ui-components-popup-tip.mjs +274 -76
  90. package/fesm2022/testgorilla-tgo-ui-components-popup-tip.mjs.map +1 -1
  91. package/fesm2022/testgorilla-tgo-ui-components-progress-bar.mjs +184 -124
  92. package/fesm2022/testgorilla-tgo-ui-components-progress-bar.mjs.map +1 -1
  93. package/fesm2022/testgorilla-tgo-ui-components-prompt.mjs +1223 -574
  94. package/fesm2022/testgorilla-tgo-ui-components-prompt.mjs.map +1 -1
  95. package/fesm2022/testgorilla-tgo-ui-components-radial-progress.mjs +249 -160
  96. package/fesm2022/testgorilla-tgo-ui-components-radial-progress.mjs.map +1 -1
  97. package/fesm2022/testgorilla-tgo-ui-components-radio-button.mjs +447 -439
  98. package/fesm2022/testgorilla-tgo-ui-components-radio-button.mjs.map +1 -1
  99. package/fesm2022/testgorilla-tgo-ui-components-rating.mjs +226 -150
  100. package/fesm2022/testgorilla-tgo-ui-components-rating.mjs.map +1 -1
  101. package/fesm2022/testgorilla-tgo-ui-components-scale-table.mjs +255 -67
  102. package/fesm2022/testgorilla-tgo-ui-components-scale-table.mjs.map +1 -1
  103. package/fesm2022/testgorilla-tgo-ui-components-scale.mjs +205 -162
  104. package/fesm2022/testgorilla-tgo-ui-components-scale.mjs.map +1 -1
  105. package/fesm2022/testgorilla-tgo-ui-components-segmented-bar.mjs +245 -153
  106. package/fesm2022/testgorilla-tgo-ui-components-segmented-bar.mjs.map +1 -1
  107. package/fesm2022/testgorilla-tgo-ui-components-segmented-button.mjs +274 -140
  108. package/fesm2022/testgorilla-tgo-ui-components-segmented-button.mjs.map +1 -1
  109. package/fesm2022/testgorilla-tgo-ui-components-segmented-toggle.mjs +319 -147
  110. package/fesm2022/testgorilla-tgo-ui-components-segmented-toggle.mjs.map +1 -1
  111. package/fesm2022/testgorilla-tgo-ui-components-selectable-card.mjs +286 -84
  112. package/fesm2022/testgorilla-tgo-ui-components-selectable-card.mjs.map +1 -1
  113. package/fesm2022/testgorilla-tgo-ui-components-side-navigation.mjs +660 -208
  114. package/fesm2022/testgorilla-tgo-ui-components-side-navigation.mjs.map +1 -1
  115. package/fesm2022/testgorilla-tgo-ui-components-side-panel.mjs +579 -320
  116. package/fesm2022/testgorilla-tgo-ui-components-side-panel.mjs.map +1 -1
  117. package/fesm2022/testgorilla-tgo-ui-components-side-sheet.mjs +419 -200
  118. package/fesm2022/testgorilla-tgo-ui-components-side-sheet.mjs.map +1 -1
  119. package/fesm2022/testgorilla-tgo-ui-components-skeleton.mjs +132 -80
  120. package/fesm2022/testgorilla-tgo-ui-components-skeleton.mjs.map +1 -1
  121. package/fesm2022/testgorilla-tgo-ui-components-slider.mjs +741 -390
  122. package/fesm2022/testgorilla-tgo-ui-components-slider.mjs.map +1 -1
  123. package/fesm2022/testgorilla-tgo-ui-components-snackbar.mjs +455 -329
  124. package/fesm2022/testgorilla-tgo-ui-components-snackbar.mjs.map +1 -1
  125. package/fesm2022/testgorilla-tgo-ui-components-spider-chart.mjs +543 -514
  126. package/fesm2022/testgorilla-tgo-ui-components-spider-chart.mjs.map +1 -1
  127. package/fesm2022/testgorilla-tgo-ui-components-spinner.mjs +193 -104
  128. package/fesm2022/testgorilla-tgo-ui-components-spinner.mjs.map +1 -1
  129. package/fesm2022/testgorilla-tgo-ui-components-stepper.mjs +760 -524
  130. package/fesm2022/testgorilla-tgo-ui-components-stepper.mjs.map +1 -1
  131. package/fesm2022/testgorilla-tgo-ui-components-table.mjs +714 -415
  132. package/fesm2022/testgorilla-tgo-ui-components-table.mjs.map +1 -1
  133. package/fesm2022/testgorilla-tgo-ui-components-tabs.mjs +847 -438
  134. package/fesm2022/testgorilla-tgo-ui-components-tabs.mjs.map +1 -1
  135. package/fesm2022/testgorilla-tgo-ui-components-tag.mjs +535 -275
  136. package/fesm2022/testgorilla-tgo-ui-components-tag.mjs.map +1 -1
  137. package/fesm2022/testgorilla-tgo-ui-components-toggle.mjs +316 -246
  138. package/fesm2022/testgorilla-tgo-ui-components-toggle.mjs.map +1 -1
  139. package/fesm2022/testgorilla-tgo-ui-components-tooltip.mjs +404 -284
  140. package/fesm2022/testgorilla-tgo-ui-components-tooltip.mjs.map +1 -1
  141. package/fesm2022/testgorilla-tgo-ui-components-universal-skills.mjs +664 -383
  142. package/fesm2022/testgorilla-tgo-ui-components-universal-skills.mjs.map +1 -1
  143. package/fesm2022/testgorilla-tgo-ui-components-validation-error.mjs +201 -112
  144. package/fesm2022/testgorilla-tgo-ui-components-validation-error.mjs.map +1 -1
  145. package/fesm2022/testgorilla-tgo-ui-components-write-with-ai.mjs +1014 -458
  146. package/fesm2022/testgorilla-tgo-ui-components-write-with-ai.mjs.map +1 -1
  147. package/fesm2022/testgorilla-tgo-ui.mjs +147 -155
  148. package/fesm2022/testgorilla-tgo-ui.mjs.map +1 -1
  149. package/mcp/catalog.json +1 -1
  150. package/package.json +16 -17
  151. package/projects/tgo-canopy-ui/theme/_palette.scss +23 -18
  152. package/types/testgorilla-tgo-ui-components-accordion.d.ts +214 -158
  153. package/types/testgorilla-tgo-ui-components-ai-audio-circle.d.ts +93 -69
  154. package/types/testgorilla-tgo-ui-components-ai-caveat.d.ts +37 -34
  155. package/types/testgorilla-tgo-ui-components-ai-feedback.d.ts +126 -86
  156. package/types/testgorilla-tgo-ui-components-alert-banner.d.ts +260 -185
  157. package/types/testgorilla-tgo-ui-components-audio-waveform.d.ts +96 -67
  158. package/types/testgorilla-tgo-ui-components-autocomplete-v2.d.ts +455 -256
  159. package/types/testgorilla-tgo-ui-components-autocomplete.d.ts +545 -390
  160. package/types/testgorilla-tgo-ui-components-avatar.d.ts +128 -102
  161. package/types/testgorilla-tgo-ui-components-badge.d.ts +191 -139
  162. package/types/testgorilla-tgo-ui-components-breadcrumb.d.ts +100 -62
  163. package/types/testgorilla-tgo-ui-components-button.d.ts +479 -340
  164. package/types/testgorilla-tgo-ui-components-card.d.ts +153 -114
  165. package/types/testgorilla-tgo-ui-components-checkbox.d.ts +299 -223
  166. package/types/testgorilla-tgo-ui-components-checklist.d.ts +149 -97
  167. package/types/testgorilla-tgo-ui-components-core.d.ts +307 -295
  168. package/types/testgorilla-tgo-ui-components-datepicker.d.ts +404 -299
  169. package/types/testgorilla-tgo-ui-components-device-control.d.ts +151 -81
  170. package/types/testgorilla-tgo-ui-components-dialog.d.ts +442 -329
  171. package/types/testgorilla-tgo-ui-components-divider.d.ts +64 -51
  172. package/types/testgorilla-tgo-ui-components-donut-chart.d.ts +41 -37
  173. package/types/testgorilla-tgo-ui-components-dropdown.d.ts +335 -241
  174. package/types/testgorilla-tgo-ui-components-elevation-shadow.d.ts +48 -43
  175. package/types/testgorilla-tgo-ui-components-empty-state.d.ts +317 -215
  176. package/types/testgorilla-tgo-ui-components-field.d.ts +559 -388
  177. package/types/testgorilla-tgo-ui-components-file-upload.d.ts +230 -168
  178. package/types/testgorilla-tgo-ui-components-filter-button.d.ts +263 -206
  179. package/types/testgorilla-tgo-ui-components-gaussian-chart.d.ts +107 -94
  180. package/types/testgorilla-tgo-ui-components-icon-label.d.ts +84 -61
  181. package/types/testgorilla-tgo-ui-components-icon.d.ts +137 -110
  182. package/types/testgorilla-tgo-ui-components-infinite-scroll-table.d.ts +429 -303
  183. package/types/testgorilla-tgo-ui-components-inline-field.d.ts +338 -254
  184. package/types/testgorilla-tgo-ui-components-logo.d.ts +119 -101
  185. package/types/testgorilla-tgo-ui-components-media-card.d.ts +51 -35
  186. package/types/testgorilla-tgo-ui-components-media-dialog.d.ts +40 -45
  187. package/types/testgorilla-tgo-ui-components-multi-input.d.ts +283 -194
  188. package/types/testgorilla-tgo-ui-components-navbar.d.ts +326 -208
  189. package/types/testgorilla-tgo-ui-components-overflow-menu.d.ts +276 -204
  190. package/types/testgorilla-tgo-ui-components-page-header.d.ts +67 -50
  191. package/types/testgorilla-tgo-ui-components-paginator.d.ts +103 -70
  192. package/types/testgorilla-tgo-ui-components-password-criteria.d.ts +67 -58
  193. package/types/testgorilla-tgo-ui-components-password-strength.d.ts +66 -57
  194. package/types/testgorilla-tgo-ui-components-phone-input.d.ts +217 -175
  195. package/types/testgorilla-tgo-ui-components-popover.d.ts +94 -53
  196. package/types/testgorilla-tgo-ui-components-popup-tip.d.ts +81 -44
  197. package/types/testgorilla-tgo-ui-components-progress-bar.d.ts +115 -84
  198. package/types/testgorilla-tgo-ui-components-prompt.d.ts +315 -219
  199. package/types/testgorilla-tgo-ui-components-radial-progress.d.ts +146 -107
  200. package/types/testgorilla-tgo-ui-components-radio-button.d.ts +296 -219
  201. package/types/testgorilla-tgo-ui-components-rating.d.ts +134 -95
  202. package/types/testgorilla-tgo-ui-components-scale-table.d.ts +67 -47
  203. package/types/testgorilla-tgo-ui-components-scale.d.ts +91 -66
  204. package/types/testgorilla-tgo-ui-components-segmented-bar.d.ts +118 -89
  205. package/types/testgorilla-tgo-ui-components-segmented-button.d.ts +107 -80
  206. package/types/testgorilla-tgo-ui-components-segmented-toggle.d.ts +138 -105
  207. package/types/testgorilla-tgo-ui-components-selectable-card.d.ts +90 -56
  208. package/types/testgorilla-tgo-ui-components-side-navigation.d.ts +183 -107
  209. package/types/testgorilla-tgo-ui-components-side-panel.d.ts +156 -145
  210. package/types/testgorilla-tgo-ui-components-side-sheet.d.ts +98 -89
  211. package/types/testgorilla-tgo-ui-components-skeleton.d.ts +50 -33
  212. package/types/testgorilla-tgo-ui-components-slider.d.ts +278 -198
  213. package/types/testgorilla-tgo-ui-components-snackbar.d.ts +211 -159
  214. package/types/testgorilla-tgo-ui-components-spider-chart.d.ts +140 -121
  215. package/types/testgorilla-tgo-ui-components-spinner.d.ts +93 -72
  216. package/types/testgorilla-tgo-ui-components-stepper.d.ts +480 -338
  217. package/types/testgorilla-tgo-ui-components-table.d.ts +280 -233
  218. package/types/testgorilla-tgo-ui-components-tabs.d.ts +282 -183
  219. package/types/testgorilla-tgo-ui-components-tag.d.ts +266 -193
  220. package/types/testgorilla-tgo-ui-components-toggle.d.ts +180 -132
  221. package/types/testgorilla-tgo-ui-components-tooltip.d.ts +142 -105
  222. package/types/testgorilla-tgo-ui-components-universal-skills.d.ts +165 -144
  223. package/types/testgorilla-tgo-ui-components-validation-error.d.ts +70 -51
  224. package/types/testgorilla-tgo-ui-components-write-with-ai.d.ts +210 -133
  225. package/types/testgorilla-tgo-ui.d.ts +52 -45
@@ -1,676 +1,1022 @@
1
- import { CdkVirtualScrollViewport, CdkFixedSizeVirtualScroll, CdkVirtualForOf, ScrollingModule } from '@angular/cdk/scrolling';
2
- import { NgTemplateOutlet, AsyncPipe, CommonModule } from '@angular/common';
3
- import * as i0 from '@angular/core';
4
- import { input, booleanAttribute, numberAttribute, output, viewChild, signal, computed, effect, untracked, isDevMode, ChangeDetectionStrategy, Component, NgModule } from '@angular/core';
5
- import { Subscription, animationFrameScheduler } from 'rxjs';
6
- import { auditTime } from 'rxjs/operators';
7
- import { CheckboxComponent } from '@testgorilla/tgo-ui/components/checkbox';
8
- import { UiTranslatePipe } from '@testgorilla/tgo-ui/components/core';
9
- import { SkeletonComponent } from '@testgorilla/tgo-ui/components/skeleton';
10
-
1
+ import { CdkFixedSizeVirtualScroll, CdkVirtualForOf, CdkVirtualScrollViewport, ScrollingModule } from "@angular/cdk/scrolling";
2
+ import { AsyncPipe, CommonModule, NgTemplateOutlet } from "@angular/common";
3
+ import * as i0 from "@angular/core";
4
+ import { ChangeDetectionStrategy, Component, NgModule, booleanAttribute, computed, effect, input, isDevMode, numberAttribute, output, signal, untracked, viewChild } from "@angular/core";
5
+ import { Subscription, animationFrameScheduler } from "rxjs";
6
+ import { auditTime } from "rxjs/operators";
7
+ import { CheckboxComponent } from "@testgorilla/tgo-ui/components/checkbox";
8
+ import { UiTranslatePipe } from "@testgorilla/tgo-ui/components/core";
9
+ import { SkeletonComponent } from "@testgorilla/tgo-ui/components/skeleton";
11
10
  const DEFAULT_FIRST_LOAD_SKELETON_COUNT = 10;
12
11
  const DEFAULT_LOAD_MORE_SKELETON_COUNT = 3;
13
12
  const DEFAULT_LOAD_MORE_THRESHOLD = 5;
14
- /**
15
- * Fallback width for a column that declares none, shared with placeholder columns so both resolve to one
16
- * identical width — header/body alignment depends on that.
17
- */
18
- const DEFAULT_COLUMN_WIDTH = '160px';
19
- /** Elements owning their own click semantics: a click inside one must not also activate the row. */
20
- const INTERACTIVE_TARGET_SELECTOR = 'a, button, input, select, textarea, [role="button"], [tabindex]';
21
- /**
22
- * A generic, virtualized table with scroll-driven infinite loading. Independent of `ui-table`: it reuses
23
- * only stable leaf primitives (`ui-skeleton`) and duplicates the column/context type shapes so consumers
24
- * can migrate with a selector swap.
25
- */
26
- class InfiniteScrollTableComponent {
27
- constructor() {
28
- /**
29
- * Rows loaded so far. **Must change by reference** (`[...rows, ...page]`): a signal input cannot observe
30
- * `rows.push(...)`, so an in-place append renders nothing and leaves `loadMore` disarmed.
31
- */
32
- this.data = input.required(...(ngDevMode ? [{ debugName: "data" }] : /* istanbul ignore next */ []));
33
- this.columns = input.required(...(ngDevMode ? [{ debugName: "columns" }] : /* istanbul ignore next */ []));
34
- /** Fixed row height in px (the virtualization `itemSize`). Variable row heights are unsupported. */
35
- this.rowHeight = input.required(...(ngDevMode ? [{ debugName: "rowHeight" }] : /* istanbul ignore next */ []));
36
- /** Stable row identity so recycled rows re-render correctly. Takes precedence over `rowIdKey`. */
37
- this.trackBy = input(...(ngDevMode ? [undefined, { debugName: "trackBy" }] : /* istanbul ignore next */ []));
38
- /** Key on each row holding a stable id. Used when `trackBy` is not provided. */
39
- this.rowIdKey = input(...(ngDevMode ? [undefined, { debugName: "rowIdKey" }] : /* istanbul ignore next */ []));
40
- /**
41
- * CDK's rendered buffers. Both default to a multiple of `rowHeight` (~5 and ~10 rows) rather than a
42
- * fixed px value, which would mean a different row count at every `rowHeight`.
43
- */
44
- this.minBufferPx = input(undefined, ...(ngDevMode ? [{ debugName: "minBufferPx" }] : /* istanbul ignore next */ []));
45
- this.maxBufferPx = input(undefined, ...(ngDevMode ? [{ debugName: "maxBufferPx" }] : /* istanbul ignore next */ []));
46
- /** Max height of the internal scroll region (e.g. `'70vh'`). The body shrinks to fit fewer rows. */
47
- this.maxHeight = input('70vh', ...(ngDevMode ? [{ debugName: "maxHeight" }] : /* istanbul ignore next */ []));
48
- /** Stretch to the parent's height instead of the content's; `maxHeight` becomes a cap, not the target. */
49
- this.fillHeight = input(false, { ...(ngDevMode ? { debugName: "fillHeight" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
50
- this.isCondensed = input(false, { ...(ngDevMode ? { debugName: "isCondensed" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
51
- /**
52
- * Prepends a left-pinned checkbox column driven by each row's `selected` property. Consumer-managed
53
- * (like `ui-table`): toggling only emits `selectionChange`.
54
- */
55
- this.selectable = input(false, { ...(ngDevMode ? { debugName: "selectable" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
56
- /**
57
- * Makes rows focusable and activatable by click or Enter/Space. Off by default: a read-only table
58
- * must not create a tab stop per rendered row or imply interactivity it does not have.
59
- */
60
- this.rowsClickable = input(false, { ...(ngDevMode ? { debugName: "rowsClickable" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
61
- /** First-load state: renders a full body of skeleton rows. */
62
- this.loading = input(false, { ...(ngDevMode ? { debugName: "loading" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
63
- /** Appends skeleton rows below the existing rows while the next page is fetched. */
64
- this.loadingMore = input(false, { ...(ngDevMode ? { debugName: "loadingMore" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
65
- /** Required, not defaulted: a silent "never load" default would disable the headline behaviour. */
66
- this.hasMore = input.required({ ...(ngDevMode ? { debugName: "hasMore" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
67
- this.skeletonRowCount = input(DEFAULT_FIRST_LOAD_SKELETON_COUNT, ...(ngDevMode ? [{ debugName: "skeletonRowCount" }] : /* istanbul ignore next */ []));
68
- /** Number of skeleton rows appended below the loaded rows while `loadingMore` is true. */
69
- this.loadMoreSkeletonCount = input(DEFAULT_LOAD_MORE_SKELETON_COUNT, ...(ngDevMode ? [{ debugName: "loadMoreSkeletonCount" }] : /* istanbul ignore next */ []));
70
- /**
71
- * Skeleton placeholder columns for a lazily-loaded column set. They deliberately sit OUTSIDE `columns`,
72
- * so they cannot change which column is last and unpin a sticky last column.
73
- */
74
- this.loadingColumnCount = input(0, { ...(ngDevMode ? { debugName: "loadingColumnCount" } : /* istanbul ignore next */ {}), transform: numberAttribute });
75
- this.loadMoreThreshold = input(DEFAULT_LOAD_MORE_THRESHOLD, ...(ngDevMode ? [{ debugName: "loadMoreThreshold" }] : /* istanbul ignore next */ []));
76
- /** Shown when `data` is empty and not loading. */
77
- this.noDataTemplate = input(...(ngDevMode ? [undefined, { debugName: "noDataTemplate" }] : /* istanbul ignore next */ []));
78
- /** Shown when `error` is `true`. Receives `{ $implicit: retry, retry }` as context. */
79
- this.errorTemplate = input(...(ngDevMode ? [undefined, { debugName: "errorTemplate" }] : /* istanbul ignore next */ []));
80
- this.error = input(false, { ...(ngDevMode ? { debugName: "error" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
81
- /**
82
- * Shown once `hasMore` goes `false` with rows loaded. Deliberately has NO built-in fallback (unlike
83
- * `noDataTemplate` / `errorTemplate`): a single-page list would otherwise flash "no more results".
84
- */
85
- this.endOfListTemplate = input(...(ngDevMode ? [undefined, { debugName: "endOfListTemplate" }] : /* istanbul ignore next */ []));
86
- this.testId = input(null, ...(ngDevMode ? [{ debugName: "testId" }] : /* istanbul ignore next */ []));
87
- this.ariaLabel = input('', ...(ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []));
88
- /** Guarded: only when `hasMore && !loading && !loadingMore`, and only once per approach to the end. */
89
- this.loadMore = output();
90
- this.retry = output();
91
- this.rowClick = output();
92
- /** The consumer is expected to apply `selected` back onto its own data. */
93
- this.selectionChange = output();
94
- this.viewport = viewChild(CdkVirtualScrollViewport, ...(ngDevMode ? [{ debugName: "viewport" }] : /* istanbul ignore next */ []));
95
- this.headerScroll = viewChild('headerScroll', ...(ngDevMode ? [{ debugName: "headerScroll" }] : /* istanbul ignore next */ []));
96
- this.scrollStart = signal(true, ...(ngDevMode ? [{ debugName: "scrollStart" }] : /* istanbul ignore next */ []));
97
- this.scrollEnd = signal(false, ...(ngDevMode ? [{ debugName: "scrollEnd" }] : /* istanbul ignore next */ []));
98
- this.horizontalScroll = signal(false, ...(ngDevMode ? [{ debugName: "horizontalScroll" }] : /* istanbul ignore next */ []));
99
- /** Reserved as right padding on the header, so its content width exactly equals the body's. */
100
- this.scrollbarWidth = signal(0, ...(ngDevMode ? [{ debugName: "scrollbarWidth" }] : /* istanbul ignore next */ []));
101
- /** Added to the viewport height so on a short list the scrollbar doesn't eat into the rows. */
102
- this.hScrollbarHeight = signal(0, ...(ngDevMode ? [{ debugName: "hScrollbarHeight" }] : /* istanbul ignore next */ []));
103
- /**
104
- * Paging latch. Three fields, one rule: `loadMore` emits at most once per page that lands while the
105
- * user is inside the trigger zone. `isLoadMoreArmed` is the latch itself, written here and by
106
- * `checkLoadMore`; `dataLengthAtEmit` records how long `data` was when the last emission went out, so
107
- * "the requested page arrived" is a length comparison rather than a guess about scroll positions;
108
- * `firstVisibleIndex` is where the user actually is.
109
- *
110
- * The invariant that matters: arming and firing must read the SAME trigger zone. They used to derive it
111
- * from two different thresholds, which opened bands the latch could never leave.
112
- */
113
- this.isLoadMoreArmed = true;
114
- this.dataLengthAtEmit = 0;
115
- /** In-place-mutation detector; see the effect that reads these for the discriminator. */
116
- this.wasLoadingMore = false;
117
- this.lastDataLength = 0;
118
- /** Latches once any non-empty `data` is seen, so only the very first render is exempt from resetting. */
119
- this.hasSeenHead = false;
120
- /** Previous `loading` value, for spotting the false -> true edge that starts a reset. */
121
- this.wasLoading = false;
122
- /**
123
- * First visible row index, kept current from `viewport.scrolledIndexChange` (no layout read) rather
124
- * than `viewport.getRenderedRange().start`, which includes CDK's read-ahead buffer.
125
- */
126
- this.firstVisibleIndex = 0;
127
- this.skeletonTheme = {
128
- background: 'var(--ui-ist-skeleton-bg)',
129
- 'border-radius': '4px',
130
- height: '24px',
131
- 'margin-bottom': '0',
132
- };
133
- // Pinning is positional by contract: only the FIRST column pins left, only the LAST pins right.
134
- // `isSticky` elsewhere is ignored (with a dev warning), not applied as `left: 0` — that would overlay
135
- // the columns before it.
136
- this.stickyStartKey = computed(() => {
137
- const columns = this.columns();
138
- return columns[0]?.isSticky ? columns[0].key : undefined;
139
- }, ...(ngDevMode ? [{ debugName: "stickyStartKey" }] : /* istanbul ignore next */ []));
140
- this.stickyEndKey = computed(() => {
141
- const columns = this.columns();
142
- const lastIndex = columns.length - 1;
143
- // `lastIndex > 0` so a single sticky column pins to the start, not the end.
144
- return lastIndex > 0 && columns[lastIndex]?.isSticky ? columns[lastIndex].key : undefined;
145
- }, ...(ngDevMode ? [{ debugName: "stickyEndKey" }] : /* istanbul ignore next */ []));
146
- this.defaultColumnWidth = DEFAULT_COLUMN_WIDTH;
147
- this.effectiveMinBufferPx = computed(() => this.minBufferPx() ?? this.rowHeight() * 5, ...(ngDevMode ? [{ debugName: "effectiveMinBufferPx" }] : /* istanbul ignore next */ []));
148
- /**
149
- * The `Math.max` is load-bearing: CDK throws in dev mode when `maxBufferPx < minBufferPx`, which a
150
- * consumer triggers just by raising `minBufferPx` above the derived default.
151
- */
152
- this.effectiveMaxBufferPx = computed(() => Math.max(this.maxBufferPx() ?? this.rowHeight() * 10, this.effectiveMinBufferPx()), ...(ngDevMode ? [{ debugName: "effectiveMaxBufferPx" }] : /* istanbul ignore next */ []));
153
- /** Stable keys for the placeholder columns, so `@for` can track them across renders. */
154
- this.loadingColumns = computed(() => Array.from({ length: Math.max(0, this.loadingColumnCount()) }, (_, index) => `loading-column-${index}`), ...(ngDevMode ? [{ debugName: "loadingColumns" }] : /* istanbul ignore next */ []));
155
- this.renderRows = computed(() => {
156
- if (this.loading()) {
157
- return Array.from({ length: Math.max(1, this.skeletonRowCount()) }, (_, i) => ({
158
- kind: 'skeleton',
159
- id: `skeleton-first-${i}`,
160
- }));
161
- }
162
- const rows = this.data().map((item, index) => ({ kind: 'data', item, index }));
163
- if (this.loadingMore() && this.hasMore()) {
164
- for (let i = 0; i < Math.max(1, this.loadMoreSkeletonCount()); i++) {
165
- rows.push({ kind: 'skeleton', id: `skeleton-more-${i}` });
166
- }
167
- }
168
- return rows;
169
- }, ...(ngDevMode ? [{ debugName: "renderRows" }] : /* istanbul ignore next */ []));
170
- this.hasData = computed(() => this.data().length > 0, ...(ngDevMode ? [{ debugName: "hasData" }] : /* istanbul ignore next */ []));
171
- this.showViewport = computed(() => this.loading() || this.hasData(), ...(ngDevMode ? [{ debugName: "showViewport" }] : /* istanbul ignore next */ []));
172
- /**
173
- * `loadingMore` counts as loading here too: a consumer that retries a failed first page through the same
174
- * flag it uses for every page would otherwise render "no rows" with `aria-busy` set and the live region
175
- * announcing a fetch.
176
- */
177
- this.showEmptyState = computed(() => !this.loading() && !this.loadingMore() && !this.error() && !this.hasData(), ...(ngDevMode ? [{ debugName: "showEmptyState" }] : /* istanbul ignore next */ []));
178
- this.showErrorState = computed(() => !this.loading() && this.error() && !this.hasData(), ...(ngDevMode ? [{ debugName: "showErrorState" }] : /* istanbul ignore next */ []));
179
- this.showErrorFooter = computed(() => !this.loading() && this.error() && this.hasData(), ...(ngDevMode ? [{ debugName: "showErrorFooter" }] : /* istanbul ignore next */ []));
180
- /**
181
- * The negative clauses keep this out of slots other states own, and `!loadingMore()` closes a one-tick
182
- * flash: a fetch completing and the consumer flipping `hasMore` need not land in the same cycle.
183
- */
184
- this.showEndOfList = computed(() => this.hasData() && !this.hasMore() && !this.loading() && !this.loadingMore() && !this.error(), ...(ngDevMode ? [{ debugName: "showEndOfList" }] : /* istanbul ignore next */ []));
185
- /**
186
- * CSS `min()` because the cap mixes units. The scrollbar reserve stops a short list from growing a
187
- * spurious vertical scrollbar; fill mode returns `null` so flex owns the sizing and the reserve is moot.
188
- */
189
- this.viewportHeight = computed(() => {
190
- if (this.fillHeight()) {
191
- return null;
192
- }
193
- const contentHeight = this.renderRows().length * this.rowHeight();
194
- const scrollbarReserve = this.horizontalScroll() ? this.hScrollbarHeight() : 0;
195
- return `min(${contentHeight + scrollbarReserve}px, ${this.maxHeight()})`;
196
- }, ...(ngDevMode ? [{ debugName: "viewportHeight" }] : /* istanbul ignore next */ []));
197
- this.translationContext = 'INFINITE_SCROLL_TABLE.';
198
- /** A translation key, resolved in the template: screen-reader users are not all English speakers. */
199
- this.statusMessageKey = computed(() => {
200
- if (this.loading()) {
201
- return `${this.translationContext}LOADING`;
202
- }
203
- if (this.loadingMore()) {
204
- return `${this.translationContext}LOADING_MORE`;
205
- }
206
- return '';
207
- }, ...(ngDevMode ? [{ debugName: "statusMessageKey" }] : /* istanbul ignore next */ []));
208
- this.errorContext = {
209
- $implicit: () => this.emitRetry(),
210
- retry: () => this.emitRetry(),
211
- };
212
- this.renderRowTrackBy = (index, row) => {
213
- if (row.kind === 'skeleton') {
214
- return row.id;
215
- }
216
- return this.rowIdentity(row.item, row.index);
217
- };
218
- // (Re-)attaches scroll listeners as the viewport enters or leaves the DOM. The setup reads other
219
- // signals, so it is `untracked()` — otherwise every data change would tear the listeners down.
220
- effect(onCleanup => {
221
- const viewport = this.viewport();
222
- if (!viewport) {
223
- return;
224
- }
225
- untracked(() => {
226
- // A freshly created CdkVirtualScrollViewport always mounts scrolled to the top, and this field
227
- // carries across viewport instances (`@if (showViewport())` destroys and recreates one when `data`
228
- // empties and repopulates). Leaving it stale would let `checkLoadMore` fire off a scroll position
229
- // belonging to the OLD viewport.
230
- this.firstVisibleIndex = 0;
231
- const element = viewport.elementRef.nativeElement;
232
- // Both patch CDK divs that would otherwise break the ARIA table structure: its content wrapper
233
- // sits between `role="rowgroup"` and the rows, its spacer is an unlabeled child of the rowgroup.
234
- // Both selectors are CDK internals, so the optional chaining would swallow a CDK restructure
235
- // silently. The spec asserts both attributes after mount, which is what turns such a change into a
236
- // failing test rather than a quietly invalid accessibility tree.
237
- element.querySelector('.cdk-virtual-scroll-content-wrapper')?.setAttribute('role', 'presentation');
238
- element.querySelector('.cdk-virtual-scroll-spacer')?.setAttribute('aria-hidden', 'true');
239
- const subscription = new Subscription();
240
- // Audited to one animation frame, matching CDK's own scroll handler, so `measureScrollOffset`'s
241
- // forced reflow can't run several times per frame and interleave with CDK's DOM writes.
242
- subscription.add(viewport
243
- .elementScrolled()
244
- .pipe(auditTime(0, animationFrameScheduler))
245
- .subscribe(() => this.syncHorizontalScroll()));
246
- // Neither trigger is redundant: an append changes the rendered range without a scroll, and a scroll
247
- // inside the read-ahead buffer moves `firstVisibleIndex` without changing the range.
248
- subscription.add(viewport.renderedRangeStream.subscribe(() => this.checkLoadMore()));
249
- subscription.add(viewport.scrolledIndexChange.subscribe(index => {
250
- this.firstVisibleIndex = index;
251
- this.checkLoadMore();
252
- }));
253
- // `offsetWidth - clientWidth` also counts borders: pure scrollbar only because `.ui-ist__body`
254
- // has none, and it must stay borderless.
255
- const measureScrollbar = () => {
256
- this.scrollbarWidth.set(element.offsetWidth - element.clientWidth);
257
- this.hScrollbarHeight.set(element.offsetHeight - element.clientHeight);
258
- };
259
- subscription.add(viewport.renderedRangeStream.subscribe(() => measureScrollbar()));
260
- // Covers box changes no signal captures: a flex parent resizing, or a relative `maxHeight`
261
- // reacting to its container. Signal-driven height changes are the effect below.
262
- let resizeObserver;
263
- if (typeof ResizeObserver !== 'undefined') {
264
- resizeObserver = new ResizeObserver(() => {
265
- measureScrollbar();
266
- // A resize can cross into or out of horizontal overflow without a scroll event, leaving the
267
- // sticky shadows and `viewportHeight()`'s scrollbar reserve stale.
268
- this.syncHorizontalScroll();
269
- this.scheduleViewportRemeasure();
270
- });
271
- resizeObserver.observe(element);
272
- }
273
- measureScrollbar();
274
- this.syncHorizontalScroll();
275
- this.checkLoadMore();
276
- // The sync above runs before CDK lays out its rows, so the overflow measurement is stale until
277
- // the next frame. Guarded because requestAnimationFrame is browser-only (SSR).
278
- let scrollSyncFrame;
279
- if (typeof requestAnimationFrame !== 'undefined') {
280
- scrollSyncFrame = requestAnimationFrame(() => this.syncHorizontalScroll());
281
- }
282
- onCleanup(() => {
283
- subscription.unsubscribe();
284
- resizeObserver?.disconnect();
285
- // Pending frames must not fire after the viewport leaves the DOM.
286
- if (scrollSyncFrame !== undefined) {
287
- cancelAnimationFrame(scrollSyncFrame);
288
- }
289
- if (this.remeasureFrame !== undefined) {
290
- cancelAnimationFrame(this.remeasureFrame);
291
- this.remeasureFrame = undefined;
292
- }
293
- });
294
- });
295
- });
296
- // CDK caches its measured size and re-measures only on scroll or window resize, so any signal-driven
297
- // height change here (`fillHeight` included: it swaps the `min()` cap for a flex-driven height) would
298
- // leave the new space empty with the tail rows unrendered. Read individually rather than via
299
- // `viewportHeight()`, to keep the dependency off horizontal-scroll state. `loadingColumnCount` changes
300
- // content WIDTH not the box, so the ResizeObserver misses it and only the deferred
301
- // `syncHorizontalScroll()` keeps the horizontal-overflow state current.
302
- effect(() => {
303
- this.renderRows();
304
- this.rowHeight();
305
- this.maxHeight();
306
- this.columns();
307
- this.fillHeight();
308
- this.loadingColumnCount();
309
- // Adds a 56px checkbox column: content width changes, the box does not.
310
- this.selectable();
311
- this.scheduleViewportRemeasure();
312
- });
313
- // A `data` change is the one signal that a requested page landed, so it is where the latch gets its
314
- // second chance. See `rearmLoadMoreIfUnreachable` for which cases that covers and why.
315
- effect(() => {
316
- this.data();
317
- untracked(() => this.rearmLoadMoreIfUnreachable());
318
- });
319
- // Dev-only: with selection on and no stable id, identity falls back to the data index, so selection
320
- // state can silently attach to the wrong row after a reorder/prepend.
321
- effect(() => {
322
- if (isDevMode() && this.selectable() && !this.trackBy() && !this.rowIdKey()) {
323
- console.warn('[ui-infinite-scroll-table] `selectable` is enabled without `trackBy` or `rowIdKey`. ' +
324
- 'Row identity falls back to the data index, so selection can attach to the wrong row ' +
325
- 'when rows are reordered or prepended. Provide `trackBy` or `rowIdKey` for stable identity.');
326
- }
327
- });
328
- // Dev-only: `isSticky` reads like a per-column capability, so name the columns being ignored.
329
- effect(() => {
330
- if (!isDevMode()) {
331
- return;
332
- }
333
- const columns = this.columns();
334
- const lastIndex = columns.length - 1;
335
- const ignored = columns
336
- .filter((column, index) => column.isSticky && index !== 0 && index !== lastIndex)
337
- .map(column => column.key);
338
- if (ignored.length > 0) {
339
- console.warn('[ui-infinite-scroll-table] `isSticky` is only honoured on the first and last column. ' +
340
- `Ignoring it on: ${ignored.join(', ')}.`);
341
- }
342
- });
343
- // Dev-only: the in-place-append tell is a fetch completing with the SAME array reference AND a GROWN
344
- // length. Length is the discriminator — a failed or empty final fetch keeps the reference but not the
345
- // growth, and those are legitimate outcomes that must stay silent.
346
- effect(() => {
347
- const loadingMore = this.loadingMore();
348
- const data = this.data();
349
- const completedFetch = this.wasLoadingMore && !loadingMore;
350
- const sameReference = this.lastDataReference === data;
351
- const grew = data.length > this.lastDataLength;
352
- this.wasLoadingMore = loadingMore;
353
- this.lastDataReference = data;
354
- this.lastDataLength = data.length;
355
- if (isDevMode() && completedFetch && sameReference && grew) {
356
- console.warn('[ui-infinite-scroll-table] `loadingMore` completed without `data` changing reference. ' +
357
- 'Append pages with a new array (`[...rows, ...page]`) — a signal input cannot observe an ' +
358
- 'in-place `push`, so the new rows will not render and `loadMore` will not fire again.');
359
- }
360
- });
361
- // Two ways a reset is recognised. Entering `loading` is the earlier and better one: the body becomes
362
- // skeletons, so the scroll belongs at the top immediately, and by the time the data lands there is
363
- // nothing left to jump. The head-identity check then covers a replacement swapped in WITHOUT a loading
364
- // pass — that one needs `trackBy` or `rowIdKey`, since the index fallback makes the head always `0`.
365
- // Caveat: a newest-first feed that PREPENDS also resets; those consumers should call `scrollToTop()`.
366
- effect(onCleanup => {
367
- onCleanup(() => this.cancelResetScrollFrame());
368
- const data = this.data();
369
- const loading = this.loading();
370
- const startedLoading = loading && !this.wasLoading;
371
- this.wasLoading = loading;
372
- const headIdentity = data.length > 0 ? untracked(() => this.rowIdentity(data[0], 0)) : undefined;
373
- const replaced = this.hasSeenHead && data.length > 0 && headIdentity !== this.previousHeadIdentity;
374
- this.previousHeadIdentity = headIdentity;
375
- // Latches once and never clears: a reset usually passes through empty + `loading`, which keeps the
376
- // viewport (and its scroll offset) alive, so clearing here would make the repopulation look like a
377
- // first render and skip the reset.
378
- this.hasSeenHead = this.hasSeenHead || data.length > 0;
379
- if (!startedLoading && !replaced) {
380
- // A shrink that isn't recognised as a replacement still strands the index past the new end, where
381
- // it reads as "at the bottom" and fires `loadMore` for a list the user hasn't seen.
382
- this.firstVisibleIndex = Math.min(this.firstVisibleIndex, Math.max(0, data.length - 1));
383
- return;
384
- }
385
- // Synchronously, ahead of the deferred scroll: CDK updates its rendered range for the new length
386
- // during this change detection, and that runs `checkLoadMore` while the index still points into the
387
- // old, longer list.
388
- this.firstVisibleIndex = 0;
389
- // Deferred a frame: CDK clamps a scroll request against the size it has already measured. Tracked so
390
- // it can be cancelled — a frame must not fire after the viewport leaves the DOM.
391
- if (typeof requestAnimationFrame === 'undefined') {
392
- untracked(() => this.scrollToTop());
393
- return;
394
- }
395
- this.cancelResetScrollFrame();
396
- this.resetScrollFrame = requestAnimationFrame(() => {
397
- this.resetScrollFrame = undefined;
398
- untracked(() => this.scrollToTop());
399
- });
400
- });
401
- }
402
- cancelResetScrollFrame() {
403
- if (this.resetScrollFrame !== undefined) {
404
- cancelAnimationFrame(this.resetScrollFrame);
405
- this.resetScrollFrame = undefined;
406
- }
407
- }
408
- /** No-ops only when no rows are rendered: the empty state, or an error with no rows. */
409
- scrollToIndex(index, behavior = 'auto') {
410
- this.viewport()?.scrollToIndex(index, behavior);
411
- }
412
- scrollToTop(behavior = 'auto') {
413
- this.viewport()?.scrollToIndex(0, behavior);
414
- }
415
- /**
416
- * The single place `T` is widened to its structural contract. Every field read on a row goes through
417
- * here, so the assertion exists once instead of at each call site.
418
- */
419
- asRowLike(item) {
420
- return item;
421
- }
422
- getCellValue(item, key) {
423
- return this.asRowLike(item)[key];
424
- }
425
- /** Applied as `flex-basis`, `min-width` AND `max-width` on header and body cells alike — see the SCSS. */
426
- columnWidth(column) {
427
- return column.styles?.width ?? DEFAULT_COLUMN_WIDTH;
428
- }
429
- emitRowClick(event, row) {
430
- if (!this.rowsClickable() || row.kind !== 'data') {
431
- return;
432
- }
433
- if (this.isInteractiveTarget(event) || this.hasTextSelection()) {
434
- return;
435
- }
436
- this.rowClick.emit({ row: row.item, index: row.index });
437
- }
438
- rowTestId(row) {
439
- const testId = this.testId();
440
- return testId && row.kind === 'data' ? `${testId}-row-${row.index}` : null;
441
- }
442
- cellTestId(row, columnKey) {
443
- const testId = this.testId();
444
- return testId && row.kind === 'data' ? `${testId}-cell-${row.index}-${columnKey}` : null;
445
- }
446
- rowCheckboxTestId(row) {
447
- const rowTestId = this.rowTestId(row);
448
- return rowTestId ? `${rowTestId}-select` : null;
449
- }
450
- isRowSelected(row) {
451
- return this.selectable() && row.kind === 'data' && Boolean(this.asRowLike(row.item).selected);
452
- }
453
- emitSelectionChange(row, selected) {
454
- if (row.kind !== 'data') {
455
- return;
456
- }
457
- this.selectionChange.emit({ row: row.item, index: row.index, selected });
458
- }
459
- /** Reads `--ui-ist-checkbox-width` so the offset cannot drift from the checkbox column's own width. */
460
- stickyStartLeft(column) {
461
- if (column.key !== this.stickyStartKey()) {
462
- return null;
463
- }
464
- return this.selectable() ? 'var(--ui-ist-checkbox-width)' : '0px';
465
- }
466
- /**
467
- * Only the outermost start-pinned cell may cast the sticky shadow: the checkbox cell is pinned too, and
468
- * shadowing both would drop a shadow across the column beside it.
469
- */
470
- isStickyStartEdge(column) {
471
- return column.key === this.stickyStartKey();
472
- }
473
- activateRow(event, row) {
474
- if (!this.rowsClickable() || row.kind !== 'data') {
475
- return;
476
- }
477
- if (this.isInteractiveTarget(event)) {
478
- return;
479
- }
480
- // Only after the guards, so a non-clickable table never swallows page-scroll-by-space.
481
- event.preventDefault();
482
- this.rowClick.emit({ row: row.item, index: row.index });
483
- }
484
- /** A clickable row matches `[tabindex]` itself, so `currentTarget` must be excluded explicitly. */
485
- isInteractiveTarget(event) {
486
- const target = event.target;
487
- if (!(target instanceof Element)) {
488
- return false;
489
- }
490
- const interactive = target.closest(INTERACTIVE_TARGET_SELECTOR);
491
- return interactive !== null && interactive !== event.currentTarget;
492
- }
493
- /** Whether the user is selecting text, in which case a click is a selection gesture, not activation. */
494
- hasTextSelection() {
495
- const selection = typeof window !== 'undefined' ? window.getSelection() : null;
496
- return Boolean(selection && !selection.isCollapsed && selection.toString().length > 0);
497
- }
498
- /**
499
- * Deferred a frame to read the settled layout and never trip "ResizeObserver loop limit exceeded";
500
- * repeated triggers coalesce to one measure.
501
- */
502
- scheduleViewportRemeasure() {
503
- if (typeof requestAnimationFrame === 'undefined') {
504
- this.viewport()?.checkViewportSize();
505
- this.settleLoadMore();
506
- return;
507
- }
508
- if (this.remeasureFrame !== undefined) {
509
- cancelAnimationFrame(this.remeasureFrame);
510
- }
511
- this.remeasureFrame = requestAnimationFrame(() => {
512
- this.remeasureFrame = undefined;
513
- this.viewport()?.checkViewportSize();
514
- this.syncHorizontalScroll();
515
- this.settleLoadMore();
516
- });
517
- }
518
- /**
519
- * The third `checkLoadMore` trigger, and the only one that survives a page landing without a rendered-range
520
- * change. CDK emits a range only when the virtual-for LENGTH changes, so a page whose row count exactly
521
- * replaces the load-more skeletons (`data + skeletons` before, `data` after) moves nothing CDK watches —
522
- * and when the new rows add no scrollable height, no scroll event can ever arrive either. Runs after the
523
- * re-measure so the zone is tested against the size CDK just settled on.
524
- */
525
- settleLoadMore() {
526
- this.rearmLoadMoreIfUnreachable();
527
- this.checkLoadMore();
528
- }
529
- emitRetry() {
530
- this.retry.emit();
531
- }
532
- /**
533
- * The index fallback is identity-in-name-only — it cannot tell rows apart after a reorder — which is why
534
- * the automatic scroll reset cannot work without `trackBy` or `rowIdKey`.
535
- */
536
- rowIdentity(item, index) {
537
- const explicitTrackBy = this.trackBy();
538
- if (explicitTrackBy) {
539
- return explicitTrackBy(index, item);
540
- }
541
- const key = this.rowIdKey();
542
- return key ? this.asRowLike(item)[key] : index;
543
- }
544
- /**
545
- * Assigning an absolute `scrollLeft` is drift-free by construction: it self-corrects every scroll event
546
- * and the browser clamps when the header's maximum is momentarily smaller. A progress-normalized CSS
547
- * scroll-timeline cannot guarantee that, which is why it was removed — do not reintroduce one.
548
- */
549
- syncHorizontalScroll() {
550
- const viewport = this.viewport();
551
- if (!viewport) {
552
- return;
553
- }
554
- const left = viewport.measureScrollOffset('left');
555
- const right = viewport.measureScrollOffset('right');
556
- const header = this.headerScroll();
557
- if (header) {
558
- // Rounded: columns are pixel-identical, so a sub-pixel offset misaligns every one of them.
559
- header.nativeElement.scrollLeft = Math.round(left);
560
- }
561
- this.scrollStart.set(left <= 1);
562
- this.scrollEnd.set(right <= 1);
563
- this.horizontalScroll.set(left + right > 1);
564
- }
565
- /**
566
- * How many rows the viewport shows. Zero until CDK has measured, which callers must treat as
567
- * "unknown" rather than "none".
568
- */
569
- visibleRowCount() {
570
- return Math.ceil((this.viewport()?.getViewportSize() ?? 0) / this.rowHeight());
571
- }
572
- /**
573
- * Rows from the end that count as "approaching it". Capped at a screenful: a threshold wider than the
574
- * viewport cannot mean approaching, and uncapped it made the zone unleavable at every scroll position,
575
- * which is how an oversized `loadMoreThreshold` used to walk a whole dataset unattended. Clamped at 0 so
576
- * a negative value can't push the trigger point past the end and disable paging outright.
577
- */
578
- triggerZoneRows(visibleRows) {
579
- const threshold = Math.max(0, this.loadMoreThreshold());
580
- // Capped only once the viewport is measured — before that there is no screenful to compare against,
581
- // and capping at 0 would silently disable paging on the first pass.
582
- return visibleRows > 0 ? Math.min(threshold, visibleRows) : threshold;
583
- }
584
- /**
585
- * The rendered range includes CDK's read-ahead buffer, so measuring it conflates the user reaching the
586
- * end with CDK merely pre-rendering it. The visible end has no such slack, so it tracks the user's
587
- * actual scroll position instead.
588
- */
589
- isInTriggerZone(dataLength, visibleRows) {
590
- return this.firstVisibleIndex + visibleRows >= dataLength - this.triggerZoneRows(visibleRows);
591
- }
592
- /**
593
- * Re-arms the latch when something other than scrolling has to do it. Two cases, both of which used to
594
- * be terminal stalls:
595
- *
596
- * - **The requested page landed.** `data` grew past its length at the last emission, so that emission is
597
- * spent. Without this, re-arming needed the user to scroll *out* of the zone and back — impossible when
598
- * the page was smaller than the threshold, and impossible to even attempt when the new rows added no
599
- * scrollable height.
600
- * - **The zone can't be left.** `visibleEnd` bottoms out at `visibleRows`, so while that floor sits
601
- * inside the zone no amount of scrolling re-arms anything. Also covers a not-yet-measured viewport,
602
- * which must count as unleavable or the first fill never starts.
603
- *
604
- * Deliberately not driven by `loadingMore` or `error`: a failed fetch clears `loadingMore` without
605
- * growing `data`, and must stay disarmed rather than re-fire in a loop.
606
- */
607
- rearmLoadMoreIfUnreachable() {
608
- const dataLength = this.data().length;
609
- const visibleRows = this.visibleRowCount();
610
- if (dataLength > this.dataLengthAtEmit) {
611
- this.isLoadMoreArmed = true;
612
- return;
613
- }
614
- if (visibleRows === 0 || visibleRows >= dataLength - this.triggerZoneRows(visibleRows)) {
615
- this.isLoadMoreArmed = true;
616
- }
617
- }
618
- /** Emits at most once per page that lands while the user is inside the trigger zone. */
619
- checkLoadMore() {
620
- const viewport = this.viewport();
621
- // `error()` pauses auto-loading until the consumer clears it, rather than instantly re-firing.
622
- if (!viewport || !this.hasMore() || this.loading() || this.loadingMore() || this.error()) {
623
- return;
624
- }
625
- const dataLength = this.data().length;
626
- if (dataLength === 0) {
627
- return;
628
- }
629
- if (!this.isInTriggerZone(dataLength, this.visibleRowCount())) {
630
- this.isLoadMoreArmed = true;
631
- return;
632
- }
633
- if (this.isLoadMoreArmed) {
634
- this.isLoadMoreArmed = false;
635
- this.dataLengthAtEmit = dataLength;
636
- this.loadMore.emit();
637
- }
638
- }
639
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: InfiniteScrollTableComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
640
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.25", type: InfiniteScrollTableComponent, isStandalone: true, selector: "ui-infinite-scroll-table", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: true, transformFunction: null }, columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: true, transformFunction: null }, rowHeight: { classPropertyName: "rowHeight", publicName: "rowHeight", isSignal: true, isRequired: true, transformFunction: null }, trackBy: { classPropertyName: "trackBy", publicName: "trackBy", isSignal: true, isRequired: false, transformFunction: null }, rowIdKey: { classPropertyName: "rowIdKey", publicName: "rowIdKey", isSignal: true, isRequired: false, transformFunction: null }, minBufferPx: { classPropertyName: "minBufferPx", publicName: "minBufferPx", isSignal: true, isRequired: false, transformFunction: null }, maxBufferPx: { classPropertyName: "maxBufferPx", publicName: "maxBufferPx", isSignal: true, isRequired: false, transformFunction: null }, maxHeight: { classPropertyName: "maxHeight", publicName: "maxHeight", isSignal: true, isRequired: false, transformFunction: null }, fillHeight: { classPropertyName: "fillHeight", publicName: "fillHeight", isSignal: true, isRequired: false, transformFunction: null }, isCondensed: { classPropertyName: "isCondensed", publicName: "isCondensed", isSignal: true, isRequired: false, transformFunction: null }, selectable: { classPropertyName: "selectable", publicName: "selectable", isSignal: true, isRequired: false, transformFunction: null }, rowsClickable: { classPropertyName: "rowsClickable", publicName: "rowsClickable", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, loadingMore: { classPropertyName: "loadingMore", publicName: "loadingMore", isSignal: true, isRequired: false, transformFunction: null }, hasMore: { classPropertyName: "hasMore", publicName: "hasMore", isSignal: true, isRequired: true, transformFunction: null }, skeletonRowCount: { classPropertyName: "skeletonRowCount", publicName: "skeletonRowCount", isSignal: true, isRequired: false, transformFunction: null }, loadMoreSkeletonCount: { classPropertyName: "loadMoreSkeletonCount", publicName: "loadMoreSkeletonCount", isSignal: true, isRequired: false, transformFunction: null }, loadingColumnCount: { classPropertyName: "loadingColumnCount", publicName: "loadingColumnCount", isSignal: true, isRequired: false, transformFunction: null }, loadMoreThreshold: { classPropertyName: "loadMoreThreshold", publicName: "loadMoreThreshold", isSignal: true, isRequired: false, transformFunction: null }, noDataTemplate: { classPropertyName: "noDataTemplate", publicName: "noDataTemplate", isSignal: true, isRequired: false, transformFunction: null }, errorTemplate: { classPropertyName: "errorTemplate", publicName: "errorTemplate", isSignal: true, isRequired: false, transformFunction: null }, error: { classPropertyName: "error", publicName: "error", isSignal: true, isRequired: false, transformFunction: null }, endOfListTemplate: { classPropertyName: "endOfListTemplate", publicName: "endOfListTemplate", isSignal: true, isRequired: false, transformFunction: null }, testId: { classPropertyName: "testId", publicName: "testId", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { loadMore: "loadMore", retry: "retry", rowClick: "rowClick", selectionChange: "selectionChange" }, host: { properties: { "class.ui-ist--fill-host": "fillHeight()" } }, viewQueries: [{ propertyName: "viewport", first: true, predicate: CdkVirtualScrollViewport, descendants: true, isSignal: true }, { propertyName: "headerScroll", first: true, predicate: ["headerScroll"], descendants: true, isSignal: true }], ngImport: i0, template: "<!-- role=\"table\", not \"grid\": row access is Tab-only with no arrow-key cell traversal, so \"grid\" would\n promise 2D keyboard navigation this does not implement. Selection is conveyed by the row's checkbox,\n not `aria-selected` \u2014 which is valid only on grid/treegrid anyway. -->\n<div\n class=\"ui-ist\"\n role=\"table\"\n [class.ui-ist--condensed]=\"isCondensed()\"\n [class.ui-ist--scrolled-start]=\"!scrollStart()\"\n [class.ui-ist--scrolled-end]=\"horizontalScroll() && !scrollEnd()\"\n [class.ui-ist--fill-height]=\"fillHeight()\"\n [attr.aria-rowcount]=\"hasMore() ? -1 : data().length + 1\"\n [attr.aria-busy]=\"loading() || loadingMore()\"\n [attr.aria-label]=\"ariaLabel() || null\"\n [attr.data-testid]=\"testId()\"\n>\n <!-- Pinned header, outside the viewport so it never scrolls vertically. The outer element reserves the\n body's scrollbar width as padding (keeping the background and border across that strip); the inner\n one carries the horizontal scrollLeft synced from the body. -->\n <div class=\"ui-ist__header\" [style.padding-right.px]=\"scrollbarWidth()\" role=\"presentation\">\n <div #headerScroll class=\"ui-ist__header-scroll\" role=\"presentation\">\n <div class=\"ui-ist__row ui-ist__row--header\" role=\"row\" aria-rowindex=\"1\">\n @if (selectable()) {\n <div\n class=\"ui-ist__cell ui-ist__cell--header ui-ist__cell--checkbox ui-ist__cell--sticky-start\"\n [class.ui-ist__cell--sticky-start-edge]=\"!stickyStartKey()\"\n role=\"columnheader\"\n ></div>\n }\n @for (column of columns(); track column.key; let colIndex = $index) {\n <div\n class=\"ui-ist__cell ui-ist__cell--header\"\n role=\"columnheader\"\n [class.ui-ist__cell--sticky-start]=\"column.key === stickyStartKey()\"\n [class.ui-ist__cell--sticky-start-edge]=\"isStickyStartEdge(column)\"\n [class.ui-ist__cell--sticky-end]=\"column.key === stickyEndKey()\"\n [class.ui-ist__cell--right]=\"column.styles?.alignment === 'right'\"\n [class.ui-ist__cell--center]=\"column.styles?.alignment === 'center'\"\n [style.flex-basis]=\"columnWidth(column)\"\n [style.min-width]=\"columnWidth(column)\"\n [style.max-width]=\"columnWidth(column)\"\n [style.left]=\"stickyStartLeft(column)\"\n >\n @if (column.headerCellTemplate) {\n <ng-container\n *ngTemplateOutlet=\"column.headerCellTemplate; context: { $implicit: column.title, column, colIndex }\"\n ></ng-container>\n } @else {\n <span class=\"ui-ist__cell-text\">{{ column.title }}</span>\n }\n </div>\n }\n @for (loadingKey of loadingColumns(); track loadingKey) {\n <div\n class=\"ui-ist__cell ui-ist__cell--header ui-ist__cell--loading\"\n role=\"presentation\"\n aria-hidden=\"true\"\n [style.flex-basis]=\"defaultColumnWidth\"\n [style.min-width]=\"defaultColumnWidth\"\n [style.max-width]=\"defaultColumnWidth\"\n >\n <ui-skeleton class=\"ui-ist__skeleton\" [count]=\"1\" [theme]=\"skeletonTheme\" appearance=\"line\"></ui-skeleton>\n </div>\n }\n <div class=\"ui-ist__cell ui-ist__cell--spacer\" role=\"presentation\" aria-hidden=\"true\"></div>\n </div>\n </div>\n </div>\n\n <!-- The CDK viewport owns BOTH vertical (virtualized) and horizontal scroll, so sticky columns pin\n against it and the horizontal scrollbar sits at the viewport bottom. -->\n @if (showViewport()) {\n <cdk-virtual-scroll-viewport\n class=\"ui-ist__body\"\n role=\"rowgroup\"\n [itemSize]=\"rowHeight()\"\n [minBufferPx]=\"effectiveMinBufferPx()\"\n [maxBufferPx]=\"effectiveMaxBufferPx()\"\n [style.height]=\"viewportHeight()\"\n [style.max-height]=\"fillHeight() ? maxHeight() : null\"\n >\n <div\n *cdkVirtualFor=\"let row of renderRows(); let rowIndex = index; trackBy: renderRowTrackBy\"\n class=\"ui-ist__row\"\n role=\"row\"\n [class.ui-ist__row--clickable]=\"rowsClickable() && row.kind === 'data'\"\n [class.ui-ist__row--selected]=\"isRowSelected(row)\"\n [attr.aria-rowindex]=\"row.kind === 'data' ? row.index + 2 : null\"\n [attr.aria-hidden]=\"row.kind === 'skeleton' ? true : null\"\n [attr.tabindex]=\"rowsClickable() && row.kind === 'data' ? 0 : null\"\n [style.height.px]=\"rowHeight()\"\n [attr.data-testid]=\"rowTestId(row)\"\n (click)=\"emitRowClick($event, row)\"\n (keydown.enter)=\"activateRow($event, row)\"\n (keydown.space)=\"activateRow($event, row)\"\n >\n @if (selectable()) {\n <!-- This `stopPropagation` is what actually stops a checkbox click activating the row: it runs\n before the click reaches the row's listener, so `isInteractiveTarget` is never consulted on\n this path. That guard is a real second line of defence (`ui-checkbox` renders a focusable\n wrapper and a native input, both matching INTERACTIVE_TARGET_SELECTOR), not a substitute. -->\n <div\n class=\"ui-ist__cell ui-ist__cell--checkbox ui-ist__cell--sticky-start\"\n [class.ui-ist__cell--sticky-start-edge]=\"!stickyStartKey()\"\n role=\"cell\"\n (click)=\"$event.stopPropagation()\"\n (keydown)=\"$event.stopPropagation()\"\n >\n @if (row.kind === 'data') {\n <ui-checkbox\n [checked]=\"isRowSelected(row)\"\n [ariaLabel]=\"'Select row ' + (row.index + 1)\"\n [testId]=\"rowCheckboxTestId(row)\"\n (changed)=\"emitSelectionChange(row, $event)\"\n ></ui-checkbox>\n }\n </div>\n }\n @for (column of columns(); track column.key) {\n <div\n class=\"ui-ist__cell\"\n role=\"cell\"\n [class.ui-ist__cell--sticky-start]=\"column.key === stickyStartKey()\"\n [class.ui-ist__cell--sticky-start-edge]=\"isStickyStartEdge(column)\"\n [class.ui-ist__cell--sticky-end]=\"column.key === stickyEndKey()\"\n [class.ui-ist__cell--right]=\"column.styles?.alignment === 'right'\"\n [class.ui-ist__cell--center]=\"column.styles?.alignment === 'center'\"\n [style.flex-basis]=\"columnWidth(column)\"\n [style.min-width]=\"columnWidth(column)\"\n [style.max-width]=\"columnWidth(column)\"\n [style.left]=\"stickyStartLeft(column)\"\n [attr.data-testid]=\"cellTestId(row, column.key)\"\n >\n @if (row.kind === 'skeleton') {\n <ui-skeleton class=\"ui-ist__skeleton\" [count]=\"1\" [theme]=\"skeletonTheme\" appearance=\"line\"></ui-skeleton>\n } @else if (column.rowCellTemplate) {\n <ng-container\n *ngTemplateOutlet=\"column.rowCellTemplate; context: { $implicit: row.item, rowIndex: row.index }\"\n ></ng-container>\n } @else {\n <span class=\"ui-ist__cell-text\">{{ getCellValue(row.item, column.key) }}</span>\n }\n </div>\n }\n @for (loadingKey of loadingColumns(); track loadingKey) {\n <div\n class=\"ui-ist__cell ui-ist__cell--loading\"\n role=\"presentation\"\n aria-hidden=\"true\"\n [style.flex-basis]=\"defaultColumnWidth\"\n [style.min-width]=\"defaultColumnWidth\"\n [style.max-width]=\"defaultColumnWidth\"\n >\n <ui-skeleton class=\"ui-ist__skeleton\" [count]=\"1\" [theme]=\"skeletonTheme\" appearance=\"line\"></ui-skeleton>\n </div>\n }\n <div class=\"ui-ist__cell ui-ist__cell--spacer\" role=\"presentation\" aria-hidden=\"true\"></div>\n </div>\n </cdk-virtual-scroll-viewport>\n }\n\n <!-- `showErrorFooter()` and `showErrorState()` differ only on `hasData()`, so they are mutually\n exclusive and safe to merge here. Both fall back to a plain-language message, so a failed fetch is\n never a silent blank box. -->\n @if (showErrorFooter() || showErrorState()) {\n <div class=\"ui-ist__state\" role=\"alert\">\n @if (errorTemplate(); as errorTpl) {\n <ng-container *ngTemplateOutlet=\"errorTpl; context: errorContext\"></ng-container>\n } @else {\n <span>{{ translationContext + 'LOAD_ERROR' | uiTranslate | async }}</span>\n }\n </div>\n }\n\n @if (showEmptyState()) {\n <div class=\"ui-ist__state\">\n @if (noDataTemplate(); as emptyTpl) {\n <ng-container *ngTemplateOutlet=\"emptyTpl\"></ng-container>\n } @else {\n <span>{{ translationContext + 'NO_ROWS' | uiTranslate | async }}</span>\n }\n </div>\n }\n\n <!-- Opt-in, with no fallback (see `endOfListTemplate`). Not role=\"alert\": reaching the end is not an\n alert, and `aria-rowcount` already conveys completeness to assistive tech. -->\n @if (showEndOfList() && endOfListTemplate(); as endTpl) {\n <div class=\"ui-ist__state\">\n <ng-container *ngTemplateOutlet=\"endTpl\"></ng-container>\n </div>\n }\n\n <span class=\"ui-ist__sr-only\" role=\"status\" aria-live=\"polite\">\n @if (statusMessageKey(); as statusKey) {\n {{ statusKey | uiTranslate | async }}\n }\n </span>\n</div>\n", styles: [".bg-teal-60b{background:#1c443c}.bg-teal-30b{background:#31766a}.bg-teal-default{background:#46a997}.bg-teal-30w{background:#7ec3b6}.bg-teal-60w{background:#b5ddd5}.bg-teal-secondary{background:#cbd6cb}.bg-teal-90w{background:#ecf6f5}.bg-petrol-60b{background:#102930}.bg-petrol-30b{background:#1b4754}.bg-petrol-default{background:#276678}.bg-petrol-30w{background:#6894a0}.bg-petrol-60w{background:#a9c2c9}.bg-petrol-secondary{background:#c8d7de}.bg-petrol-90w{background:#e9f0f1}.bg-error-60b{background:#513131}.bg-error-30b{background:#8e5655}.bg-error-60w{background:#e3c3c6}.bg-error-secondary{background:#f0dad9}.bg-error-default{background:#cb7b7a}.bg-warning-secondary{background:#f0d6bb}.bg-warning-default{background:#cca45f}.bg-black{background:#000}.bg-dark{background:#888}.bg-medium{background:#e0e0e0}.bg-grey{background:#ededed}.bg-light{background:#f6f6f6}.bg-white{background:#fff}.bg-box-shadow{background:#00000014}.bg-navigation-subtitle{background:#528593}.bgc-teal-60b{background-color:#1c443c}.bgc-teal-30b{background-color:#31766a}.bgc-teal-default{background-color:#46a997}.bgc-teal-30w{background-color:#7ec3b6}.bgc-teal-60w{background-color:#b5ddd5}.bgc-teal-secondary{background-color:#cbd6cb}.bgc-teal-90w{background-color:#ecf6f5}.bgc-petrol-60b{background-color:#102930}.bgc-petrol-30b{background-color:#1b4754}.bgc-petrol-default{background-color:#276678}.bgc-petrol-30w{background-color:#6894a0}.bgc-petrol-60w{background-color:#a9c2c9}.bgc-petrol-secondary{background-color:#c8d7de}.bgc-petrol-90w{background-color:#e9f0f1}.bgc-error-60b{background-color:#513131}.bgc-error-30b{background-color:#8e5655}.bgc-error-60w{background-color:#e3c3c6}.bgc-error-secondary{background-color:#f0dad9}.bgc-error-default{background-color:#cb7b7a}.bgc-warning-secondary{background-color:#f0d6bb}.bgc-warning-default{background-color:#cca45f}.bgc-black{background-color:#000}.bgc-dark{background-color:#888}.bgc-medium{background-color:#e0e0e0}.bgc-grey{background-color:#ededed}.bgc-light{background-color:#f6f6f6}.bgc-white{background-color:#fff}.bgc-box-shadow{background-color:#00000014}.bgc-navigation-subtitle{background-color:#528593}:host{display:block}.ui-ist{--ui-ist-checkbox-width: 56px;--ui-ist-skeleton-bg: #f4f4f4;display:flex;flex-direction:column;border:1px solid #e0e0e0;border-radius:8px;overflow:hidden;background:#fff}.ui-ist__header{flex:0 0 auto;box-sizing:border-box;overflow:hidden;border-bottom:1px solid #e0e0e0;background:var(--ui-ist-header-bg, #ffffff)}.ui-ist__header-scroll{overflow:hidden}.ui-ist__body{flex:1 1 auto;overflow:auto;scrollbar-width:auto}.ui-ist__body::-webkit-scrollbar{width:8px;height:8px}.ui-ist__body::-webkit-scrollbar-button{display:none}.ui-ist__body::-webkit-scrollbar-thumb{background-color:#00000059;border-radius:4px}.ui-ist__body::-webkit-scrollbar-track:hover{background-color:#00000026}.ui-ist__row{display:flex;width:max-content;min-width:100%;box-sizing:border-box}.ui-ist__row--header{min-height:56px}.ui-ist__row:not(.ui-ist__row--header){border-bottom:1px solid #d3d3d3}.ui-ist__row--clickable{cursor:pointer}.ui-ist__row--clickable:not(.ui-ist__row--selected):hover{background:#fff2fc}.ui-ist__row--clickable:not(.ui-ist__row--selected):hover .ui-ist__cell{background:#fff2fc}.ui-ist__row--selected .ui-ist__cell{background:#f4f4f4}.ui-ist__cell{flex-grow:0;flex-shrink:0;box-sizing:border-box;display:flex;align-items:center;padding:8px 24px;font-size:14px;line-height:20px;overflow:hidden;background:#fff}.ui-ist__cell--header{background:var(--ui-ist-header-bg, #ffffff);font-weight:700;font-size:14px;line-height:16px}.ui-ist__cell--right{justify-content:flex-end;text-align:right}.ui-ist__cell--center{justify-content:center;text-align:center}.ui-ist__cell--sticky-start{position:sticky;z-index:2}.ui-ist__cell--checkbox.ui-ist__cell--sticky-start{left:0}.ui-ist__cell--sticky-end{position:sticky;right:0;z-index:2;order:1}.ui-ist__cell--checkbox{flex:0 0 var(--ui-ist-checkbox-width);min-width:var(--ui-ist-checkbox-width);justify-content:center;padding:0}.ui-ist__cell--spacer{flex:1 1 auto;min-width:0;padding:0}.ui-ist__row--header .ui-ist__cell--spacer{background:var(--ui-ist-header-bg, #ffffff)}.ui-ist__cell-text{overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.ui-ist__skeleton{display:block;width:100%}.ui-ist--scrolled-start .ui-ist__cell--sticky-start-edge{box-shadow:24px 8px 24px #24242414}.ui-ist--scrolled-end .ui-ist__cell--sticky-end{box-shadow:0 8px 24px 4px #24242414}.ui-ist__state{padding:8px 24px;font-size:14px;line-height:20px}.ui-ist--condensed .ui-ist__cell{padding:8px 12px}.ui-ist--condensed .ui-ist__cell:first-child{padding-left:24px}.ui-ist--condensed .ui-ist__cell--sticky-end{padding-right:24px}.ui-ist--condensed .ui-ist__cell--spacer{padding:0}:host(.ui-ist--fill-host){height:100%}.ui-ist--fill-height{height:100%}.ui-ist--fill-height .ui-ist__body{min-height:0}.ui-ist__sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: CdkVirtualScrollViewport, selector: "cdk-virtual-scroll-viewport", inputs: ["orientation", "appendOnly"], outputs: ["scrolledIndexChange"] }, { kind: "directive", type: CdkFixedSizeVirtualScroll, selector: "cdk-virtual-scroll-viewport[itemSize]", inputs: ["itemSize", "minBufferPx", "maxBufferPx"] }, { kind: "directive", type: CdkVirtualForOf, selector: "[cdkVirtualFor][cdkVirtualForOf]", inputs: ["cdkVirtualForOf", "cdkVirtualForTrackBy", "cdkVirtualForTemplate", "cdkVirtualForTemplateCacheSize"] }, { kind: "component", type: SkeletonComponent, selector: "ui-skeleton", inputs: ["count", "theme", "appearance", "isAiTheme", "applicationTheme"] }, { kind: "component", type: CheckboxComponent, selector: "ui-checkbox", inputs: ["disabled", "checked", "indeterminate", "companyColor", "name", "label", "multiple", "applicationTheme", "ariaLabel", "testId", "ariaRequired", "hasError", "hideBuiltInErrors", "hideLabelInErrors", "ariaLabelledby", "ariaDescribedby", "truncateText", "alignment", "tabIndex"], outputs: ["changed"] }, { kind: "pipe", type: AsyncPipe, name: "async" }, { kind: "pipe", type: UiTranslatePipe, name: "uiTranslate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
641
- }
642
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: InfiniteScrollTableComponent, decorators: [{
643
- type: Component,
644
- args: [{ selector: 'ui-infinite-scroll-table', changeDetection: ChangeDetectionStrategy.OnPush, host: {
645
- '[class.ui-ist--fill-host]': 'fillHeight()',
646
- }, imports: [
647
- AsyncPipe,
648
- NgTemplateOutlet,
649
- CdkVirtualScrollViewport,
650
- CdkFixedSizeVirtualScroll,
651
- CdkVirtualForOf,
652
- SkeletonComponent,
653
- CheckboxComponent,
654
- UiTranslatePipe,
655
- ], template: "<!-- role=\"table\", not \"grid\": row access is Tab-only with no arrow-key cell traversal, so \"grid\" would\n promise 2D keyboard navigation this does not implement. Selection is conveyed by the row's checkbox,\n not `aria-selected` \u2014 which is valid only on grid/treegrid anyway. -->\n<div\n class=\"ui-ist\"\n role=\"table\"\n [class.ui-ist--condensed]=\"isCondensed()\"\n [class.ui-ist--scrolled-start]=\"!scrollStart()\"\n [class.ui-ist--scrolled-end]=\"horizontalScroll() && !scrollEnd()\"\n [class.ui-ist--fill-height]=\"fillHeight()\"\n [attr.aria-rowcount]=\"hasMore() ? -1 : data().length + 1\"\n [attr.aria-busy]=\"loading() || loadingMore()\"\n [attr.aria-label]=\"ariaLabel() || null\"\n [attr.data-testid]=\"testId()\"\n>\n <!-- Pinned header, outside the viewport so it never scrolls vertically. The outer element reserves the\n body's scrollbar width as padding (keeping the background and border across that strip); the inner\n one carries the horizontal scrollLeft synced from the body. -->\n <div class=\"ui-ist__header\" [style.padding-right.px]=\"scrollbarWidth()\" role=\"presentation\">\n <div #headerScroll class=\"ui-ist__header-scroll\" role=\"presentation\">\n <div class=\"ui-ist__row ui-ist__row--header\" role=\"row\" aria-rowindex=\"1\">\n @if (selectable()) {\n <div\n class=\"ui-ist__cell ui-ist__cell--header ui-ist__cell--checkbox ui-ist__cell--sticky-start\"\n [class.ui-ist__cell--sticky-start-edge]=\"!stickyStartKey()\"\n role=\"columnheader\"\n ></div>\n }\n @for (column of columns(); track column.key; let colIndex = $index) {\n <div\n class=\"ui-ist__cell ui-ist__cell--header\"\n role=\"columnheader\"\n [class.ui-ist__cell--sticky-start]=\"column.key === stickyStartKey()\"\n [class.ui-ist__cell--sticky-start-edge]=\"isStickyStartEdge(column)\"\n [class.ui-ist__cell--sticky-end]=\"column.key === stickyEndKey()\"\n [class.ui-ist__cell--right]=\"column.styles?.alignment === 'right'\"\n [class.ui-ist__cell--center]=\"column.styles?.alignment === 'center'\"\n [style.flex-basis]=\"columnWidth(column)\"\n [style.min-width]=\"columnWidth(column)\"\n [style.max-width]=\"columnWidth(column)\"\n [style.left]=\"stickyStartLeft(column)\"\n >\n @if (column.headerCellTemplate) {\n <ng-container\n *ngTemplateOutlet=\"column.headerCellTemplate; context: { $implicit: column.title, column, colIndex }\"\n ></ng-container>\n } @else {\n <span class=\"ui-ist__cell-text\">{{ column.title }}</span>\n }\n </div>\n }\n @for (loadingKey of loadingColumns(); track loadingKey) {\n <div\n class=\"ui-ist__cell ui-ist__cell--header ui-ist__cell--loading\"\n role=\"presentation\"\n aria-hidden=\"true\"\n [style.flex-basis]=\"defaultColumnWidth\"\n [style.min-width]=\"defaultColumnWidth\"\n [style.max-width]=\"defaultColumnWidth\"\n >\n <ui-skeleton class=\"ui-ist__skeleton\" [count]=\"1\" [theme]=\"skeletonTheme\" appearance=\"line\"></ui-skeleton>\n </div>\n }\n <div class=\"ui-ist__cell ui-ist__cell--spacer\" role=\"presentation\" aria-hidden=\"true\"></div>\n </div>\n </div>\n </div>\n\n <!-- The CDK viewport owns BOTH vertical (virtualized) and horizontal scroll, so sticky columns pin\n against it and the horizontal scrollbar sits at the viewport bottom. -->\n @if (showViewport()) {\n <cdk-virtual-scroll-viewport\n class=\"ui-ist__body\"\n role=\"rowgroup\"\n [itemSize]=\"rowHeight()\"\n [minBufferPx]=\"effectiveMinBufferPx()\"\n [maxBufferPx]=\"effectiveMaxBufferPx()\"\n [style.height]=\"viewportHeight()\"\n [style.max-height]=\"fillHeight() ? maxHeight() : null\"\n >\n <div\n *cdkVirtualFor=\"let row of renderRows(); let rowIndex = index; trackBy: renderRowTrackBy\"\n class=\"ui-ist__row\"\n role=\"row\"\n [class.ui-ist__row--clickable]=\"rowsClickable() && row.kind === 'data'\"\n [class.ui-ist__row--selected]=\"isRowSelected(row)\"\n [attr.aria-rowindex]=\"row.kind === 'data' ? row.index + 2 : null\"\n [attr.aria-hidden]=\"row.kind === 'skeleton' ? true : null\"\n [attr.tabindex]=\"rowsClickable() && row.kind === 'data' ? 0 : null\"\n [style.height.px]=\"rowHeight()\"\n [attr.data-testid]=\"rowTestId(row)\"\n (click)=\"emitRowClick($event, row)\"\n (keydown.enter)=\"activateRow($event, row)\"\n (keydown.space)=\"activateRow($event, row)\"\n >\n @if (selectable()) {\n <!-- This `stopPropagation` is what actually stops a checkbox click activating the row: it runs\n before the click reaches the row's listener, so `isInteractiveTarget` is never consulted on\n this path. That guard is a real second line of defence (`ui-checkbox` renders a focusable\n wrapper and a native input, both matching INTERACTIVE_TARGET_SELECTOR), not a substitute. -->\n <div\n class=\"ui-ist__cell ui-ist__cell--checkbox ui-ist__cell--sticky-start\"\n [class.ui-ist__cell--sticky-start-edge]=\"!stickyStartKey()\"\n role=\"cell\"\n (click)=\"$event.stopPropagation()\"\n (keydown)=\"$event.stopPropagation()\"\n >\n @if (row.kind === 'data') {\n <ui-checkbox\n [checked]=\"isRowSelected(row)\"\n [ariaLabel]=\"'Select row ' + (row.index + 1)\"\n [testId]=\"rowCheckboxTestId(row)\"\n (changed)=\"emitSelectionChange(row, $event)\"\n ></ui-checkbox>\n }\n </div>\n }\n @for (column of columns(); track column.key) {\n <div\n class=\"ui-ist__cell\"\n role=\"cell\"\n [class.ui-ist__cell--sticky-start]=\"column.key === stickyStartKey()\"\n [class.ui-ist__cell--sticky-start-edge]=\"isStickyStartEdge(column)\"\n [class.ui-ist__cell--sticky-end]=\"column.key === stickyEndKey()\"\n [class.ui-ist__cell--right]=\"column.styles?.alignment === 'right'\"\n [class.ui-ist__cell--center]=\"column.styles?.alignment === 'center'\"\n [style.flex-basis]=\"columnWidth(column)\"\n [style.min-width]=\"columnWidth(column)\"\n [style.max-width]=\"columnWidth(column)\"\n [style.left]=\"stickyStartLeft(column)\"\n [attr.data-testid]=\"cellTestId(row, column.key)\"\n >\n @if (row.kind === 'skeleton') {\n <ui-skeleton class=\"ui-ist__skeleton\" [count]=\"1\" [theme]=\"skeletonTheme\" appearance=\"line\"></ui-skeleton>\n } @else if (column.rowCellTemplate) {\n <ng-container\n *ngTemplateOutlet=\"column.rowCellTemplate; context: { $implicit: row.item, rowIndex: row.index }\"\n ></ng-container>\n } @else {\n <span class=\"ui-ist__cell-text\">{{ getCellValue(row.item, column.key) }}</span>\n }\n </div>\n }\n @for (loadingKey of loadingColumns(); track loadingKey) {\n <div\n class=\"ui-ist__cell ui-ist__cell--loading\"\n role=\"presentation\"\n aria-hidden=\"true\"\n [style.flex-basis]=\"defaultColumnWidth\"\n [style.min-width]=\"defaultColumnWidth\"\n [style.max-width]=\"defaultColumnWidth\"\n >\n <ui-skeleton class=\"ui-ist__skeleton\" [count]=\"1\" [theme]=\"skeletonTheme\" appearance=\"line\"></ui-skeleton>\n </div>\n }\n <div class=\"ui-ist__cell ui-ist__cell--spacer\" role=\"presentation\" aria-hidden=\"true\"></div>\n </div>\n </cdk-virtual-scroll-viewport>\n }\n\n <!-- `showErrorFooter()` and `showErrorState()` differ only on `hasData()`, so they are mutually\n exclusive and safe to merge here. Both fall back to a plain-language message, so a failed fetch is\n never a silent blank box. -->\n @if (showErrorFooter() || showErrorState()) {\n <div class=\"ui-ist__state\" role=\"alert\">\n @if (errorTemplate(); as errorTpl) {\n <ng-container *ngTemplateOutlet=\"errorTpl; context: errorContext\"></ng-container>\n } @else {\n <span>{{ translationContext + 'LOAD_ERROR' | uiTranslate | async }}</span>\n }\n </div>\n }\n\n @if (showEmptyState()) {\n <div class=\"ui-ist__state\">\n @if (noDataTemplate(); as emptyTpl) {\n <ng-container *ngTemplateOutlet=\"emptyTpl\"></ng-container>\n } @else {\n <span>{{ translationContext + 'NO_ROWS' | uiTranslate | async }}</span>\n }\n </div>\n }\n\n <!-- Opt-in, with no fallback (see `endOfListTemplate`). Not role=\"alert\": reaching the end is not an\n alert, and `aria-rowcount` already conveys completeness to assistive tech. -->\n @if (showEndOfList() && endOfListTemplate(); as endTpl) {\n <div class=\"ui-ist__state\">\n <ng-container *ngTemplateOutlet=\"endTpl\"></ng-container>\n </div>\n }\n\n <span class=\"ui-ist__sr-only\" role=\"status\" aria-live=\"polite\">\n @if (statusMessageKey(); as statusKey) {\n {{ statusKey | uiTranslate | async }}\n }\n </span>\n</div>\n", styles: [".bg-teal-60b{background:#1c443c}.bg-teal-30b{background:#31766a}.bg-teal-default{background:#46a997}.bg-teal-30w{background:#7ec3b6}.bg-teal-60w{background:#b5ddd5}.bg-teal-secondary{background:#cbd6cb}.bg-teal-90w{background:#ecf6f5}.bg-petrol-60b{background:#102930}.bg-petrol-30b{background:#1b4754}.bg-petrol-default{background:#276678}.bg-petrol-30w{background:#6894a0}.bg-petrol-60w{background:#a9c2c9}.bg-petrol-secondary{background:#c8d7de}.bg-petrol-90w{background:#e9f0f1}.bg-error-60b{background:#513131}.bg-error-30b{background:#8e5655}.bg-error-60w{background:#e3c3c6}.bg-error-secondary{background:#f0dad9}.bg-error-default{background:#cb7b7a}.bg-warning-secondary{background:#f0d6bb}.bg-warning-default{background:#cca45f}.bg-black{background:#000}.bg-dark{background:#888}.bg-medium{background:#e0e0e0}.bg-grey{background:#ededed}.bg-light{background:#f6f6f6}.bg-white{background:#fff}.bg-box-shadow{background:#00000014}.bg-navigation-subtitle{background:#528593}.bgc-teal-60b{background-color:#1c443c}.bgc-teal-30b{background-color:#31766a}.bgc-teal-default{background-color:#46a997}.bgc-teal-30w{background-color:#7ec3b6}.bgc-teal-60w{background-color:#b5ddd5}.bgc-teal-secondary{background-color:#cbd6cb}.bgc-teal-90w{background-color:#ecf6f5}.bgc-petrol-60b{background-color:#102930}.bgc-petrol-30b{background-color:#1b4754}.bgc-petrol-default{background-color:#276678}.bgc-petrol-30w{background-color:#6894a0}.bgc-petrol-60w{background-color:#a9c2c9}.bgc-petrol-secondary{background-color:#c8d7de}.bgc-petrol-90w{background-color:#e9f0f1}.bgc-error-60b{background-color:#513131}.bgc-error-30b{background-color:#8e5655}.bgc-error-60w{background-color:#e3c3c6}.bgc-error-secondary{background-color:#f0dad9}.bgc-error-default{background-color:#cb7b7a}.bgc-warning-secondary{background-color:#f0d6bb}.bgc-warning-default{background-color:#cca45f}.bgc-black{background-color:#000}.bgc-dark{background-color:#888}.bgc-medium{background-color:#e0e0e0}.bgc-grey{background-color:#ededed}.bgc-light{background-color:#f6f6f6}.bgc-white{background-color:#fff}.bgc-box-shadow{background-color:#00000014}.bgc-navigation-subtitle{background-color:#528593}:host{display:block}.ui-ist{--ui-ist-checkbox-width: 56px;--ui-ist-skeleton-bg: #f4f4f4;display:flex;flex-direction:column;border:1px solid #e0e0e0;border-radius:8px;overflow:hidden;background:#fff}.ui-ist__header{flex:0 0 auto;box-sizing:border-box;overflow:hidden;border-bottom:1px solid #e0e0e0;background:var(--ui-ist-header-bg, #ffffff)}.ui-ist__header-scroll{overflow:hidden}.ui-ist__body{flex:1 1 auto;overflow:auto;scrollbar-width:auto}.ui-ist__body::-webkit-scrollbar{width:8px;height:8px}.ui-ist__body::-webkit-scrollbar-button{display:none}.ui-ist__body::-webkit-scrollbar-thumb{background-color:#00000059;border-radius:4px}.ui-ist__body::-webkit-scrollbar-track:hover{background-color:#00000026}.ui-ist__row{display:flex;width:max-content;min-width:100%;box-sizing:border-box}.ui-ist__row--header{min-height:56px}.ui-ist__row:not(.ui-ist__row--header){border-bottom:1px solid #d3d3d3}.ui-ist__row--clickable{cursor:pointer}.ui-ist__row--clickable:not(.ui-ist__row--selected):hover{background:#fff2fc}.ui-ist__row--clickable:not(.ui-ist__row--selected):hover .ui-ist__cell{background:#fff2fc}.ui-ist__row--selected .ui-ist__cell{background:#f4f4f4}.ui-ist__cell{flex-grow:0;flex-shrink:0;box-sizing:border-box;display:flex;align-items:center;padding:8px 24px;font-size:14px;line-height:20px;overflow:hidden;background:#fff}.ui-ist__cell--header{background:var(--ui-ist-header-bg, #ffffff);font-weight:700;font-size:14px;line-height:16px}.ui-ist__cell--right{justify-content:flex-end;text-align:right}.ui-ist__cell--center{justify-content:center;text-align:center}.ui-ist__cell--sticky-start{position:sticky;z-index:2}.ui-ist__cell--checkbox.ui-ist__cell--sticky-start{left:0}.ui-ist__cell--sticky-end{position:sticky;right:0;z-index:2;order:1}.ui-ist__cell--checkbox{flex:0 0 var(--ui-ist-checkbox-width);min-width:var(--ui-ist-checkbox-width);justify-content:center;padding:0}.ui-ist__cell--spacer{flex:1 1 auto;min-width:0;padding:0}.ui-ist__row--header .ui-ist__cell--spacer{background:var(--ui-ist-header-bg, #ffffff)}.ui-ist__cell-text{overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.ui-ist__skeleton{display:block;width:100%}.ui-ist--scrolled-start .ui-ist__cell--sticky-start-edge{box-shadow:24px 8px 24px #24242414}.ui-ist--scrolled-end .ui-ist__cell--sticky-end{box-shadow:0 8px 24px 4px #24242414}.ui-ist__state{padding:8px 24px;font-size:14px;line-height:20px}.ui-ist--condensed .ui-ist__cell{padding:8px 12px}.ui-ist--condensed .ui-ist__cell:first-child{padding-left:24px}.ui-ist--condensed .ui-ist__cell--sticky-end{padding-right:24px}.ui-ist--condensed .ui-ist__cell--spacer{padding:0}:host(.ui-ist--fill-host){height:100%}.ui-ist--fill-height{height:100%}.ui-ist--fill-height .ui-ist__body{min-height:0}.ui-ist__sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}\n"] }]
656
- }], ctorParameters: () => [], propDecorators: { data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: true }] }], columns: [{ type: i0.Input, args: [{ isSignal: true, alias: "columns", required: true }] }], rowHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowHeight", required: true }] }], trackBy: [{ type: i0.Input, args: [{ isSignal: true, alias: "trackBy", required: false }] }], rowIdKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowIdKey", required: false }] }], minBufferPx: [{ type: i0.Input, args: [{ isSignal: true, alias: "minBufferPx", required: false }] }], maxBufferPx: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxBufferPx", required: false }] }], maxHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxHeight", required: false }] }], fillHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "fillHeight", required: false }] }], isCondensed: [{ type: i0.Input, args: [{ isSignal: true, alias: "isCondensed", required: false }] }], selectable: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectable", required: false }] }], rowsClickable: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowsClickable", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], loadingMore: [{ type: i0.Input, args: [{ isSignal: true, alias: "loadingMore", required: false }] }], hasMore: [{ type: i0.Input, args: [{ isSignal: true, alias: "hasMore", required: true }] }], skeletonRowCount: [{ type: i0.Input, args: [{ isSignal: true, alias: "skeletonRowCount", required: false }] }], loadMoreSkeletonCount: [{ type: i0.Input, args: [{ isSignal: true, alias: "loadMoreSkeletonCount", required: false }] }], loadingColumnCount: [{ type: i0.Input, args: [{ isSignal: true, alias: "loadingColumnCount", required: false }] }], loadMoreThreshold: [{ type: i0.Input, args: [{ isSignal: true, alias: "loadMoreThreshold", required: false }] }], noDataTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "noDataTemplate", required: false }] }], errorTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorTemplate", required: false }] }], error: [{ type: i0.Input, args: [{ isSignal: true, alias: "error", required: false }] }], endOfListTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "endOfListTemplate", required: false }] }], testId: [{ type: i0.Input, args: [{ isSignal: true, alias: "testId", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], loadMore: [{ type: i0.Output, args: ["loadMore"] }], retry: [{ type: i0.Output, args: ["retry"] }], rowClick: [{ type: i0.Output, args: ["rowClick"] }], selectionChange: [{ type: i0.Output, args: ["selectionChange"] }], viewport: [{ type: i0.ViewChild, args: [i0.forwardRef(() => CdkVirtualScrollViewport), { isSignal: true }] }], headerScroll: [{ type: i0.ViewChild, args: ['headerScroll', { isSignal: true }] }] } });
657
-
658
- class InfiniteScrollTableComponentModule {
659
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: InfiniteScrollTableComponentModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
660
- static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.2.25", ngImport: i0, type: InfiniteScrollTableComponentModule, imports: [CommonModule, ScrollingModule, InfiniteScrollTableComponent], exports: [InfiniteScrollTableComponent] }); }
661
- static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: InfiniteScrollTableComponentModule, imports: [CommonModule, ScrollingModule, InfiniteScrollTableComponent] }); }
662
- }
663
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.25", ngImport: i0, type: InfiniteScrollTableComponentModule, decorators: [{
664
- type: NgModule,
665
- args: [{
666
- imports: [CommonModule, ScrollingModule, InfiniteScrollTableComponent],
667
- exports: [InfiniteScrollTableComponent],
668
- }]
669
- }] });
670
-
671
- /**
672
- * Generated bundle index. Do not edit.
673
- */
674
-
13
+ const DEFAULT_COLUMN_WIDTH = "160px";
14
+ const INTERACTIVE_TARGET_SELECTOR = "a, button, input, select, textarea, [role=\"button\"], [tabindex]";
15
+ var InfiniteScrollTableComponent = class InfiniteScrollTableComponent {
16
+ constructor() {
17
+ this.data = input.required(...ngDevMode ? [{ debugName: "data" }] : /* istanbul ignore next */ []);
18
+ this.columns = input.required(...ngDevMode ? [{ debugName: "columns" }] : /* istanbul ignore next */ []);
19
+ this.rowHeight = input.required(...ngDevMode ? [{ debugName: "rowHeight" }] : /* istanbul ignore next */ []);
20
+ this.trackBy = input(...ngDevMode ? [void 0, { debugName: "trackBy" }] : /* istanbul ignore next */ []);
21
+ this.rowIdKey = input(...ngDevMode ? [void 0, { debugName: "rowIdKey" }] : /* istanbul ignore next */ []);
22
+ this.minBufferPx = input(void 0, ...ngDevMode ? [{ debugName: "minBufferPx" }] : /* istanbul ignore next */ []);
23
+ this.maxBufferPx = input(void 0, ...ngDevMode ? [{ debugName: "maxBufferPx" }] : /* istanbul ignore next */ []);
24
+ this.maxHeight = input("70vh", ...ngDevMode ? [{ debugName: "maxHeight" }] : /* istanbul ignore next */ []);
25
+ this.fillHeight = input(false, {
26
+ ...ngDevMode ? { debugName: "fillHeight" } : /* istanbul ignore next */ {},
27
+ transform: booleanAttribute
28
+ });
29
+ this.isCondensed = input(false, {
30
+ ...ngDevMode ? { debugName: "isCondensed" } : /* istanbul ignore next */ {},
31
+ transform: booleanAttribute
32
+ });
33
+ this.selectable = input(false, {
34
+ ...ngDevMode ? { debugName: "selectable" } : /* istanbul ignore next */ {},
35
+ transform: booleanAttribute
36
+ });
37
+ this.rowsClickable = input(false, {
38
+ ...ngDevMode ? { debugName: "rowsClickable" } : /* istanbul ignore next */ {},
39
+ transform: booleanAttribute
40
+ });
41
+ this.loading = input(false, {
42
+ ...ngDevMode ? { debugName: "loading" } : /* istanbul ignore next */ {},
43
+ transform: booleanAttribute
44
+ });
45
+ this.loadingMore = input(false, {
46
+ ...ngDevMode ? { debugName: "loadingMore" } : /* istanbul ignore next */ {},
47
+ transform: booleanAttribute
48
+ });
49
+ this.hasMore = input.required({
50
+ ...ngDevMode ? { debugName: "hasMore" } : /* istanbul ignore next */ {},
51
+ transform: booleanAttribute
52
+ });
53
+ this.skeletonRowCount = input(DEFAULT_FIRST_LOAD_SKELETON_COUNT, ...ngDevMode ? [{ debugName: "skeletonRowCount" }] : /* istanbul ignore next */ []);
54
+ this.loadMoreSkeletonCount = input(DEFAULT_LOAD_MORE_SKELETON_COUNT, ...ngDevMode ? [{ debugName: "loadMoreSkeletonCount" }] : /* istanbul ignore next */ []);
55
+ this.loadingColumnCount = input(0, {
56
+ ...ngDevMode ? { debugName: "loadingColumnCount" } : /* istanbul ignore next */ {},
57
+ transform: numberAttribute
58
+ });
59
+ this.loadMoreThreshold = input(DEFAULT_LOAD_MORE_THRESHOLD, ...ngDevMode ? [{ debugName: "loadMoreThreshold" }] : /* istanbul ignore next */ []);
60
+ this.noDataTemplate = input(...ngDevMode ? [void 0, { debugName: "noDataTemplate" }] : /* istanbul ignore next */ []);
61
+ this.errorTemplate = input(...ngDevMode ? [void 0, { debugName: "errorTemplate" }] : /* istanbul ignore next */ []);
62
+ this.error = input(false, {
63
+ ...ngDevMode ? { debugName: "error" } : /* istanbul ignore next */ {},
64
+ transform: booleanAttribute
65
+ });
66
+ this.endOfListTemplate = input(...ngDevMode ? [void 0, { debugName: "endOfListTemplate" }] : /* istanbul ignore next */ []);
67
+ this.testId = input(null, ...ngDevMode ? [{ debugName: "testId" }] : /* istanbul ignore next */ []);
68
+ this.ariaLabel = input("", ...ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []);
69
+ this.loadMore = output();
70
+ this.retry = output();
71
+ this.rowClick = output();
72
+ this.selectionChange = output();
73
+ this.viewport = viewChild(CdkVirtualScrollViewport, ...ngDevMode ? [{ debugName: "viewport" }] : /* istanbul ignore next */ []);
74
+ this.headerScroll = viewChild("headerScroll", ...ngDevMode ? [{ debugName: "headerScroll" }] : /* istanbul ignore next */ []);
75
+ this.scrollStart = signal(true, ...ngDevMode ? [{ debugName: "scrollStart" }] : /* istanbul ignore next */ []);
76
+ this.scrollEnd = signal(false, ...ngDevMode ? [{ debugName: "scrollEnd" }] : /* istanbul ignore next */ []);
77
+ this.horizontalScroll = signal(false, ...ngDevMode ? [{ debugName: "horizontalScroll" }] : /* istanbul ignore next */ []);
78
+ this.scrollbarWidth = signal(0, ...ngDevMode ? [{ debugName: "scrollbarWidth" }] : /* istanbul ignore next */ []);
79
+ this.hScrollbarHeight = signal(0, ...ngDevMode ? [{ debugName: "hScrollbarHeight" }] : /* istanbul ignore next */ []);
80
+ this.isLoadMoreArmed = true;
81
+ this.dataLengthAtEmit = 0;
82
+ this.wasLoadingMore = false;
83
+ this.lastDataLength = 0;
84
+ this.hasSeenHead = false;
85
+ this.wasLoading = false;
86
+ this.firstVisibleIndex = 0;
87
+ this.skeletonTheme = {
88
+ background: "var(--ui-ist-skeleton-bg)",
89
+ "border-radius": "4px",
90
+ height: "24px",
91
+ "margin-bottom": "0"
92
+ };
93
+ this.stickyStartKey = computed(() => {
94
+ const columns = this.columns();
95
+ return columns[0]?.isSticky ? columns[0].key : void 0;
96
+ }, ...ngDevMode ? [{ debugName: "stickyStartKey" }] : /* istanbul ignore next */ []);
97
+ this.stickyEndKey = computed(() => {
98
+ const columns = this.columns();
99
+ const lastIndex = columns.length - 1;
100
+ return lastIndex > 0 && columns[lastIndex]?.isSticky ? columns[lastIndex].key : void 0;
101
+ }, ...ngDevMode ? [{ debugName: "stickyEndKey" }] : /* istanbul ignore next */ []);
102
+ this.defaultColumnWidth = DEFAULT_COLUMN_WIDTH;
103
+ this.effectiveMinBufferPx = computed(() => this.minBufferPx() ?? this.rowHeight() * 5, ...ngDevMode ? [{ debugName: "effectiveMinBufferPx" }] : /* istanbul ignore next */ []);
104
+ this.effectiveMaxBufferPx = computed(() => Math.max(this.maxBufferPx() ?? this.rowHeight() * 10, this.effectiveMinBufferPx()), ...ngDevMode ? [{ debugName: "effectiveMaxBufferPx" }] : /* istanbul ignore next */ []);
105
+ this.loadingColumns = computed(() => Array.from({ length: Math.max(0, this.loadingColumnCount()) }, (_, index) => `loading-column-${index}`), ...ngDevMode ? [{ debugName: "loadingColumns" }] : /* istanbul ignore next */ []);
106
+ this.renderRows = computed(() => {
107
+ if (this.loading()) return Array.from({ length: Math.max(1, this.skeletonRowCount()) }, (_, i) => ({
108
+ kind: "skeleton",
109
+ id: `skeleton-first-${i}`
110
+ }));
111
+ const rows = this.data().map((item, index) => ({
112
+ kind: "data",
113
+ item,
114
+ index
115
+ }));
116
+ if (this.loadingMore() && this.hasMore()) for (let i = 0; i < Math.max(1, this.loadMoreSkeletonCount()); i++) rows.push({
117
+ kind: "skeleton",
118
+ id: `skeleton-more-${i}`
119
+ });
120
+ return rows;
121
+ }, ...ngDevMode ? [{ debugName: "renderRows" }] : /* istanbul ignore next */ []);
122
+ this.hasData = computed(() => this.data().length > 0, ...ngDevMode ? [{ debugName: "hasData" }] : /* istanbul ignore next */ []);
123
+ this.showViewport = computed(() => this.loading() || this.hasData(), ...ngDevMode ? [{ debugName: "showViewport" }] : /* istanbul ignore next */ []);
124
+ this.showEmptyState = computed(() => !this.loading() && !this.loadingMore() && !this.error() && !this.hasData(), ...ngDevMode ? [{ debugName: "showEmptyState" }] : /* istanbul ignore next */ []);
125
+ this.showErrorState = computed(() => !this.loading() && this.error() && !this.hasData(), ...ngDevMode ? [{ debugName: "showErrorState" }] : /* istanbul ignore next */ []);
126
+ this.showErrorFooter = computed(() => !this.loading() && this.error() && this.hasData(), ...ngDevMode ? [{ debugName: "showErrorFooter" }] : /* istanbul ignore next */ []);
127
+ this.showEndOfList = computed(() => this.hasData() && !this.hasMore() && !this.loading() && !this.loadingMore() && !this.error(), ...ngDevMode ? [{ debugName: "showEndOfList" }] : /* istanbul ignore next */ []);
128
+ this.viewportHeight = computed(() => {
129
+ if (this.fillHeight()) return null;
130
+ return `min(${this.renderRows().length * this.rowHeight() + (this.horizontalScroll() ? this.hScrollbarHeight() : 0)}px, ${this.maxHeight()})`;
131
+ }, ...ngDevMode ? [{ debugName: "viewportHeight" }] : /* istanbul ignore next */ []);
132
+ this.translationContext = "INFINITE_SCROLL_TABLE.";
133
+ this.statusMessageKey = computed(() => {
134
+ if (this.loading()) return `${this.translationContext}LOADING`;
135
+ if (this.loadingMore()) return `${this.translationContext}LOADING_MORE`;
136
+ return "";
137
+ }, ...ngDevMode ? [{ debugName: "statusMessageKey" }] : /* istanbul ignore next */ []);
138
+ this.errorContext = {
139
+ $implicit: () => this.emitRetry(),
140
+ retry: () => this.emitRetry()
141
+ };
142
+ this.renderRowTrackBy = (index, row) => {
143
+ if (row.kind === "skeleton") return row.id;
144
+ return this.rowIdentity(row.item, row.index);
145
+ };
146
+ effect((onCleanup) => {
147
+ const viewport = this.viewport();
148
+ if (!viewport) return;
149
+ untracked(() => {
150
+ this.firstVisibleIndex = 0;
151
+ const element = viewport.elementRef.nativeElement;
152
+ element.querySelector(".cdk-virtual-scroll-content-wrapper")?.setAttribute("role", "presentation");
153
+ element.querySelector(".cdk-virtual-scroll-spacer")?.setAttribute("aria-hidden", "true");
154
+ const subscription = new Subscription();
155
+ subscription.add(viewport.elementScrolled().pipe(auditTime(0, animationFrameScheduler)).subscribe(() => this.syncHorizontalScroll()));
156
+ subscription.add(viewport.renderedRangeStream.subscribe(() => this.checkLoadMore()));
157
+ subscription.add(viewport.scrolledIndexChange.subscribe((index) => {
158
+ this.firstVisibleIndex = index;
159
+ this.checkLoadMore();
160
+ }));
161
+ const measureScrollbar = () => {
162
+ this.scrollbarWidth.set(element.offsetWidth - element.clientWidth);
163
+ this.hScrollbarHeight.set(element.offsetHeight - element.clientHeight);
164
+ };
165
+ subscription.add(viewport.renderedRangeStream.subscribe(() => measureScrollbar()));
166
+ let resizeObserver;
167
+ if (typeof ResizeObserver !== "undefined") {
168
+ resizeObserver = new ResizeObserver(() => {
169
+ measureScrollbar();
170
+ this.syncHorizontalScroll();
171
+ this.scheduleViewportRemeasure();
172
+ });
173
+ resizeObserver.observe(element);
174
+ }
175
+ measureScrollbar();
176
+ this.syncHorizontalScroll();
177
+ this.checkLoadMore();
178
+ let scrollSyncFrame;
179
+ if (typeof requestAnimationFrame !== "undefined") scrollSyncFrame = requestAnimationFrame(() => this.syncHorizontalScroll());
180
+ onCleanup(() => {
181
+ subscription.unsubscribe();
182
+ resizeObserver?.disconnect();
183
+ if (scrollSyncFrame !== void 0) cancelAnimationFrame(scrollSyncFrame);
184
+ if (this.remeasureFrame !== void 0) {
185
+ cancelAnimationFrame(this.remeasureFrame);
186
+ this.remeasureFrame = void 0;
187
+ }
188
+ });
189
+ });
190
+ });
191
+ effect(() => {
192
+ this.renderRows();
193
+ this.rowHeight();
194
+ this.maxHeight();
195
+ this.columns();
196
+ this.fillHeight();
197
+ this.loadingColumnCount();
198
+ this.selectable();
199
+ this.scheduleViewportRemeasure();
200
+ });
201
+ effect(() => {
202
+ this.data();
203
+ untracked(() => this.rearmLoadMoreIfUnreachable());
204
+ });
205
+ effect(() => {
206
+ if (isDevMode() && this.selectable() && !this.trackBy() && !this.rowIdKey()) console.warn("[ui-infinite-scroll-table] `selectable` is enabled without `trackBy` or `rowIdKey`. Row identity falls back to the data index, so selection can attach to the wrong row when rows are reordered or prepended. Provide `trackBy` or `rowIdKey` for stable identity.");
207
+ });
208
+ effect(() => {
209
+ if (!isDevMode()) return;
210
+ const columns = this.columns();
211
+ const lastIndex = columns.length - 1;
212
+ const ignored = columns.filter((column, index) => column.isSticky && index !== 0 && index !== lastIndex).map((column) => column.key);
213
+ if (ignored.length > 0) console.warn(`[ui-infinite-scroll-table] \`isSticky\` is only honoured on the first and last column. Ignoring it on: ${ignored.join(", ")}.`);
214
+ });
215
+ effect(() => {
216
+ const loadingMore = this.loadingMore();
217
+ const data = this.data();
218
+ const completedFetch = this.wasLoadingMore && !loadingMore;
219
+ const sameReference = this.lastDataReference === data;
220
+ const grew = data.length > this.lastDataLength;
221
+ this.wasLoadingMore = loadingMore;
222
+ this.lastDataReference = data;
223
+ this.lastDataLength = data.length;
224
+ if (isDevMode() && completedFetch && sameReference && grew) console.warn("[ui-infinite-scroll-table] `loadingMore` completed without `data` changing reference. Append pages with a new array (`[...rows, ...page]`) — a signal input cannot observe an in-place `push`, so the new rows will not render and `loadMore` will not fire again.");
225
+ });
226
+ effect((onCleanup) => {
227
+ onCleanup(() => this.cancelResetScrollFrame());
228
+ const data = this.data();
229
+ const loading = this.loading();
230
+ const startedLoading = loading && !this.wasLoading;
231
+ this.wasLoading = loading;
232
+ const headIdentity = data.length > 0 ? untracked(() => this.rowIdentity(data[0], 0)) : void 0;
233
+ const replaced = this.hasSeenHead && data.length > 0 && headIdentity !== this.previousHeadIdentity;
234
+ this.previousHeadIdentity = headIdentity;
235
+ this.hasSeenHead = this.hasSeenHead || data.length > 0;
236
+ if (!startedLoading && !replaced) {
237
+ this.firstVisibleIndex = Math.min(this.firstVisibleIndex, Math.max(0, data.length - 1));
238
+ return;
239
+ }
240
+ this.firstVisibleIndex = 0;
241
+ if (typeof requestAnimationFrame === "undefined") {
242
+ untracked(() => this.scrollToTop());
243
+ return;
244
+ }
245
+ this.cancelResetScrollFrame();
246
+ this.resetScrollFrame = requestAnimationFrame(() => {
247
+ this.resetScrollFrame = void 0;
248
+ untracked(() => this.scrollToTop());
249
+ });
250
+ });
251
+ }
252
+ cancelResetScrollFrame() {
253
+ if (this.resetScrollFrame !== void 0) {
254
+ cancelAnimationFrame(this.resetScrollFrame);
255
+ this.resetScrollFrame = void 0;
256
+ }
257
+ }
258
+ scrollToIndex(index, behavior = "auto") {
259
+ this.viewport()?.scrollToIndex(index, behavior);
260
+ }
261
+ scrollToTop(behavior = "auto") {
262
+ this.viewport()?.scrollToIndex(0, behavior);
263
+ }
264
+ asRowLike(item) {
265
+ return item;
266
+ }
267
+ getCellValue(item, key) {
268
+ return this.asRowLike(item)[key];
269
+ }
270
+ columnWidth(column) {
271
+ return column.styles?.width ?? DEFAULT_COLUMN_WIDTH;
272
+ }
273
+ emitRowClick(event, row) {
274
+ if (!this.rowsClickable() || row.kind !== "data") return;
275
+ if (this.isInteractiveTarget(event) || this.hasTextSelection()) return;
276
+ this.rowClick.emit({
277
+ row: row.item,
278
+ index: row.index
279
+ });
280
+ }
281
+ rowTestId(row) {
282
+ const testId = this.testId();
283
+ return testId && row.kind === "data" ? `${testId}-row-${row.index}` : null;
284
+ }
285
+ cellTestId(row, columnKey) {
286
+ const testId = this.testId();
287
+ return testId && row.kind === "data" ? `${testId}-cell-${row.index}-${columnKey}` : null;
288
+ }
289
+ rowCheckboxTestId(row) {
290
+ const rowTestId = this.rowTestId(row);
291
+ return rowTestId ? `${rowTestId}-select` : null;
292
+ }
293
+ isRowSelected(row) {
294
+ return this.selectable() && row.kind === "data" && Boolean(this.asRowLike(row.item).selected);
295
+ }
296
+ emitSelectionChange(row, selected) {
297
+ if (row.kind !== "data") return;
298
+ this.selectionChange.emit({
299
+ row: row.item,
300
+ index: row.index,
301
+ selected
302
+ });
303
+ }
304
+ stickyStartLeft(column) {
305
+ if (column.key !== this.stickyStartKey()) return null;
306
+ return this.selectable() ? "var(--ui-ist-checkbox-width)" : "0px";
307
+ }
308
+ isStickyStartEdge(column) {
309
+ return column.key === this.stickyStartKey();
310
+ }
311
+ activateRow(event, row) {
312
+ if (!this.rowsClickable() || row.kind !== "data") return;
313
+ if (this.isInteractiveTarget(event)) return;
314
+ event.preventDefault();
315
+ this.rowClick.emit({
316
+ row: row.item,
317
+ index: row.index
318
+ });
319
+ }
320
+ isInteractiveTarget(event) {
321
+ const target = event.target;
322
+ if (!(target instanceof Element)) return false;
323
+ const interactive = target.closest(INTERACTIVE_TARGET_SELECTOR);
324
+ return interactive !== null && interactive !== event.currentTarget;
325
+ }
326
+ hasTextSelection() {
327
+ const selection = typeof window !== "undefined" ? window.getSelection() : null;
328
+ return Boolean(selection && !selection.isCollapsed && selection.toString().length > 0);
329
+ }
330
+ scheduleViewportRemeasure() {
331
+ if (typeof requestAnimationFrame === "undefined") {
332
+ this.viewport()?.checkViewportSize();
333
+ this.settleLoadMore();
334
+ return;
335
+ }
336
+ if (this.remeasureFrame !== void 0) cancelAnimationFrame(this.remeasureFrame);
337
+ this.remeasureFrame = requestAnimationFrame(() => {
338
+ this.remeasureFrame = void 0;
339
+ this.viewport()?.checkViewportSize();
340
+ this.syncHorizontalScroll();
341
+ this.settleLoadMore();
342
+ });
343
+ }
344
+ settleLoadMore() {
345
+ this.rearmLoadMoreIfUnreachable();
346
+ this.checkLoadMore();
347
+ }
348
+ emitRetry() {
349
+ this.retry.emit();
350
+ }
351
+ rowIdentity(item, index) {
352
+ const explicitTrackBy = this.trackBy();
353
+ if (explicitTrackBy) return explicitTrackBy(index, item);
354
+ const key = this.rowIdKey();
355
+ return key ? this.asRowLike(item)[key] : index;
356
+ }
357
+ syncHorizontalScroll() {
358
+ const viewport = this.viewport();
359
+ if (!viewport) return;
360
+ const left = viewport.measureScrollOffset("left");
361
+ const right = viewport.measureScrollOffset("right");
362
+ const header = this.headerScroll();
363
+ if (header) header.nativeElement.scrollLeft = Math.round(left);
364
+ this.scrollStart.set(left <= 1);
365
+ this.scrollEnd.set(right <= 1);
366
+ this.horizontalScroll.set(left + right > 1);
367
+ }
368
+ visibleRowCount() {
369
+ return Math.ceil((this.viewport()?.getViewportSize() ?? 0) / this.rowHeight());
370
+ }
371
+ triggerZoneRows(visibleRows) {
372
+ const threshold = Math.max(0, this.loadMoreThreshold());
373
+ return visibleRows > 0 ? Math.min(threshold, visibleRows) : threshold;
374
+ }
375
+ isInTriggerZone(dataLength, visibleRows) {
376
+ return this.firstVisibleIndex + visibleRows >= dataLength - this.triggerZoneRows(visibleRows);
377
+ }
378
+ rearmLoadMoreIfUnreachable() {
379
+ const dataLength = this.data().length;
380
+ const visibleRows = this.visibleRowCount();
381
+ if (dataLength > this.dataLengthAtEmit) {
382
+ this.isLoadMoreArmed = true;
383
+ return;
384
+ }
385
+ if (visibleRows === 0 || visibleRows >= dataLength - this.triggerZoneRows(visibleRows)) this.isLoadMoreArmed = true;
386
+ }
387
+ checkLoadMore() {
388
+ if (!this.viewport() || !this.hasMore() || this.loading() || this.loadingMore() || this.error()) return;
389
+ const dataLength = this.data().length;
390
+ if (dataLength === 0) return;
391
+ if (!this.isInTriggerZone(dataLength, this.visibleRowCount())) {
392
+ this.isLoadMoreArmed = true;
393
+ return;
394
+ }
395
+ if (this.isLoadMoreArmed) {
396
+ this.isLoadMoreArmed = false;
397
+ this.dataLengthAtEmit = dataLength;
398
+ this.loadMore.emit();
399
+ }
400
+ }
401
+ static {
402
+ this.ɵfac = i0.ɵɵngDeclareFactory({
403
+ minVersion: "12.0.0",
404
+ version: "22.2.4",
405
+ ngImport: i0,
406
+ type: InfiniteScrollTableComponent,
407
+ deps: [],
408
+ target: i0.ɵɵFactoryTarget.Component
409
+ });
410
+ }
411
+ static {
412
+ this.ɵcmp = i0.ɵɵngDeclareComponent({
413
+ minVersion: "17.0.0",
414
+ version: "22.2.4",
415
+ type: InfiniteScrollTableComponent,
416
+ isStandalone: true,
417
+ selector: "ui-infinite-scroll-table",
418
+ inputs: {
419
+ data: {
420
+ classPropertyName: "data",
421
+ publicName: "data",
422
+ isSignal: true,
423
+ isRequired: true,
424
+ transformFunction: null
425
+ },
426
+ columns: {
427
+ classPropertyName: "columns",
428
+ publicName: "columns",
429
+ isSignal: true,
430
+ isRequired: true,
431
+ transformFunction: null
432
+ },
433
+ rowHeight: {
434
+ classPropertyName: "rowHeight",
435
+ publicName: "rowHeight",
436
+ isSignal: true,
437
+ isRequired: true,
438
+ transformFunction: null
439
+ },
440
+ trackBy: {
441
+ classPropertyName: "trackBy",
442
+ publicName: "trackBy",
443
+ isSignal: true,
444
+ isRequired: false,
445
+ transformFunction: null
446
+ },
447
+ rowIdKey: {
448
+ classPropertyName: "rowIdKey",
449
+ publicName: "rowIdKey",
450
+ isSignal: true,
451
+ isRequired: false,
452
+ transformFunction: null
453
+ },
454
+ minBufferPx: {
455
+ classPropertyName: "minBufferPx",
456
+ publicName: "minBufferPx",
457
+ isSignal: true,
458
+ isRequired: false,
459
+ transformFunction: null
460
+ },
461
+ maxBufferPx: {
462
+ classPropertyName: "maxBufferPx",
463
+ publicName: "maxBufferPx",
464
+ isSignal: true,
465
+ isRequired: false,
466
+ transformFunction: null
467
+ },
468
+ maxHeight: {
469
+ classPropertyName: "maxHeight",
470
+ publicName: "maxHeight",
471
+ isSignal: true,
472
+ isRequired: false,
473
+ transformFunction: null
474
+ },
475
+ fillHeight: {
476
+ classPropertyName: "fillHeight",
477
+ publicName: "fillHeight",
478
+ isSignal: true,
479
+ isRequired: false,
480
+ transformFunction: null
481
+ },
482
+ isCondensed: {
483
+ classPropertyName: "isCondensed",
484
+ publicName: "isCondensed",
485
+ isSignal: true,
486
+ isRequired: false,
487
+ transformFunction: null
488
+ },
489
+ selectable: {
490
+ classPropertyName: "selectable",
491
+ publicName: "selectable",
492
+ isSignal: true,
493
+ isRequired: false,
494
+ transformFunction: null
495
+ },
496
+ rowsClickable: {
497
+ classPropertyName: "rowsClickable",
498
+ publicName: "rowsClickable",
499
+ isSignal: true,
500
+ isRequired: false,
501
+ transformFunction: null
502
+ },
503
+ loading: {
504
+ classPropertyName: "loading",
505
+ publicName: "loading",
506
+ isSignal: true,
507
+ isRequired: false,
508
+ transformFunction: null
509
+ },
510
+ loadingMore: {
511
+ classPropertyName: "loadingMore",
512
+ publicName: "loadingMore",
513
+ isSignal: true,
514
+ isRequired: false,
515
+ transformFunction: null
516
+ },
517
+ hasMore: {
518
+ classPropertyName: "hasMore",
519
+ publicName: "hasMore",
520
+ isSignal: true,
521
+ isRequired: true,
522
+ transformFunction: null
523
+ },
524
+ skeletonRowCount: {
525
+ classPropertyName: "skeletonRowCount",
526
+ publicName: "skeletonRowCount",
527
+ isSignal: true,
528
+ isRequired: false,
529
+ transformFunction: null
530
+ },
531
+ loadMoreSkeletonCount: {
532
+ classPropertyName: "loadMoreSkeletonCount",
533
+ publicName: "loadMoreSkeletonCount",
534
+ isSignal: true,
535
+ isRequired: false,
536
+ transformFunction: null
537
+ },
538
+ loadingColumnCount: {
539
+ classPropertyName: "loadingColumnCount",
540
+ publicName: "loadingColumnCount",
541
+ isSignal: true,
542
+ isRequired: false,
543
+ transformFunction: null
544
+ },
545
+ loadMoreThreshold: {
546
+ classPropertyName: "loadMoreThreshold",
547
+ publicName: "loadMoreThreshold",
548
+ isSignal: true,
549
+ isRequired: false,
550
+ transformFunction: null
551
+ },
552
+ noDataTemplate: {
553
+ classPropertyName: "noDataTemplate",
554
+ publicName: "noDataTemplate",
555
+ isSignal: true,
556
+ isRequired: false,
557
+ transformFunction: null
558
+ },
559
+ errorTemplate: {
560
+ classPropertyName: "errorTemplate",
561
+ publicName: "errorTemplate",
562
+ isSignal: true,
563
+ isRequired: false,
564
+ transformFunction: null
565
+ },
566
+ error: {
567
+ classPropertyName: "error",
568
+ publicName: "error",
569
+ isSignal: true,
570
+ isRequired: false,
571
+ transformFunction: null
572
+ },
573
+ endOfListTemplate: {
574
+ classPropertyName: "endOfListTemplate",
575
+ publicName: "endOfListTemplate",
576
+ isSignal: true,
577
+ isRequired: false,
578
+ transformFunction: null
579
+ },
580
+ testId: {
581
+ classPropertyName: "testId",
582
+ publicName: "testId",
583
+ isSignal: true,
584
+ isRequired: false,
585
+ transformFunction: null
586
+ },
587
+ ariaLabel: {
588
+ classPropertyName: "ariaLabel",
589
+ publicName: "ariaLabel",
590
+ isSignal: true,
591
+ isRequired: false,
592
+ transformFunction: null
593
+ }
594
+ },
595
+ outputs: {
596
+ loadMore: "loadMore",
597
+ retry: "retry",
598
+ rowClick: "rowClick",
599
+ selectionChange: "selectionChange"
600
+ },
601
+ host: { properties: { "class.ui-ist--fill-host": "fillHeight()" } },
602
+ viewQueries: [{
603
+ propertyName: "viewport",
604
+ first: true,
605
+ predicate: CdkVirtualScrollViewport,
606
+ descendants: true,
607
+ isSignal: true
608
+ }, {
609
+ propertyName: "headerScroll",
610
+ first: true,
611
+ predicate: ["headerScroll"],
612
+ descendants: true,
613
+ isSignal: true
614
+ }],
615
+ ngImport: i0,
616
+ template: "<!-- role=\"table\", not \"grid\": row access is Tab-only with no arrow-key cell traversal, so \"grid\" would\n promise 2D keyboard navigation this does not implement. Selection is conveyed by the row's checkbox,\n not `aria-selected` — which is valid only on grid/treegrid anyway. -->\n<div\n class=\"ui-ist\"\n role=\"table\"\n [class.ui-ist--condensed]=\"isCondensed()\"\n [class.ui-ist--scrolled-start]=\"!scrollStart()\"\n [class.ui-ist--scrolled-end]=\"horizontalScroll() && !scrollEnd()\"\n [class.ui-ist--fill-height]=\"fillHeight()\"\n [attr.aria-rowcount]=\"hasMore() ? -1 : data().length + 1\"\n [attr.aria-busy]=\"loading() || loadingMore()\"\n [attr.aria-label]=\"ariaLabel() || null\"\n [attr.data-testid]=\"testId()\"\n>\n <!-- Pinned header, outside the viewport so it never scrolls vertically. The outer element reserves the\n body's scrollbar width as padding (keeping the background and border across that strip); the inner\n one carries the horizontal scrollLeft synced from the body. -->\n <div class=\"ui-ist__header\" [style.padding-right.px]=\"scrollbarWidth()\" role=\"presentation\">\n <div #headerScroll class=\"ui-ist__header-scroll\" role=\"presentation\">\n <div class=\"ui-ist__row ui-ist__row--header\" role=\"row\" aria-rowindex=\"1\">\n @if (selectable()) {\n <div\n class=\"ui-ist__cell ui-ist__cell--header ui-ist__cell--checkbox ui-ist__cell--sticky-start\"\n [class.ui-ist__cell--sticky-start-edge]=\"!stickyStartKey()\"\n role=\"columnheader\"\n ></div>\n }\n @for (column of columns(); track column.key; let colIndex = $index) {\n <div\n class=\"ui-ist__cell ui-ist__cell--header\"\n role=\"columnheader\"\n [class.ui-ist__cell--sticky-start]=\"column.key === stickyStartKey()\"\n [class.ui-ist__cell--sticky-start-edge]=\"isStickyStartEdge(column)\"\n [class.ui-ist__cell--sticky-end]=\"column.key === stickyEndKey()\"\n [class.ui-ist__cell--right]=\"column.styles?.alignment === 'right'\"\n [class.ui-ist__cell--center]=\"column.styles?.alignment === 'center'\"\n [style.flex-basis]=\"columnWidth(column)\"\n [style.min-width]=\"columnWidth(column)\"\n [style.max-width]=\"columnWidth(column)\"\n [style.left]=\"stickyStartLeft(column)\"\n >\n @if (column.headerCellTemplate) {\n <ng-container\n *ngTemplateOutlet=\"column.headerCellTemplate; context: { $implicit: column.title, column, colIndex }\"\n ></ng-container>\n } @else {\n <span class=\"ui-ist__cell-text\">{{ column.title }}</span>\n }\n </div>\n }\n @for (loadingKey of loadingColumns(); track loadingKey) {\n <div\n class=\"ui-ist__cell ui-ist__cell--header ui-ist__cell--loading\"\n role=\"presentation\"\n aria-hidden=\"true\"\n [style.flex-basis]=\"defaultColumnWidth\"\n [style.min-width]=\"defaultColumnWidth\"\n [style.max-width]=\"defaultColumnWidth\"\n >\n <ui-skeleton class=\"ui-ist__skeleton\" [count]=\"1\" [theme]=\"skeletonTheme\" appearance=\"line\"></ui-skeleton>\n </div>\n }\n <div class=\"ui-ist__cell ui-ist__cell--spacer\" role=\"presentation\" aria-hidden=\"true\"></div>\n </div>\n </div>\n </div>\n\n <!-- The CDK viewport owns BOTH vertical (virtualized) and horizontal scroll, so sticky columns pin\n against it and the horizontal scrollbar sits at the viewport bottom. -->\n @if (showViewport()) {\n <cdk-virtual-scroll-viewport\n class=\"ui-ist__body\"\n role=\"rowgroup\"\n [itemSize]=\"rowHeight()\"\n [minBufferPx]=\"effectiveMinBufferPx()\"\n [maxBufferPx]=\"effectiveMaxBufferPx()\"\n [style.height]=\"viewportHeight()\"\n [style.max-height]=\"fillHeight() ? maxHeight() : null\"\n >\n <div\n *cdkVirtualFor=\"let row of renderRows(); let rowIndex = index; trackBy: renderRowTrackBy\"\n class=\"ui-ist__row\"\n role=\"row\"\n [class.ui-ist__row--clickable]=\"rowsClickable() && row.kind === 'data'\"\n [class.ui-ist__row--selected]=\"isRowSelected(row)\"\n [attr.aria-rowindex]=\"row.kind === 'data' ? row.index + 2 : null\"\n [attr.aria-hidden]=\"row.kind === 'skeleton' ? true : null\"\n [attr.tabindex]=\"rowsClickable() && row.kind === 'data' ? 0 : null\"\n [style.height.px]=\"rowHeight()\"\n [attr.data-testid]=\"rowTestId(row)\"\n (click)=\"emitRowClick($event, row)\"\n (keydown.enter)=\"activateRow($event, row)\"\n (keydown.space)=\"activateRow($event, row)\"\n >\n @if (selectable()) {\n <!-- This `stopPropagation` is what actually stops a checkbox click activating the row: it runs\n before the click reaches the row's listener, so `isInteractiveTarget` is never consulted on\n this path. That guard is a real second line of defence (`ui-checkbox` renders a focusable\n wrapper and a native input, both matching INTERACTIVE_TARGET_SELECTOR), not a substitute. -->\n <div\n class=\"ui-ist__cell ui-ist__cell--checkbox ui-ist__cell--sticky-start\"\n [class.ui-ist__cell--sticky-start-edge]=\"!stickyStartKey()\"\n role=\"cell\"\n (click)=\"$event.stopPropagation()\"\n (keydown)=\"$event.stopPropagation()\"\n >\n @if (row.kind === 'data') {\n <ui-checkbox\n [checked]=\"isRowSelected(row)\"\n [ariaLabel]=\"'Select row ' + (row.index + 1)\"\n [testId]=\"rowCheckboxTestId(row)\"\n (changed)=\"emitSelectionChange(row, $event)\"\n ></ui-checkbox>\n }\n </div>\n }\n @for (column of columns(); track column.key) {\n <div\n class=\"ui-ist__cell\"\n role=\"cell\"\n [class.ui-ist__cell--sticky-start]=\"column.key === stickyStartKey()\"\n [class.ui-ist__cell--sticky-start-edge]=\"isStickyStartEdge(column)\"\n [class.ui-ist__cell--sticky-end]=\"column.key === stickyEndKey()\"\n [class.ui-ist__cell--right]=\"column.styles?.alignment === 'right'\"\n [class.ui-ist__cell--center]=\"column.styles?.alignment === 'center'\"\n [style.flex-basis]=\"columnWidth(column)\"\n [style.min-width]=\"columnWidth(column)\"\n [style.max-width]=\"columnWidth(column)\"\n [style.left]=\"stickyStartLeft(column)\"\n [attr.data-testid]=\"cellTestId(row, column.key)\"\n >\n @if (row.kind === 'skeleton') {\n <ui-skeleton class=\"ui-ist__skeleton\" [count]=\"1\" [theme]=\"skeletonTheme\" appearance=\"line\"></ui-skeleton>\n } @else if (column.rowCellTemplate) {\n <ng-container\n *ngTemplateOutlet=\"column.rowCellTemplate; context: { $implicit: row.item, rowIndex: row.index }\"\n ></ng-container>\n } @else {\n <span class=\"ui-ist__cell-text\">{{ getCellValue(row.item, column.key) }}</span>\n }\n </div>\n }\n @for (loadingKey of loadingColumns(); track loadingKey) {\n <div\n class=\"ui-ist__cell ui-ist__cell--loading\"\n role=\"presentation\"\n aria-hidden=\"true\"\n [style.flex-basis]=\"defaultColumnWidth\"\n [style.min-width]=\"defaultColumnWidth\"\n [style.max-width]=\"defaultColumnWidth\"\n >\n <ui-skeleton class=\"ui-ist__skeleton\" [count]=\"1\" [theme]=\"skeletonTheme\" appearance=\"line\"></ui-skeleton>\n </div>\n }\n <div class=\"ui-ist__cell ui-ist__cell--spacer\" role=\"presentation\" aria-hidden=\"true\"></div>\n </div>\n </cdk-virtual-scroll-viewport>\n }\n\n <!-- `showErrorFooter()` and `showErrorState()` differ only on `hasData()`, so they are mutually\n exclusive and safe to merge here. Both fall back to a plain-language message, so a failed fetch is\n never a silent blank box. -->\n @if (showErrorFooter() || showErrorState()) {\n <div class=\"ui-ist__state\" role=\"alert\">\n @if (errorTemplate(); as errorTpl) {\n <ng-container *ngTemplateOutlet=\"errorTpl; context: errorContext\"></ng-container>\n } @else {\n <span>{{ translationContext + 'LOAD_ERROR' | uiTranslate | async }}</span>\n }\n </div>\n }\n\n @if (showEmptyState()) {\n <div class=\"ui-ist__state\">\n @if (noDataTemplate(); as emptyTpl) {\n <ng-container *ngTemplateOutlet=\"emptyTpl\"></ng-container>\n } @else {\n <span>{{ translationContext + 'NO_ROWS' | uiTranslate | async }}</span>\n }\n </div>\n }\n\n <!-- Opt-in, with no fallback (see `endOfListTemplate`). Not role=\"alert\": reaching the end is not an\n alert, and `aria-rowcount` already conveys completeness to assistive tech. -->\n @if (showEndOfList() && endOfListTemplate(); as endTpl) {\n <div class=\"ui-ist__state\">\n <ng-container *ngTemplateOutlet=\"endTpl\"></ng-container>\n </div>\n }\n\n <span class=\"ui-ist__sr-only\" role=\"status\" aria-live=\"polite\">\n @if (statusMessageKey(); as statusKey) {\n {{ statusKey | uiTranslate | async }}\n }\n </span>\n</div>\n",
617
+ styles: [".bg-teal-60b{background:#1c443c}.bg-teal-30b{background:#31766a}.bg-teal-default{background:#46a997}.bg-teal-30w{background:#7ec3b6}.bg-teal-60w{background:#b5ddd5}.bg-teal-secondary{background:#cbd6cb}.bg-teal-90w{background:#ecf6f5}.bg-petrol-60b{background:#102930}.bg-petrol-30b{background:#1b4754}.bg-petrol-default{background:#276678}.bg-petrol-30w{background:#6894a0}.bg-petrol-60w{background:#a9c2c9}.bg-petrol-secondary{background:#c8d7de}.bg-petrol-90w{background:#e9f0f1}.bg-error-60b{background:#513131}.bg-error-30b{background:#8e5655}.bg-error-60w{background:#e3c3c6}.bg-error-secondary{background:#f0dad9}.bg-error-default{background:#cb7b7a}.bg-warning-secondary{background:#f0d6bb}.bg-warning-default{background:#cca45f}.bg-black{background:#000}.bg-dark{background:#888}.bg-medium{background:#e0e0e0}.bg-grey{background:#ededed}.bg-light{background:#f6f6f6}.bg-white{background:#fff}.bg-box-shadow{background:#00000014}.bg-navigation-subtitle{background:#528593}.bgc-teal-60b{background-color:#1c443c}.bgc-teal-30b{background-color:#31766a}.bgc-teal-default{background-color:#46a997}.bgc-teal-30w{background-color:#7ec3b6}.bgc-teal-60w{background-color:#b5ddd5}.bgc-teal-secondary{background-color:#cbd6cb}.bgc-teal-90w{background-color:#ecf6f5}.bgc-petrol-60b{background-color:#102930}.bgc-petrol-30b{background-color:#1b4754}.bgc-petrol-default{background-color:#276678}.bgc-petrol-30w{background-color:#6894a0}.bgc-petrol-60w{background-color:#a9c2c9}.bgc-petrol-secondary{background-color:#c8d7de}.bgc-petrol-90w{background-color:#e9f0f1}.bgc-error-60b{background-color:#513131}.bgc-error-30b{background-color:#8e5655}.bgc-error-60w{background-color:#e3c3c6}.bgc-error-secondary{background-color:#f0dad9}.bgc-error-default{background-color:#cb7b7a}.bgc-warning-secondary{background-color:#f0d6bb}.bgc-warning-default{background-color:#cca45f}.bgc-black{background-color:#000}.bgc-dark{background-color:#888}.bgc-medium{background-color:#e0e0e0}.bgc-grey{background-color:#ededed}.bgc-light{background-color:#f6f6f6}.bgc-white{background-color:#fff}.bgc-box-shadow{background-color:#00000014}.bgc-navigation-subtitle{background-color:#528593}:host{display:block}.ui-ist{--ui-ist-checkbox-width: 56px;--ui-ist-skeleton-bg: #f4f4f4;display:flex;flex-direction:column;border:1px solid #e0e0e0;border-radius:8px;overflow:hidden;background:#fff}.ui-ist__header{flex:0 0 auto;box-sizing:border-box;overflow:hidden;border-bottom:1px solid #e0e0e0;background:var(--ui-ist-header-bg, #ffffff)}.ui-ist__header-scroll{overflow:hidden}.ui-ist__body{flex:1 1 auto;overflow:auto;scrollbar-width:auto}.ui-ist__body::-webkit-scrollbar{width:8px;height:8px}.ui-ist__body::-webkit-scrollbar-button{display:none}.ui-ist__body::-webkit-scrollbar-thumb{background-color:#00000059;border-radius:4px}.ui-ist__body::-webkit-scrollbar-track:hover{background-color:#00000026}.ui-ist__row{display:flex;width:max-content;min-width:100%;box-sizing:border-box}.ui-ist__row--header{min-height:56px}.ui-ist__row:not(.ui-ist__row--header){border-bottom:1px solid #d3d3d3}.ui-ist__row--clickable{cursor:pointer}.ui-ist__row--clickable:not(.ui-ist__row--selected):hover{background:#fff2fc}.ui-ist__row--clickable:not(.ui-ist__row--selected):hover .ui-ist__cell{background:#fff2fc}.ui-ist__row--selected .ui-ist__cell{background:#f4f4f4}.ui-ist__cell{flex-grow:0;flex-shrink:0;box-sizing:border-box;display:flex;align-items:center;padding:8px 24px;font-size:14px;line-height:20px;overflow:hidden;background:#fff}.ui-ist__cell--header{background:var(--ui-ist-header-bg, #ffffff);font-weight:700;font-size:14px;line-height:16px}.ui-ist__cell--right{justify-content:flex-end;text-align:right}.ui-ist__cell--center{justify-content:center;text-align:center}.ui-ist__cell--sticky-start{position:sticky;z-index:2}.ui-ist__cell--checkbox.ui-ist__cell--sticky-start{left:0}.ui-ist__cell--sticky-end{position:sticky;right:0;z-index:2;order:1}.ui-ist__cell--checkbox{flex:0 0 var(--ui-ist-checkbox-width);min-width:var(--ui-ist-checkbox-width);justify-content:center;padding:0}.ui-ist__cell--spacer{flex:1 1 auto;min-width:0;padding:0}.ui-ist__row--header .ui-ist__cell--spacer{background:var(--ui-ist-header-bg, #ffffff)}.ui-ist__cell-text{overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.ui-ist__skeleton{display:block;width:100%}.ui-ist--scrolled-start .ui-ist__cell--sticky-start-edge{box-shadow:24px 8px 24px #24242414}.ui-ist--scrolled-end .ui-ist__cell--sticky-end{box-shadow:0 8px 24px 4px #24242414}.ui-ist__state{padding:8px 24px;font-size:14px;line-height:20px}.ui-ist--condensed .ui-ist__cell{padding:8px 12px}.ui-ist--condensed .ui-ist__cell:first-child{padding-left:24px}.ui-ist--condensed .ui-ist__cell--sticky-end{padding-right:24px}.ui-ist--condensed .ui-ist__cell--spacer{padding:0}:host(.ui-ist--fill-host){height:100%}.ui-ist--fill-height{height:100%}.ui-ist--fill-height .ui-ist__body{min-height:0}.ui-ist__sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}\n"],
618
+ dependencies: [
619
+ {
620
+ kind: "directive",
621
+ type: NgTemplateOutlet,
622
+ selector: "[ngTemplateOutlet]",
623
+ inputs: [
624
+ "ngTemplateOutletContext",
625
+ "ngTemplateOutlet",
626
+ "ngTemplateOutletInjector"
627
+ ]
628
+ },
629
+ {
630
+ kind: "component",
631
+ type: CdkVirtualScrollViewport,
632
+ selector: "cdk-virtual-scroll-viewport",
633
+ inputs: ["orientation", "appendOnly"],
634
+ outputs: ["scrolledIndexChange"]
635
+ },
636
+ {
637
+ kind: "directive",
638
+ type: CdkFixedSizeVirtualScroll,
639
+ selector: "cdk-virtual-scroll-viewport[itemSize]",
640
+ inputs: [
641
+ "itemSize",
642
+ "minBufferPx",
643
+ "maxBufferPx"
644
+ ]
645
+ },
646
+ {
647
+ kind: "directive",
648
+ type: CdkVirtualForOf,
649
+ selector: "[cdkVirtualFor][cdkVirtualForOf]",
650
+ inputs: [
651
+ "cdkVirtualForOf",
652
+ "cdkVirtualForTrackBy",
653
+ "cdkVirtualForTemplate",
654
+ "cdkVirtualForTemplateCacheSize"
655
+ ]
656
+ },
657
+ {
658
+ kind: "component",
659
+ type: SkeletonComponent,
660
+ selector: "ui-skeleton",
661
+ inputs: [
662
+ "count",
663
+ "theme",
664
+ "appearance",
665
+ "isAiTheme",
666
+ "applicationTheme"
667
+ ]
668
+ },
669
+ {
670
+ kind: "component",
671
+ type: CheckboxComponent,
672
+ selector: "ui-checkbox",
673
+ inputs: [
674
+ "disabled",
675
+ "checked",
676
+ "indeterminate",
677
+ "companyColor",
678
+ "name",
679
+ "label",
680
+ "multiple",
681
+ "applicationTheme",
682
+ "ariaLabel",
683
+ "testId",
684
+ "ariaRequired",
685
+ "hasError",
686
+ "hideBuiltInErrors",
687
+ "hideLabelInErrors",
688
+ "ariaLabelledby",
689
+ "ariaDescribedby",
690
+ "truncateText",
691
+ "alignment",
692
+ "tabIndex"
693
+ ],
694
+ outputs: ["changed"]
695
+ },
696
+ {
697
+ kind: "pipe",
698
+ type: AsyncPipe,
699
+ name: "async"
700
+ },
701
+ {
702
+ kind: "pipe",
703
+ type: UiTranslatePipe,
704
+ name: "uiTranslate"
705
+ }
706
+ ],
707
+ changeDetection: i0.ChangeDetectionStrategy.OnPush
708
+ });
709
+ }
710
+ };
711
+ i0.ɵɵngDeclareClassMetadata({
712
+ minVersion: "12.0.0",
713
+ version: "22.2.4",
714
+ ngImport: i0,
715
+ type: InfiniteScrollTableComponent,
716
+ decorators: [{
717
+ type: Component,
718
+ args: [{
719
+ selector: "ui-infinite-scroll-table",
720
+ changeDetection: ChangeDetectionStrategy.OnPush,
721
+ host: { "[class.ui-ist--fill-host]": "fillHeight()" },
722
+ imports: [
723
+ AsyncPipe,
724
+ NgTemplateOutlet,
725
+ CdkVirtualScrollViewport,
726
+ CdkFixedSizeVirtualScroll,
727
+ CdkVirtualForOf,
728
+ SkeletonComponent,
729
+ CheckboxComponent,
730
+ UiTranslatePipe
731
+ ],
732
+ template: "<!-- role=\"table\", not \"grid\": row access is Tab-only with no arrow-key cell traversal, so \"grid\" would\n promise 2D keyboard navigation this does not implement. Selection is conveyed by the row's checkbox,\n not `aria-selected` — which is valid only on grid/treegrid anyway. -->\n<div\n class=\"ui-ist\"\n role=\"table\"\n [class.ui-ist--condensed]=\"isCondensed()\"\n [class.ui-ist--scrolled-start]=\"!scrollStart()\"\n [class.ui-ist--scrolled-end]=\"horizontalScroll() && !scrollEnd()\"\n [class.ui-ist--fill-height]=\"fillHeight()\"\n [attr.aria-rowcount]=\"hasMore() ? -1 : data().length + 1\"\n [attr.aria-busy]=\"loading() || loadingMore()\"\n [attr.aria-label]=\"ariaLabel() || null\"\n [attr.data-testid]=\"testId()\"\n>\n <!-- Pinned header, outside the viewport so it never scrolls vertically. The outer element reserves the\n body's scrollbar width as padding (keeping the background and border across that strip); the inner\n one carries the horizontal scrollLeft synced from the body. -->\n <div class=\"ui-ist__header\" [style.padding-right.px]=\"scrollbarWidth()\" role=\"presentation\">\n <div #headerScroll class=\"ui-ist__header-scroll\" role=\"presentation\">\n <div class=\"ui-ist__row ui-ist__row--header\" role=\"row\" aria-rowindex=\"1\">\n @if (selectable()) {\n <div\n class=\"ui-ist__cell ui-ist__cell--header ui-ist__cell--checkbox ui-ist__cell--sticky-start\"\n [class.ui-ist__cell--sticky-start-edge]=\"!stickyStartKey()\"\n role=\"columnheader\"\n ></div>\n }\n @for (column of columns(); track column.key; let colIndex = $index) {\n <div\n class=\"ui-ist__cell ui-ist__cell--header\"\n role=\"columnheader\"\n [class.ui-ist__cell--sticky-start]=\"column.key === stickyStartKey()\"\n [class.ui-ist__cell--sticky-start-edge]=\"isStickyStartEdge(column)\"\n [class.ui-ist__cell--sticky-end]=\"column.key === stickyEndKey()\"\n [class.ui-ist__cell--right]=\"column.styles?.alignment === 'right'\"\n [class.ui-ist__cell--center]=\"column.styles?.alignment === 'center'\"\n [style.flex-basis]=\"columnWidth(column)\"\n [style.min-width]=\"columnWidth(column)\"\n [style.max-width]=\"columnWidth(column)\"\n [style.left]=\"stickyStartLeft(column)\"\n >\n @if (column.headerCellTemplate) {\n <ng-container\n *ngTemplateOutlet=\"column.headerCellTemplate; context: { $implicit: column.title, column, colIndex }\"\n ></ng-container>\n } @else {\n <span class=\"ui-ist__cell-text\">{{ column.title }}</span>\n }\n </div>\n }\n @for (loadingKey of loadingColumns(); track loadingKey) {\n <div\n class=\"ui-ist__cell ui-ist__cell--header ui-ist__cell--loading\"\n role=\"presentation\"\n aria-hidden=\"true\"\n [style.flex-basis]=\"defaultColumnWidth\"\n [style.min-width]=\"defaultColumnWidth\"\n [style.max-width]=\"defaultColumnWidth\"\n >\n <ui-skeleton class=\"ui-ist__skeleton\" [count]=\"1\" [theme]=\"skeletonTheme\" appearance=\"line\"></ui-skeleton>\n </div>\n }\n <div class=\"ui-ist__cell ui-ist__cell--spacer\" role=\"presentation\" aria-hidden=\"true\"></div>\n </div>\n </div>\n </div>\n\n <!-- The CDK viewport owns BOTH vertical (virtualized) and horizontal scroll, so sticky columns pin\n against it and the horizontal scrollbar sits at the viewport bottom. -->\n @if (showViewport()) {\n <cdk-virtual-scroll-viewport\n class=\"ui-ist__body\"\n role=\"rowgroup\"\n [itemSize]=\"rowHeight()\"\n [minBufferPx]=\"effectiveMinBufferPx()\"\n [maxBufferPx]=\"effectiveMaxBufferPx()\"\n [style.height]=\"viewportHeight()\"\n [style.max-height]=\"fillHeight() ? maxHeight() : null\"\n >\n <div\n *cdkVirtualFor=\"let row of renderRows(); let rowIndex = index; trackBy: renderRowTrackBy\"\n class=\"ui-ist__row\"\n role=\"row\"\n [class.ui-ist__row--clickable]=\"rowsClickable() && row.kind === 'data'\"\n [class.ui-ist__row--selected]=\"isRowSelected(row)\"\n [attr.aria-rowindex]=\"row.kind === 'data' ? row.index + 2 : null\"\n [attr.aria-hidden]=\"row.kind === 'skeleton' ? true : null\"\n [attr.tabindex]=\"rowsClickable() && row.kind === 'data' ? 0 : null\"\n [style.height.px]=\"rowHeight()\"\n [attr.data-testid]=\"rowTestId(row)\"\n (click)=\"emitRowClick($event, row)\"\n (keydown.enter)=\"activateRow($event, row)\"\n (keydown.space)=\"activateRow($event, row)\"\n >\n @if (selectable()) {\n <!-- This `stopPropagation` is what actually stops a checkbox click activating the row: it runs\n before the click reaches the row's listener, so `isInteractiveTarget` is never consulted on\n this path. That guard is a real second line of defence (`ui-checkbox` renders a focusable\n wrapper and a native input, both matching INTERACTIVE_TARGET_SELECTOR), not a substitute. -->\n <div\n class=\"ui-ist__cell ui-ist__cell--checkbox ui-ist__cell--sticky-start\"\n [class.ui-ist__cell--sticky-start-edge]=\"!stickyStartKey()\"\n role=\"cell\"\n (click)=\"$event.stopPropagation()\"\n (keydown)=\"$event.stopPropagation()\"\n >\n @if (row.kind === 'data') {\n <ui-checkbox\n [checked]=\"isRowSelected(row)\"\n [ariaLabel]=\"'Select row ' + (row.index + 1)\"\n [testId]=\"rowCheckboxTestId(row)\"\n (changed)=\"emitSelectionChange(row, $event)\"\n ></ui-checkbox>\n }\n </div>\n }\n @for (column of columns(); track column.key) {\n <div\n class=\"ui-ist__cell\"\n role=\"cell\"\n [class.ui-ist__cell--sticky-start]=\"column.key === stickyStartKey()\"\n [class.ui-ist__cell--sticky-start-edge]=\"isStickyStartEdge(column)\"\n [class.ui-ist__cell--sticky-end]=\"column.key === stickyEndKey()\"\n [class.ui-ist__cell--right]=\"column.styles?.alignment === 'right'\"\n [class.ui-ist__cell--center]=\"column.styles?.alignment === 'center'\"\n [style.flex-basis]=\"columnWidth(column)\"\n [style.min-width]=\"columnWidth(column)\"\n [style.max-width]=\"columnWidth(column)\"\n [style.left]=\"stickyStartLeft(column)\"\n [attr.data-testid]=\"cellTestId(row, column.key)\"\n >\n @if (row.kind === 'skeleton') {\n <ui-skeleton class=\"ui-ist__skeleton\" [count]=\"1\" [theme]=\"skeletonTheme\" appearance=\"line\"></ui-skeleton>\n } @else if (column.rowCellTemplate) {\n <ng-container\n *ngTemplateOutlet=\"column.rowCellTemplate; context: { $implicit: row.item, rowIndex: row.index }\"\n ></ng-container>\n } @else {\n <span class=\"ui-ist__cell-text\">{{ getCellValue(row.item, column.key) }}</span>\n }\n </div>\n }\n @for (loadingKey of loadingColumns(); track loadingKey) {\n <div\n class=\"ui-ist__cell ui-ist__cell--loading\"\n role=\"presentation\"\n aria-hidden=\"true\"\n [style.flex-basis]=\"defaultColumnWidth\"\n [style.min-width]=\"defaultColumnWidth\"\n [style.max-width]=\"defaultColumnWidth\"\n >\n <ui-skeleton class=\"ui-ist__skeleton\" [count]=\"1\" [theme]=\"skeletonTheme\" appearance=\"line\"></ui-skeleton>\n </div>\n }\n <div class=\"ui-ist__cell ui-ist__cell--spacer\" role=\"presentation\" aria-hidden=\"true\"></div>\n </div>\n </cdk-virtual-scroll-viewport>\n }\n\n <!-- `showErrorFooter()` and `showErrorState()` differ only on `hasData()`, so they are mutually\n exclusive and safe to merge here. Both fall back to a plain-language message, so a failed fetch is\n never a silent blank box. -->\n @if (showErrorFooter() || showErrorState()) {\n <div class=\"ui-ist__state\" role=\"alert\">\n @if (errorTemplate(); as errorTpl) {\n <ng-container *ngTemplateOutlet=\"errorTpl; context: errorContext\"></ng-container>\n } @else {\n <span>{{ translationContext + 'LOAD_ERROR' | uiTranslate | async }}</span>\n }\n </div>\n }\n\n @if (showEmptyState()) {\n <div class=\"ui-ist__state\">\n @if (noDataTemplate(); as emptyTpl) {\n <ng-container *ngTemplateOutlet=\"emptyTpl\"></ng-container>\n } @else {\n <span>{{ translationContext + 'NO_ROWS' | uiTranslate | async }}</span>\n }\n </div>\n }\n\n <!-- Opt-in, with no fallback (see `endOfListTemplate`). Not role=\"alert\": reaching the end is not an\n alert, and `aria-rowcount` already conveys completeness to assistive tech. -->\n @if (showEndOfList() && endOfListTemplate(); as endTpl) {\n <div class=\"ui-ist__state\">\n <ng-container *ngTemplateOutlet=\"endTpl\"></ng-container>\n </div>\n }\n\n <span class=\"ui-ist__sr-only\" role=\"status\" aria-live=\"polite\">\n @if (statusMessageKey(); as statusKey) {\n {{ statusKey | uiTranslate | async }}\n }\n </span>\n</div>\n",
733
+ styles: [".bg-teal-60b{background:#1c443c}.bg-teal-30b{background:#31766a}.bg-teal-default{background:#46a997}.bg-teal-30w{background:#7ec3b6}.bg-teal-60w{background:#b5ddd5}.bg-teal-secondary{background:#cbd6cb}.bg-teal-90w{background:#ecf6f5}.bg-petrol-60b{background:#102930}.bg-petrol-30b{background:#1b4754}.bg-petrol-default{background:#276678}.bg-petrol-30w{background:#6894a0}.bg-petrol-60w{background:#a9c2c9}.bg-petrol-secondary{background:#c8d7de}.bg-petrol-90w{background:#e9f0f1}.bg-error-60b{background:#513131}.bg-error-30b{background:#8e5655}.bg-error-60w{background:#e3c3c6}.bg-error-secondary{background:#f0dad9}.bg-error-default{background:#cb7b7a}.bg-warning-secondary{background:#f0d6bb}.bg-warning-default{background:#cca45f}.bg-black{background:#000}.bg-dark{background:#888}.bg-medium{background:#e0e0e0}.bg-grey{background:#ededed}.bg-light{background:#f6f6f6}.bg-white{background:#fff}.bg-box-shadow{background:#00000014}.bg-navigation-subtitle{background:#528593}.bgc-teal-60b{background-color:#1c443c}.bgc-teal-30b{background-color:#31766a}.bgc-teal-default{background-color:#46a997}.bgc-teal-30w{background-color:#7ec3b6}.bgc-teal-60w{background-color:#b5ddd5}.bgc-teal-secondary{background-color:#cbd6cb}.bgc-teal-90w{background-color:#ecf6f5}.bgc-petrol-60b{background-color:#102930}.bgc-petrol-30b{background-color:#1b4754}.bgc-petrol-default{background-color:#276678}.bgc-petrol-30w{background-color:#6894a0}.bgc-petrol-60w{background-color:#a9c2c9}.bgc-petrol-secondary{background-color:#c8d7de}.bgc-petrol-90w{background-color:#e9f0f1}.bgc-error-60b{background-color:#513131}.bgc-error-30b{background-color:#8e5655}.bgc-error-60w{background-color:#e3c3c6}.bgc-error-secondary{background-color:#f0dad9}.bgc-error-default{background-color:#cb7b7a}.bgc-warning-secondary{background-color:#f0d6bb}.bgc-warning-default{background-color:#cca45f}.bgc-black{background-color:#000}.bgc-dark{background-color:#888}.bgc-medium{background-color:#e0e0e0}.bgc-grey{background-color:#ededed}.bgc-light{background-color:#f6f6f6}.bgc-white{background-color:#fff}.bgc-box-shadow{background-color:#00000014}.bgc-navigation-subtitle{background-color:#528593}:host{display:block}.ui-ist{--ui-ist-checkbox-width: 56px;--ui-ist-skeleton-bg: #f4f4f4;display:flex;flex-direction:column;border:1px solid #e0e0e0;border-radius:8px;overflow:hidden;background:#fff}.ui-ist__header{flex:0 0 auto;box-sizing:border-box;overflow:hidden;border-bottom:1px solid #e0e0e0;background:var(--ui-ist-header-bg, #ffffff)}.ui-ist__header-scroll{overflow:hidden}.ui-ist__body{flex:1 1 auto;overflow:auto;scrollbar-width:auto}.ui-ist__body::-webkit-scrollbar{width:8px;height:8px}.ui-ist__body::-webkit-scrollbar-button{display:none}.ui-ist__body::-webkit-scrollbar-thumb{background-color:#00000059;border-radius:4px}.ui-ist__body::-webkit-scrollbar-track:hover{background-color:#00000026}.ui-ist__row{display:flex;width:max-content;min-width:100%;box-sizing:border-box}.ui-ist__row--header{min-height:56px}.ui-ist__row:not(.ui-ist__row--header){border-bottom:1px solid #d3d3d3}.ui-ist__row--clickable{cursor:pointer}.ui-ist__row--clickable:not(.ui-ist__row--selected):hover{background:#fff2fc}.ui-ist__row--clickable:not(.ui-ist__row--selected):hover .ui-ist__cell{background:#fff2fc}.ui-ist__row--selected .ui-ist__cell{background:#f4f4f4}.ui-ist__cell{flex-grow:0;flex-shrink:0;box-sizing:border-box;display:flex;align-items:center;padding:8px 24px;font-size:14px;line-height:20px;overflow:hidden;background:#fff}.ui-ist__cell--header{background:var(--ui-ist-header-bg, #ffffff);font-weight:700;font-size:14px;line-height:16px}.ui-ist__cell--right{justify-content:flex-end;text-align:right}.ui-ist__cell--center{justify-content:center;text-align:center}.ui-ist__cell--sticky-start{position:sticky;z-index:2}.ui-ist__cell--checkbox.ui-ist__cell--sticky-start{left:0}.ui-ist__cell--sticky-end{position:sticky;right:0;z-index:2;order:1}.ui-ist__cell--checkbox{flex:0 0 var(--ui-ist-checkbox-width);min-width:var(--ui-ist-checkbox-width);justify-content:center;padding:0}.ui-ist__cell--spacer{flex:1 1 auto;min-width:0;padding:0}.ui-ist__row--header .ui-ist__cell--spacer{background:var(--ui-ist-header-bg, #ffffff)}.ui-ist__cell-text{overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.ui-ist__skeleton{display:block;width:100%}.ui-ist--scrolled-start .ui-ist__cell--sticky-start-edge{box-shadow:24px 8px 24px #24242414}.ui-ist--scrolled-end .ui-ist__cell--sticky-end{box-shadow:0 8px 24px 4px #24242414}.ui-ist__state{padding:8px 24px;font-size:14px;line-height:20px}.ui-ist--condensed .ui-ist__cell{padding:8px 12px}.ui-ist--condensed .ui-ist__cell:first-child{padding-left:24px}.ui-ist--condensed .ui-ist__cell--sticky-end{padding-right:24px}.ui-ist--condensed .ui-ist__cell--spacer{padding:0}:host(.ui-ist--fill-host){height:100%}.ui-ist--fill-height{height:100%}.ui-ist--fill-height .ui-ist__body{min-height:0}.ui-ist__sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}\n"]
734
+ }]
735
+ }],
736
+ ctorParameters: () => [],
737
+ propDecorators: {
738
+ data: [{
739
+ type: i0.Input,
740
+ args: [{
741
+ isSignal: true,
742
+ alias: "data",
743
+ required: true
744
+ }]
745
+ }],
746
+ columns: [{
747
+ type: i0.Input,
748
+ args: [{
749
+ isSignal: true,
750
+ alias: "columns",
751
+ required: true
752
+ }]
753
+ }],
754
+ rowHeight: [{
755
+ type: i0.Input,
756
+ args: [{
757
+ isSignal: true,
758
+ alias: "rowHeight",
759
+ required: true
760
+ }]
761
+ }],
762
+ trackBy: [{
763
+ type: i0.Input,
764
+ args: [{
765
+ isSignal: true,
766
+ alias: "trackBy",
767
+ required: false
768
+ }]
769
+ }],
770
+ rowIdKey: [{
771
+ type: i0.Input,
772
+ args: [{
773
+ isSignal: true,
774
+ alias: "rowIdKey",
775
+ required: false
776
+ }]
777
+ }],
778
+ minBufferPx: [{
779
+ type: i0.Input,
780
+ args: [{
781
+ isSignal: true,
782
+ alias: "minBufferPx",
783
+ required: false
784
+ }]
785
+ }],
786
+ maxBufferPx: [{
787
+ type: i0.Input,
788
+ args: [{
789
+ isSignal: true,
790
+ alias: "maxBufferPx",
791
+ required: false
792
+ }]
793
+ }],
794
+ maxHeight: [{
795
+ type: i0.Input,
796
+ args: [{
797
+ isSignal: true,
798
+ alias: "maxHeight",
799
+ required: false
800
+ }]
801
+ }],
802
+ fillHeight: [{
803
+ type: i0.Input,
804
+ args: [{
805
+ isSignal: true,
806
+ alias: "fillHeight",
807
+ required: false
808
+ }]
809
+ }],
810
+ isCondensed: [{
811
+ type: i0.Input,
812
+ args: [{
813
+ isSignal: true,
814
+ alias: "isCondensed",
815
+ required: false
816
+ }]
817
+ }],
818
+ selectable: [{
819
+ type: i0.Input,
820
+ args: [{
821
+ isSignal: true,
822
+ alias: "selectable",
823
+ required: false
824
+ }]
825
+ }],
826
+ rowsClickable: [{
827
+ type: i0.Input,
828
+ args: [{
829
+ isSignal: true,
830
+ alias: "rowsClickable",
831
+ required: false
832
+ }]
833
+ }],
834
+ loading: [{
835
+ type: i0.Input,
836
+ args: [{
837
+ isSignal: true,
838
+ alias: "loading",
839
+ required: false
840
+ }]
841
+ }],
842
+ loadingMore: [{
843
+ type: i0.Input,
844
+ args: [{
845
+ isSignal: true,
846
+ alias: "loadingMore",
847
+ required: false
848
+ }]
849
+ }],
850
+ hasMore: [{
851
+ type: i0.Input,
852
+ args: [{
853
+ isSignal: true,
854
+ alias: "hasMore",
855
+ required: true
856
+ }]
857
+ }],
858
+ skeletonRowCount: [{
859
+ type: i0.Input,
860
+ args: [{
861
+ isSignal: true,
862
+ alias: "skeletonRowCount",
863
+ required: false
864
+ }]
865
+ }],
866
+ loadMoreSkeletonCount: [{
867
+ type: i0.Input,
868
+ args: [{
869
+ isSignal: true,
870
+ alias: "loadMoreSkeletonCount",
871
+ required: false
872
+ }]
873
+ }],
874
+ loadingColumnCount: [{
875
+ type: i0.Input,
876
+ args: [{
877
+ isSignal: true,
878
+ alias: "loadingColumnCount",
879
+ required: false
880
+ }]
881
+ }],
882
+ loadMoreThreshold: [{
883
+ type: i0.Input,
884
+ args: [{
885
+ isSignal: true,
886
+ alias: "loadMoreThreshold",
887
+ required: false
888
+ }]
889
+ }],
890
+ noDataTemplate: [{
891
+ type: i0.Input,
892
+ args: [{
893
+ isSignal: true,
894
+ alias: "noDataTemplate",
895
+ required: false
896
+ }]
897
+ }],
898
+ errorTemplate: [{
899
+ type: i0.Input,
900
+ args: [{
901
+ isSignal: true,
902
+ alias: "errorTemplate",
903
+ required: false
904
+ }]
905
+ }],
906
+ error: [{
907
+ type: i0.Input,
908
+ args: [{
909
+ isSignal: true,
910
+ alias: "error",
911
+ required: false
912
+ }]
913
+ }],
914
+ endOfListTemplate: [{
915
+ type: i0.Input,
916
+ args: [{
917
+ isSignal: true,
918
+ alias: "endOfListTemplate",
919
+ required: false
920
+ }]
921
+ }],
922
+ testId: [{
923
+ type: i0.Input,
924
+ args: [{
925
+ isSignal: true,
926
+ alias: "testId",
927
+ required: false
928
+ }]
929
+ }],
930
+ ariaLabel: [{
931
+ type: i0.Input,
932
+ args: [{
933
+ isSignal: true,
934
+ alias: "ariaLabel",
935
+ required: false
936
+ }]
937
+ }],
938
+ loadMore: [{
939
+ type: i0.Output,
940
+ args: ["loadMore"]
941
+ }],
942
+ retry: [{
943
+ type: i0.Output,
944
+ args: ["retry"]
945
+ }],
946
+ rowClick: [{
947
+ type: i0.Output,
948
+ args: ["rowClick"]
949
+ }],
950
+ selectionChange: [{
951
+ type: i0.Output,
952
+ args: ["selectionChange"]
953
+ }],
954
+ viewport: [{
955
+ type: i0.ViewChild,
956
+ args: [i0.forwardRef(() => CdkVirtualScrollViewport), { isSignal: true }]
957
+ }],
958
+ headerScroll: [{
959
+ type: i0.ViewChild,
960
+ args: ["headerScroll", { isSignal: true }]
961
+ }]
962
+ }
963
+ });
964
+ var InfiniteScrollTableComponentModule = class InfiniteScrollTableComponentModule {
965
+ static {
966
+ this.ɵfac = i0.ɵɵngDeclareFactory({
967
+ minVersion: "12.0.0",
968
+ version: "22.2.4",
969
+ ngImport: i0,
970
+ type: InfiniteScrollTableComponentModule,
971
+ deps: [],
972
+ target: i0.ɵɵFactoryTarget.NgModule
973
+ });
974
+ }
975
+ static {
976
+ this.ɵmod = i0.ɵɵngDeclareNgModule({
977
+ minVersion: "14.0.0",
978
+ version: "22.2.4",
979
+ ngImport: i0,
980
+ type: InfiniteScrollTableComponentModule,
981
+ imports: [
982
+ CommonModule,
983
+ ScrollingModule,
984
+ InfiniteScrollTableComponent
985
+ ],
986
+ exports: [InfiniteScrollTableComponent]
987
+ });
988
+ }
989
+ static {
990
+ this.ɵinj = i0.ɵɵngDeclareInjector({
991
+ minVersion: "12.0.0",
992
+ version: "22.2.4",
993
+ ngImport: i0,
994
+ type: InfiniteScrollTableComponentModule,
995
+ imports: [
996
+ CommonModule,
997
+ ScrollingModule,
998
+ InfiniteScrollTableComponent
999
+ ]
1000
+ });
1001
+ }
1002
+ };
1003
+ i0.ɵɵngDeclareClassMetadata({
1004
+ minVersion: "12.0.0",
1005
+ version: "22.2.4",
1006
+ ngImport: i0,
1007
+ type: InfiniteScrollTableComponentModule,
1008
+ decorators: [{
1009
+ type: NgModule,
1010
+ args: [{
1011
+ imports: [
1012
+ CommonModule,
1013
+ ScrollingModule,
1014
+ InfiniteScrollTableComponent
1015
+ ],
1016
+ exports: [InfiniteScrollTableComponent]
1017
+ }]
1018
+ }]
1019
+ });
675
1020
  export { InfiniteScrollTableComponent, InfiniteScrollTableComponentModule };
676
- //# sourceMappingURL=testgorilla-tgo-ui-components-infinite-scroll-table.mjs.map
1021
+
1022
+ //# sourceMappingURL=testgorilla-tgo-ui-components-infinite-scroll-table.mjs.map