@ngbase/adk 0.1.17 → 0.1.18

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 (199) hide show
  1. package/fesm2022/ngbase-adk-a11y.mjs +42 -42
  2. package/fesm2022/ngbase-adk-a11y.mjs.map +1 -1
  3. package/fesm2022/ngbase-adk-accordion.mjs +20 -26
  4. package/fesm2022/ngbase-adk-accordion.mjs.map +1 -1
  5. package/fesm2022/ngbase-adk-autocomplete.mjs +11 -11
  6. package/fesm2022/ngbase-adk-autocomplete.mjs.map +1 -1
  7. package/fesm2022/ngbase-adk-avatar.mjs +13 -13
  8. package/fesm2022/ngbase-adk-avatar.mjs.map +1 -1
  9. package/fesm2022/ngbase-adk-bidi.mjs +3 -3
  10. package/fesm2022/ngbase-adk-bidi.mjs.map +1 -1
  11. package/fesm2022/ngbase-adk-breadcrumb.mjs +14 -14
  12. package/fesm2022/ngbase-adk-breadcrumb.mjs.map +1 -1
  13. package/fesm2022/ngbase-adk-cache.mjs +3 -3
  14. package/fesm2022/ngbase-adk-cache.mjs.map +1 -1
  15. package/fesm2022/ngbase-adk-carousel.mjs +18 -18
  16. package/fesm2022/ngbase-adk-carousel.mjs.map +1 -1
  17. package/fesm2022/ngbase-adk-checkbox.mjs +15 -21
  18. package/fesm2022/ngbase-adk-checkbox.mjs.map +1 -1
  19. package/fesm2022/ngbase-adk-chip.mjs +12 -12
  20. package/fesm2022/ngbase-adk-chip.mjs.map +1 -1
  21. package/fesm2022/ngbase-adk-clipboard.mjs +7 -5
  22. package/fesm2022/ngbase-adk-clipboard.mjs.map +1 -1
  23. package/fesm2022/ngbase-adk-collections.mjs.map +1 -1
  24. package/fesm2022/ngbase-adk-color-picker.mjs +44 -53
  25. package/fesm2022/ngbase-adk-color-picker.mjs.map +1 -1
  26. package/fesm2022/ngbase-adk-cookies.mjs +3 -3
  27. package/fesm2022/ngbase-adk-cookies.mjs.map +1 -1
  28. package/fesm2022/ngbase-adk-datepicker.mjs +70 -89
  29. package/fesm2022/ngbase-adk-datepicker.mjs.map +1 -1
  30. package/fesm2022/ngbase-adk-dialog.mjs +17 -39
  31. package/fesm2022/ngbase-adk-dialog.mjs.map +1 -1
  32. package/fesm2022/ngbase-adk-drag.mjs +20 -20
  33. package/fesm2022/ngbase-adk-drag.mjs.map +1 -1
  34. package/fesm2022/ngbase-adk-form-field.mjs +65 -118
  35. package/fesm2022/ngbase-adk-form-field.mjs.map +1 -1
  36. package/fesm2022/ngbase-adk-hover-card.mjs +5 -5
  37. package/fesm2022/ngbase-adk-hover-card.mjs.map +1 -1
  38. package/fesm2022/ngbase-adk-icon.mjs +9 -11
  39. package/fesm2022/ngbase-adk-icon.mjs.map +1 -1
  40. package/fesm2022/ngbase-adk-inline-edit.mjs +27 -35
  41. package/fesm2022/ngbase-adk-inline-edit.mjs.map +1 -1
  42. package/fesm2022/ngbase-adk-jwt.mjs +6 -6
  43. package/fesm2022/ngbase-adk-jwt.mjs.map +1 -1
  44. package/fesm2022/ngbase-adk-keys.mjs +6 -6
  45. package/fesm2022/ngbase-adk-keys.mjs.map +1 -1
  46. package/fesm2022/ngbase-adk-layout.mjs.map +1 -1
  47. package/fesm2022/ngbase-adk-list.mjs +10 -10
  48. package/fesm2022/ngbase-adk-list.mjs.map +1 -1
  49. package/fesm2022/ngbase-adk-mask.mjs +8 -8
  50. package/fesm2022/ngbase-adk-mask.mjs.map +1 -1
  51. package/fesm2022/ngbase-adk-menu.mjs +69 -79
  52. package/fesm2022/ngbase-adk-menu.mjs.map +1 -1
  53. package/fesm2022/ngbase-adk-network.mjs +3 -3
  54. package/fesm2022/ngbase-adk-network.mjs.map +1 -1
  55. package/fesm2022/ngbase-adk-otp.mjs +24 -45
  56. package/fesm2022/ngbase-adk-otp.mjs.map +1 -1
  57. package/fesm2022/ngbase-adk-pagination.mjs +9 -9
  58. package/fesm2022/ngbase-adk-pagination.mjs.map +1 -1
  59. package/fesm2022/ngbase-adk-popover.mjs +120 -89
  60. package/fesm2022/ngbase-adk-popover.mjs.map +1 -1
  61. package/fesm2022/ngbase-adk-portal.mjs +134 -47
  62. package/fesm2022/ngbase-adk-portal.mjs.map +1 -1
  63. package/fesm2022/ngbase-adk-progress.mjs +7 -7
  64. package/fesm2022/ngbase-adk-progress.mjs.map +1 -1
  65. package/fesm2022/ngbase-adk-radio.mjs +20 -27
  66. package/fesm2022/ngbase-adk-radio.mjs.map +1 -1
  67. package/fesm2022/ngbase-adk-resizable.mjs +138 -48
  68. package/fesm2022/ngbase-adk-resizable.mjs.map +1 -1
  69. package/fesm2022/ngbase-adk-scroll-area.mjs +28 -20
  70. package/fesm2022/ngbase-adk-scroll-area.mjs.map +1 -1
  71. package/fesm2022/ngbase-adk-select.mjs +58 -80
  72. package/fesm2022/ngbase-adk-select.mjs.map +1 -1
  73. package/fesm2022/ngbase-adk-selectable.mjs +19 -30
  74. package/fesm2022/ngbase-adk-selectable.mjs.map +1 -1
  75. package/fesm2022/ngbase-adk-sheet.mjs +6 -20
  76. package/fesm2022/ngbase-adk-sheet.mjs.map +1 -1
  77. package/fesm2022/ngbase-adk-sidenav.mjs +65 -48
  78. package/fesm2022/ngbase-adk-sidenav.mjs.map +1 -1
  79. package/fesm2022/ngbase-adk-slider.mjs +40 -53
  80. package/fesm2022/ngbase-adk-slider.mjs.map +1 -1
  81. package/fesm2022/ngbase-adk-sonner.mjs +12 -19
  82. package/fesm2022/ngbase-adk-sonner.mjs.map +1 -1
  83. package/fesm2022/ngbase-adk-stepper.mjs +17 -25
  84. package/fesm2022/ngbase-adk-stepper.mjs.map +1 -1
  85. package/fesm2022/ngbase-adk-switch.mjs +25 -32
  86. package/fesm2022/ngbase-adk-switch.mjs.map +1 -1
  87. package/fesm2022/ngbase-adk-table.mjs +581 -83
  88. package/fesm2022/ngbase-adk-table.mjs.map +1 -1
  89. package/fesm2022/ngbase-adk-tabs.mjs +37 -35
  90. package/fesm2022/ngbase-adk-tabs.mjs.map +1 -1
  91. package/fesm2022/ngbase-adk-test.mjs.map +1 -1
  92. package/fesm2022/ngbase-adk-toggle-group.mjs +20 -34
  93. package/fesm2022/ngbase-adk-toggle-group.mjs.map +1 -1
  94. package/fesm2022/ngbase-adk-toggle.mjs +14 -19
  95. package/fesm2022/ngbase-adk-toggle.mjs.map +1 -1
  96. package/fesm2022/ngbase-adk-tooltip.mjs +12 -19
  97. package/fesm2022/ngbase-adk-tooltip.mjs.map +1 -1
  98. package/fesm2022/ngbase-adk-tour.mjs +52 -52
  99. package/fesm2022/ngbase-adk-tour.mjs.map +1 -1
  100. package/fesm2022/ngbase-adk-translate.mjs +8 -10
  101. package/fesm2022/ngbase-adk-translate.mjs.map +1 -1
  102. package/fesm2022/ngbase-adk-tree.mjs +20 -20
  103. package/fesm2022/ngbase-adk-tree.mjs.map +1 -1
  104. package/fesm2022/ngbase-adk-utils.mjs +30 -43
  105. package/fesm2022/ngbase-adk-utils.mjs.map +1 -1
  106. package/fesm2022/ngbase-adk-virtualizer.mjs +9 -9
  107. package/fesm2022/ngbase-adk-virtualizer.mjs.map +1 -1
  108. package/package.json +101 -101
  109. package/schematics/components/files/accordion/accordion.ts.template +8 -5
  110. package/schematics/components/files/audio/AudioPlayer.ts.template +245 -0
  111. package/schematics/components/files/audio/AudioRecorder.ts.template +377 -0
  112. package/schematics/components/files/audio/AudioVisualizer.ts.template +175 -0
  113. package/schematics/components/files/audio/index.ts.template +3 -0
  114. package/schematics/components/files/charts/area-chart.component.ts.template +278 -0
  115. package/schematics/components/files/charts/bar-chart.component.ts.template +262 -0
  116. package/schematics/components/files/charts/chart-tooltip.component.ts.template +168 -0
  117. package/schematics/components/files/charts/index.ts.template +4 -0
  118. package/schematics/components/files/charts/line-chart.component.ts.template +238 -0
  119. package/schematics/components/files/charts/pie-chart.component.ts.template +283 -0
  120. package/schematics/components/files/checkbox/checkbox.ts.template +2 -2
  121. package/schematics/components/files/color-picker/color-picker.ts.template +2 -2
  122. package/schematics/components/files/dialog/dialog.ts.template +18 -14
  123. package/schematics/components/files/drawer/drawer.ts.template +30 -27
  124. package/schematics/components/files/form-field/form-field.ts.template +49 -21
  125. package/schematics/components/files/pagination/pagination.ts.template +4 -4
  126. package/schematics/components/files/picasa/picasa-base.component.ts.template +15 -30
  127. package/schematics/components/files/popover/popover.ts.template +15 -4
  128. package/schematics/components/files/select/list-selection.ts.template +0 -2
  129. package/schematics/components/files/select/option.ts.template +1 -1
  130. package/schematics/components/files/selectable/selectable.ts.template +2 -2
  131. package/schematics/components/files/sheet/sheet.ts.template +26 -14
  132. package/schematics/components/files/sidenav/sidenav.ts.template +7 -5
  133. package/schematics/components/files/sonner/sonner.ts.template +1 -2
  134. package/schematics/components/files/stepper/stepper.ts.template +2 -4
  135. package/schematics/components/files/switch/switch.ts.template +2 -2
  136. package/schematics/components/files/table/table.ts.template +43 -3
  137. package/schematics/components/files/theme/theme.service.ts.template +3 -3
  138. package/schematics/components/files/toggle/toggle.ts.template +1 -1
  139. package/schematics/components/files/toggle-group/toggle-group.ts.template +1 -1
  140. package/schematics/components/files/tooltip/tooltip.ts.template +2 -3
  141. package/{accordion/index.d.ts → types/ngbase-adk-accordion.d.ts} +1 -3
  142. package/{autocomplete/index.d.ts → types/ngbase-adk-autocomplete.d.ts} +2 -7
  143. package/{checkbox/index.d.ts → types/ngbase-adk-checkbox.d.ts} +8 -14
  144. package/types/ngbase-adk-clipboard.d.ts +12 -0
  145. package/{color-picker/index.d.ts → types/ngbase-adk-color-picker.d.ts} +14 -26
  146. package/{datepicker/index.d.ts → types/ngbase-adk-datepicker.d.ts} +9 -18
  147. package/{dialog/index.d.ts → types/ngbase-adk-dialog.d.ts} +3 -8
  148. package/types/ngbase-adk-form-field.d.ts +88 -0
  149. package/{inline-edit/index.d.ts → types/ngbase-adk-inline-edit.d.ts} +8 -16
  150. package/{menu/index.d.ts → types/ngbase-adk-menu.d.ts} +6 -5
  151. package/{otp/index.d.ts → types/ngbase-adk-otp.d.ts} +8 -16
  152. package/{popover/index.d.ts → types/ngbase-adk-popover.d.ts} +14 -2
  153. package/{portal/index.d.ts → types/ngbase-adk-portal.d.ts} +29 -8
  154. package/{radio/index.d.ts → types/ngbase-adk-radio.d.ts} +9 -12
  155. package/{resizable/index.d.ts → types/ngbase-adk-resizable.d.ts} +4 -4
  156. package/{scroll-area/index.d.ts → types/ngbase-adk-scroll-area.d.ts} +2 -1
  157. package/{select/index.d.ts → types/ngbase-adk-select.d.ts} +8 -22
  158. package/{selectable/index.d.ts → types/ngbase-adk-selectable.d.ts} +6 -10
  159. package/{sheet/index.d.ts → types/ngbase-adk-sheet.d.ts} +4 -3
  160. package/{sidenav/index.d.ts → types/ngbase-adk-sidenav.d.ts} +7 -8
  161. package/{slider/index.d.ts → types/ngbase-adk-slider.d.ts} +8 -17
  162. package/{sonner/index.d.ts → types/ngbase-adk-sonner.d.ts} +1 -3
  163. package/{stepper/index.d.ts → types/ngbase-adk-stepper.d.ts} +1 -4
  164. package/{switch/index.d.ts → types/ngbase-adk-switch.d.ts} +7 -14
  165. package/{table/index.d.ts → types/ngbase-adk-table.d.ts} +126 -3
  166. package/{test/index.d.ts → types/ngbase-adk-test.d.ts} +1 -1
  167. package/{toggle-group/index.d.ts → types/ngbase-adk-toggle-group.d.ts} +5 -10
  168. package/types/ngbase-adk-toggle.d.ts +14 -0
  169. package/{tooltip/index.d.ts → types/ngbase-adk-tooltip.d.ts} +9 -11
  170. package/{tour/index.d.ts → types/ngbase-adk-tour.d.ts} +4 -6
  171. package/{utils/index.d.ts → types/ngbase-adk-utils.d.ts} +15 -11
  172. package/clipboard/index.d.ts +0 -11
  173. package/form-field/index.d.ts +0 -97
  174. package/toggle/index.d.ts +0 -16
  175. /package/{a11y/index.d.ts → types/ngbase-adk-a11y.d.ts} +0 -0
  176. /package/{avatar/index.d.ts → types/ngbase-adk-avatar.d.ts} +0 -0
  177. /package/{bidi/index.d.ts → types/ngbase-adk-bidi.d.ts} +0 -0
  178. /package/{breadcrumb/index.d.ts → types/ngbase-adk-breadcrumb.d.ts} +0 -0
  179. /package/{cache/index.d.ts → types/ngbase-adk-cache.d.ts} +0 -0
  180. /package/{carousel/index.d.ts → types/ngbase-adk-carousel.d.ts} +0 -0
  181. /package/{chip/index.d.ts → types/ngbase-adk-chip.d.ts} +0 -0
  182. /package/{collections/index.d.ts → types/ngbase-adk-collections.d.ts} +0 -0
  183. /package/{cookies/index.d.ts → types/ngbase-adk-cookies.d.ts} +0 -0
  184. /package/{drag/index.d.ts → types/ngbase-adk-drag.d.ts} +0 -0
  185. /package/{hover-card/index.d.ts → types/ngbase-adk-hover-card.d.ts} +0 -0
  186. /package/{icon/index.d.ts → types/ngbase-adk-icon.d.ts} +0 -0
  187. /package/{jwt/index.d.ts → types/ngbase-adk-jwt.d.ts} +0 -0
  188. /package/{keys/index.d.ts → types/ngbase-adk-keys.d.ts} +0 -0
  189. /package/{layout/index.d.ts → types/ngbase-adk-layout.d.ts} +0 -0
  190. /package/{list/index.d.ts → types/ngbase-adk-list.d.ts} +0 -0
  191. /package/{mask/index.d.ts → types/ngbase-adk-mask.d.ts} +0 -0
  192. /package/{network/index.d.ts → types/ngbase-adk-network.d.ts} +0 -0
  193. /package/{pagination/index.d.ts → types/ngbase-adk-pagination.d.ts} +0 -0
  194. /package/{progress/index.d.ts → types/ngbase-adk-progress.d.ts} +0 -0
  195. /package/{tabs/index.d.ts → types/ngbase-adk-tabs.d.ts} +0 -0
  196. /package/{translate/index.d.ts → types/ngbase-adk-translate.d.ts} +0 -0
  197. /package/{tree/index.d.ts → types/ngbase-adk-tree.d.ts} +0 -0
  198. /package/{virtualizer/index.d.ts → types/ngbase-adk-virtualizer.d.ts} +0 -0
  199. /package/{index.d.ts → types/ngbase-adk.d.ts} +0 -0
@@ -1,15 +1,16 @@
1
1
  import * as i0 from '@angular/core';
2
- import { inject, Directive, input, contentChild, TemplateRef, viewChild, ViewContainerRef, computed, effect, untracked, InjectionToken, Injector, IterableDiffers, contentChildren, signal, model, output } from '@angular/core';
2
+ import { inject, Directive, input, contentChild, TemplateRef, viewChild, ViewContainerRef, computed, effect, untracked, InjectionToken, Injector, IterableDiffers, contentChildren, signal, DestroyRef, model, output, ElementRef, Renderer2, afterNextRender } from '@angular/core';
3
+ import { fromEvent, auditTime } from 'rxjs';
3
4
 
4
5
  class NgbHead {
5
6
  constructor() {
6
7
  this.column = inject(NgbColumn);
7
8
  this.sticky = this.column.sticky;
8
9
  }
9
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.0", ngImport: i0, type: NgbHead, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
10
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.2.0", type: NgbHead, isStandalone: true, selector: "[ngbHead]", host: { properties: { "attr.data-sticky": "column.sticky() || undefined" } }, ngImport: i0 }); }
10
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: NgbHead, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
11
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.1.0", type: NgbHead, isStandalone: true, selector: "[ngbHead]", host: { properties: { "attr.data-sticky": "column.sticky() || undefined" } }, ngImport: i0 }); }
11
12
  }
12
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0", ngImport: i0, type: NgbHead, decorators: [{
13
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: NgbHead, decorators: [{
13
14
  type: Directive,
14
15
  args: [{
15
16
  selector: '[ngbHead]',
@@ -19,10 +20,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0", ngImpor
19
20
  }]
20
21
  }] });
21
22
  class NgbHeadDef {
22
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.0", ngImport: i0, type: NgbHeadDef, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
23
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.2.0", type: NgbHeadDef, isStandalone: true, selector: "[ngbHeadDef]", ngImport: i0 }); }
23
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: NgbHeadDef, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
24
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.1.0", type: NgbHeadDef, isStandalone: true, selector: "[ngbHeadDef]", ngImport: i0 }); }
24
25
  }
25
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0", ngImport: i0, type: NgbHeadDef, decorators: [{
26
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: NgbHeadDef, decorators: [{
26
27
  type: Directive,
27
28
  args: [{
28
29
  selector: '[ngbHeadDef]',
@@ -33,27 +34,27 @@ class NgbColumn {
33
34
  constructor() {
34
35
  this.ngbColumn = input.required(...(ngDevMode ? [{ debugName: "ngbColumn" }] : []));
35
36
  this.sticky = input('', ...(ngDevMode ? [{ debugName: "sticky" }] : []));
36
- this.cells = contentChild(NgbCellDef, ...(ngDevMode ? [{ debugName: "cells", read: TemplateRef }] : [{ read: TemplateRef }]));
37
- this.heads = contentChild(NgbHeadDef, ...(ngDevMode ? [{ debugName: "heads", read: TemplateRef }] : [{ read: TemplateRef }]));
37
+ this.cells = contentChild(NgbCellDef, { ...(ngDevMode ? { debugName: "cells" } : {}), read: TemplateRef });
38
+ this.heads = contentChild(NgbHeadDef, { ...(ngDevMode ? { debugName: "heads" } : {}), read: TemplateRef });
38
39
  }
39
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.0", ngImport: i0, type: NgbColumn, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
40
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.2.0", version: "20.2.0", type: NgbColumn, isStandalone: true, selector: "[ngbColumn]", inputs: { ngbColumn: { classPropertyName: "ngbColumn", publicName: "ngbColumn", isSignal: true, isRequired: true, transformFunction: null }, sticky: { classPropertyName: "sticky", publicName: "sticky", isSignal: true, isRequired: false, transformFunction: null } }, queries: [{ propertyName: "cells", first: true, predicate: NgbCellDef, descendants: true, read: TemplateRef, isSignal: true }, { propertyName: "heads", first: true, predicate: NgbHeadDef, descendants: true, read: TemplateRef, isSignal: true }], ngImport: i0 }); }
40
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: NgbColumn, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
41
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.2.0", version: "21.1.0", type: NgbColumn, isStandalone: true, selector: "[ngbColumn]", inputs: { ngbColumn: { classPropertyName: "ngbColumn", publicName: "ngbColumn", isSignal: true, isRequired: true, transformFunction: null }, sticky: { classPropertyName: "sticky", publicName: "sticky", isSignal: true, isRequired: false, transformFunction: null } }, queries: [{ propertyName: "cells", first: true, predicate: NgbCellDef, descendants: true, read: TemplateRef, isSignal: true }, { propertyName: "heads", first: true, predicate: NgbHeadDef, descendants: true, read: TemplateRef, isSignal: true }], ngImport: i0 }); }
41
42
  }
42
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0", ngImport: i0, type: NgbColumn, decorators: [{
43
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: NgbColumn, decorators: [{
43
44
  type: Directive,
44
45
  args: [{
45
46
  selector: '[ngbColumn]',
46
47
  }]
47
- }] });
48
+ }], propDecorators: { ngbColumn: [{ type: i0.Input, args: [{ isSignal: true, alias: "ngbColumn", required: true }] }], sticky: [{ type: i0.Input, args: [{ isSignal: true, alias: "sticky", required: false }] }], cells: [{ type: i0.ContentChild, args: [i0.forwardRef(() => NgbCellDef), { ...{ read: TemplateRef }, isSignal: true }] }], heads: [{ type: i0.ContentChild, args: [i0.forwardRef(() => NgbHeadDef), { ...{ read: TemplateRef }, isSignal: true }] }] } });
48
49
 
49
50
  class NgbCell {
50
51
  constructor() {
51
52
  this.column = inject(NgbColumn);
52
53
  }
53
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.0", ngImport: i0, type: NgbCell, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
54
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.2.0", type: NgbCell, isStandalone: true, selector: "[ngbCell]", host: { properties: { "class": "column.sticky() === 'start' ? 'sticky left-0 border-r z-10' : column.sticky() === 'end' ? 'sticky right-0 border-l z-10' : ''" } }, ngImport: i0 }); }
54
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: NgbCell, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
55
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.1.0", type: NgbCell, isStandalone: true, selector: "[ngbCell]", host: { properties: { "class": "column.sticky() === 'start' ? 'sticky left-0 border-r z-10' : column.sticky() === 'end' ? 'sticky right-0 border-l z-10' : ''" } }, ngImport: i0 }); }
55
56
  }
56
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0", ngImport: i0, type: NgbCell, decorators: [{
57
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: NgbCell, decorators: [{
57
58
  type: Directive,
58
59
  args: [{
59
60
  selector: '[ngbCell]',
@@ -63,10 +64,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0", ngImpor
63
64
  }]
64
65
  }] });
65
66
  class NgbCellDef {
66
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.0", ngImport: i0, type: NgbCellDef, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
67
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.2.0", type: NgbCellDef, isStandalone: true, selector: "[ngbCellDef]", ngImport: i0 }); }
67
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: NgbCellDef, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
68
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.1.0", type: NgbCellDef, isStandalone: true, selector: "[ngbCellDef]", ngImport: i0 }); }
68
69
  }
69
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0", ngImport: i0, type: NgbCellDef, decorators: [{
70
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: NgbCellDef, decorators: [{
70
71
  type: Directive,
71
72
  args: [{
72
73
  selector: '[ngbCellDef]',
@@ -78,15 +79,15 @@ class NgbHeadRowDef {
78
79
  this.ngbHeadRowDef = input.required(...(ngDevMode ? [{ debugName: "ngbHeadRowDef" }] : []));
79
80
  this.ngbHeadRowDefSticky = input(...(ngDevMode ? [undefined, { debugName: "ngbHeadRowDefSticky" }] : []));
80
81
  }
81
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.0", ngImport: i0, type: NgbHeadRowDef, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
82
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.2.0", type: NgbHeadRowDef, isStandalone: true, selector: "[ngbHeadRowDef]", inputs: { ngbHeadRowDef: { classPropertyName: "ngbHeadRowDef", publicName: "ngbHeadRowDef", isSignal: true, isRequired: true, transformFunction: null }, ngbHeadRowDefSticky: { classPropertyName: "ngbHeadRowDefSticky", publicName: "ngbHeadRowDefSticky", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0 }); }
82
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: NgbHeadRowDef, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
83
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.1.0", type: NgbHeadRowDef, isStandalone: true, selector: "[ngbHeadRowDef]", inputs: { ngbHeadRowDef: { classPropertyName: "ngbHeadRowDef", publicName: "ngbHeadRowDef", isSignal: true, isRequired: true, transformFunction: null }, ngbHeadRowDefSticky: { classPropertyName: "ngbHeadRowDefSticky", publicName: "ngbHeadRowDefSticky", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0 }); }
83
84
  }
84
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0", ngImport: i0, type: NgbHeadRowDef, decorators: [{
85
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: NgbHeadRowDef, decorators: [{
85
86
  type: Directive,
86
87
  args: [{
87
88
  selector: '[ngbHeadRowDef]',
88
89
  }]
89
- }] });
90
+ }], propDecorators: { ngbHeadRowDef: [{ type: i0.Input, args: [{ isSignal: true, alias: "ngbHeadRowDef", required: true }] }], ngbHeadRowDefSticky: [{ type: i0.Input, args: [{ isSignal: true, alias: "ngbHeadRowDefSticky", required: false }] }] } });
90
91
  class NgbHeadRow {
91
92
  constructor() {
92
93
  this.headDef = inject(NgbHeadRowDef);
@@ -131,10 +132,10 @@ class NgbHeadRow {
131
132
  ngOnDestroy() {
132
133
  this.container().clear();
133
134
  }
134
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.0", ngImport: i0, type: NgbHeadRow, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
135
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.2.0", version: "20.2.0", type: NgbHeadRow, isStandalone: true, selector: "[ngbHeadRow]", host: { properties: { "attr.data-sticky": "headDef.ngbHeadRowDefSticky() || undefined" } }, viewQueries: [{ propertyName: "container", first: true, predicate: ["container"], descendants: true, read: ViewContainerRef, isSignal: true }], ngImport: i0 }); }
135
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: NgbHeadRow, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
136
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.2.0", version: "21.1.0", type: NgbHeadRow, isStandalone: true, selector: "[ngbHeadRow]", host: { properties: { "attr.data-sticky": "headDef.ngbHeadRowDefSticky() || undefined" } }, viewQueries: [{ propertyName: "container", first: true, predicate: ["container"], descendants: true, read: ViewContainerRef, isSignal: true }], ngImport: i0 }); }
136
137
  }
137
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0", ngImport: i0, type: NgbHeadRow, decorators: [{
138
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: NgbHeadRow, decorators: [{
138
139
  type: Directive,
139
140
  args: [{
140
141
  selector: '[ngbHeadRow]',
@@ -142,26 +143,160 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0", ngImpor
142
143
  '[attr.data-sticky]': 'headDef.ngbHeadRowDefSticky() || undefined',
143
144
  },
144
145
  }]
145
- }], ctorParameters: () => [] });
146
+ }], ctorParameters: () => [], propDecorators: { container: [{ type: i0.ViewChild, args: ['container', { ...{ read: ViewContainerRef }, isSignal: true }] }] } });
146
147
  function aliasHeadRow(headRow) {
147
148
  return { provide: NgbHeadRow, useExisting: headRow };
148
149
  }
149
150
 
151
+ /**
152
+ * Cache for storing and reusing table row views during virtual scrolling.
153
+ * Dramatically improves performance by avoiding view destruction/recreation.
154
+ */
155
+ class ViewCache {
156
+ /**
157
+ * @param maxSize Maximum number of views to cache (default: 100)
158
+ */
159
+ constructor(maxSize = 100) {
160
+ this.maxSize = maxSize;
161
+ this.cache = new Map();
162
+ this.previousDataReference = null;
163
+ }
164
+ /**
165
+ * Get cached views for a specific trackBy ID.
166
+ * @param trackById The trackBy identifier
167
+ * @returns Array of cached views, or undefined if not found
168
+ */
169
+ get(trackById) {
170
+ return this.cache.get(trackById);
171
+ }
172
+ /**
173
+ * Store views in the cache for a specific trackBy ID.
174
+ * @param trackById The trackBy identifier
175
+ * @param views Array of views to cache
176
+ */
177
+ set(trackById, views) {
178
+ this.cache.set(trackById, views);
179
+ }
180
+ /**
181
+ * Add a single view to the cache for a specific trackBy ID.
182
+ * @param trackById The trackBy identifier
183
+ * @param view The view to add
184
+ * @returns true if view was cached, false if cache size limit reached
185
+ */
186
+ add(trackById, view) {
187
+ if (this.isFull()) {
188
+ return false;
189
+ }
190
+ let views = this.cache.get(trackById);
191
+ if (!views) {
192
+ views = [];
193
+ this.cache.set(trackById, views);
194
+ }
195
+ views.push(view);
196
+ return true;
197
+ }
198
+ /**
199
+ * Remove views from cache for a specific trackBy ID.
200
+ * @param trackById The trackBy identifier
201
+ * @param count Number of views to remove (default: all)
202
+ * @returns Array of removed views
203
+ */
204
+ remove(trackById, count) {
205
+ const views = this.cache.get(trackById);
206
+ if (!views) {
207
+ return [];
208
+ }
209
+ const removed = count !== undefined ? views.splice(0, count) : views.splice(0);
210
+ // Clean up empty cache entry
211
+ if (views.length === 0) {
212
+ this.cache.delete(trackById);
213
+ }
214
+ return removed;
215
+ }
216
+ /**
217
+ * Check if cache has reached its size limit.
218
+ */
219
+ isFull() {
220
+ return this.size() >= this.maxSize;
221
+ }
222
+ /**
223
+ * Get total number of cached views across all trackBy IDs.
224
+ */
225
+ size() {
226
+ return Array.from(this.cache.values()).reduce((sum, views) => sum + views.length, 0);
227
+ }
228
+ /**
229
+ * Clear cache when data reference changes.
230
+ * Destroys all cached views to prevent stale data.
231
+ * @param newDataReference New data array reference
232
+ */
233
+ invalidateOnDataChange(newDataReference) {
234
+ if (this.previousDataReference !== newDataReference) {
235
+ this.destroyAll();
236
+ this.previousDataReference = newDataReference;
237
+ }
238
+ }
239
+ /**
240
+ * Destroy all cached views and clear the cache.
241
+ */
242
+ destroyAll() {
243
+ this.cache.forEach(views => views.forEach(view => view.destroy()));
244
+ this.cache.clear();
245
+ }
246
+ /**
247
+ * Delete a specific cache entry without destroying views.
248
+ * Useful when views are being reused.
249
+ * @param trackById The trackBy identifier
250
+ */
251
+ delete(trackById) {
252
+ this.cache.delete(trackById);
253
+ }
254
+ }
255
+
150
256
  const TABLE_ROW_DATA = new InjectionToken('TABLE_ROW_DATA');
257
+ /**
258
+ * Plugin priority levels for controlling execution order.
259
+ * Higher priority plugins execute first.
260
+ */
261
+ var PluginPriority;
262
+ (function (PluginPriority) {
263
+ /** Search and filter operations (highest priority) */
264
+ PluginPriority[PluginPriority["FILTER"] = 100] = "FILTER";
265
+ /** Data transformation operations (group, aggregate, etc.) */
266
+ PluginPriority[PluginPriority["TRANSFORM"] = 50] = "TRANSFORM";
267
+ /** Sorting operations */
268
+ PluginPriority[PluginPriority["SORT"] = 10] = "SORT";
269
+ /** View operations (virtual scroll, pagination) (lowest priority) */
270
+ PluginPriority[PluginPriority["VIEW"] = 0] = "VIEW";
271
+ })(PluginPriority || (PluginPriority = {}));
151
272
  class NgbTable {
152
273
  constructor() {
153
274
  this.injector = inject(Injector);
154
275
  this.differs = inject(IterableDiffers);
155
276
  this.thead = viewChild.required('thead', { read: ViewContainerRef });
156
277
  this.tbody = viewChild.required('tbody', { read: ViewContainerRef });
157
- this.bodyRowDef = contentChildren(NgbBodyRowDef, ...(ngDevMode ? [{ debugName: "bodyRowDef", read: TemplateRef }] : [{ read: TemplateRef }]));
278
+ this.bodyRowDef = contentChildren(NgbBodyRowDef, { ...(ngDevMode ? { debugName: "bodyRowDef" } : {}), read: TemplateRef });
158
279
  this.headRowDef = contentChild.required(NgbHeadRowDef, { read: TemplateRef });
159
280
  this.columns = contentChildren(NgbColumn, ...(ngDevMode ? [{ debugName: "columns" }] : []));
160
- this.plugins = signal(new Set(), ...(ngDevMode ? [{ debugName: "plugins" }] : []));
281
+ this._plugins = new Map();
282
+ this._pluginVersion = signal(0, ...(ngDevMode ? [{ debugName: "_pluginVersion" }] : []));
283
+ this._pluginOrder = 0;
284
+ // View caching for performance
285
+ this._viewCache = new ViewCache(100);
161
286
  this.data = input.required(...(ngDevMode ? [{ debugName: "data" }] : []));
162
287
  this.trackBy = input((_, item) => item, ...(ngDevMode ? [{ debugName: "trackBy" }] : []));
163
288
  this.pluggedData = computed(() => {
164
- return Array.from(this.plugins()).reduce((acc, plugin) => plugin(acc), this.data());
289
+ // Trigger recomputation when plugins change
290
+ this._pluginVersion();
291
+ const originalData = this.data();
292
+ // Sort plugins by priority (descending) then by insertion order (ascending)
293
+ const sortedPlugins = Array.from(this._plugins.values()).sort((a, b) => {
294
+ if (b.priority !== a.priority) {
295
+ return b.priority - a.priority; // Higher priority first
296
+ }
297
+ return a.order - b.order; // Earlier registration first
298
+ });
299
+ return sortedPlugins.reduce((acc, { fn }) => fn(acc, originalData), originalData);
165
300
  }, ...(ngDevMode ? [{ debugName: "pluggedData" }] : []));
166
301
  this._values = new WeakMap();
167
302
  effect(cleanup => {
@@ -176,7 +311,12 @@ class NgbTable {
176
311
  const tbody = this.tbody();
177
312
  const bodyRowDefs = this.bodyRowDef();
178
313
  const data = this.pluggedData();
179
- this._dataDiffers ??= this.differs.find([]).create(this.trackBy());
314
+ const originalData = this.data();
315
+ const trackByFn = this.trackBy();
316
+ // Clear cache only when original data reference changes
317
+ // This avoids expensive validation loops on every scroll
318
+ this._viewCache.invalidateOnDataChange(originalData);
319
+ this._dataDiffers ??= this.differs.find([]).create(trackByFn);
180
320
  const changes = this._dataDiffers?.diff(data);
181
321
  if (!changes) {
182
322
  return;
@@ -184,24 +324,56 @@ class NgbTable {
184
324
  const len = bodyRowDefs.length;
185
325
  changes.forEachOperation((item, adjustedPreviousIndex, currentIndex) => {
186
326
  if (item.previousIndex == null) {
187
- const value = item.item;
188
- const data = signal(value, ...(ngDevMode ? [{ debugName: "data" }] : []));
189
- const injector = Injector.create({
190
- providers: [{ provide: TABLE_ROW_DATA, useValue: data }],
191
- parent: this.injector,
192
- });
193
- const i = currentIndex * len;
194
- for (let j = 0; j < len; j++) {
195
- const ref = tbody.createEmbeddedView(bodyRowDefs[j], { $implicit: value, _data: data }, { injector, index: i + j });
196
- this._values.set(ref, item.item);
327
+ // Item entering visible range - check cache first
328
+ const trackById = trackByFn(0, item.item);
329
+ const reusedViews = this._viewCache.remove(trackById, len);
330
+ if (reusedViews.length >= len) {
331
+ // Reuse cached views
332
+ const i = currentIndex * len;
333
+ reusedViews.forEach((ref, j) => {
334
+ // Update context with new data
335
+ ref.context.$implicit = item.item;
336
+ ref.context._data.set(item.item);
337
+ ref.markForCheck();
338
+ // Reattach to tbody at correct position
339
+ tbody.insert(ref, i + j);
340
+ });
341
+ }
342
+ else {
343
+ // Create new views
344
+ const value = item.item;
345
+ const data = signal(value, ...(ngDevMode ? [{ debugName: "data" }] : []));
346
+ const injector = Injector.create({
347
+ providers: [{ provide: TABLE_ROW_DATA, useValue: data }],
348
+ parent: this.injector,
349
+ });
350
+ const i = currentIndex * len;
351
+ for (let j = 0; j < len; j++) {
352
+ const ref = tbody.createEmbeddedView(bodyRowDefs[j], { $implicit: value, _data: data }, { injector, index: i + j });
353
+ this._values.set(ref, item.item);
354
+ }
197
355
  }
198
356
  }
199
357
  else if (currentIndex == null) {
200
- for (let i = 0; i < len; i++) {
201
- const ref = tbody.get(adjustedPreviousIndex * len);
202
- ref?.destroy();
358
+ // Item leaving visible range - cache instead of destroy
359
+ const trackById = trackByFn(0, item.item);
360
+ if (!this._viewCache.isFull()) {
361
+ // Cache the views (detach without destroying)
362
+ for (let i = 0; i < len; i++) {
363
+ const viewIndex = adjustedPreviousIndex * len;
364
+ const ref = tbody.detach(viewIndex);
365
+ if (ref) {
366
+ this._viewCache.add(trackById, ref);
367
+ }
368
+ }
369
+ }
370
+ else {
371
+ // Cache full - destroy views
372
+ for (let i = 0; i < len; i++) {
373
+ const ref = tbody.get(adjustedPreviousIndex * len);
374
+ ref?.destroy();
375
+ }
203
376
  }
204
- // tbody.remove(adjustedPreviousIndex!);
205
377
  }
206
378
  else {
207
379
  // based on current and previous index we need to check whether we need to do 1 or -1
@@ -235,15 +407,41 @@ class NgbTable {
235
407
  context.index = renderIndex;
236
408
  }
237
409
  }
238
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.0", ngImport: i0, type: NgbTable, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
239
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.2.0", version: "20.2.0", type: NgbTable, isStandalone: true, selector: "table[ngbTable]", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: true, transformFunction: null }, trackBy: { classPropertyName: "trackBy", publicName: "trackBy", isSignal: true, isRequired: false, transformFunction: null } }, queries: [{ propertyName: "bodyRowDef", predicate: NgbBodyRowDef, read: TemplateRef, isSignal: true }, { propertyName: "headRowDef", first: true, predicate: NgbHeadRowDef, descendants: true, read: TemplateRef, isSignal: true }, { propertyName: "columns", predicate: NgbColumn, isSignal: true }], viewQueries: [{ propertyName: "thead", first: true, predicate: ["thead"], descendants: true, read: ViewContainerRef, isSignal: true }, { propertyName: "tbody", first: true, predicate: ["tbody"], descendants: true, read: ViewContainerRef, isSignal: true }], ngImport: i0 }); }
410
+ /**
411
+ * Register a plugin to transform table data.
412
+ * Plugins receive both the current data and the original data.
413
+ * @param plugin Function that transforms data
414
+ * @param priority Plugin priority (higher values execute first). Use PluginPriority enum values.
415
+ * @returns Symbol key to unregister the plugin later
416
+ */
417
+ registerPlugin(plugin, priority = PluginPriority.VIEW) {
418
+ const key = Symbol('plugin');
419
+ this._plugins.set(key, {
420
+ fn: plugin,
421
+ priority,
422
+ order: this._pluginOrder++,
423
+ });
424
+ this._pluginVersion.update(v => v + 1);
425
+ return key;
426
+ }
427
+ /**
428
+ * Unregister a previously registered plugin.
429
+ * @param key Symbol returned from registerPlugin
430
+ */
431
+ unregisterPlugin(key) {
432
+ if (this._plugins.delete(key)) {
433
+ this._pluginVersion.update(v => v - 1);
434
+ }
435
+ }
436
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: NgbTable, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
437
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.2.0", version: "21.1.0", type: NgbTable, isStandalone: true, selector: "table[ngbTable]", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: true, transformFunction: null }, trackBy: { classPropertyName: "trackBy", publicName: "trackBy", isSignal: true, isRequired: false, transformFunction: null } }, queries: [{ propertyName: "bodyRowDef", predicate: NgbBodyRowDef, read: TemplateRef, isSignal: true }, { propertyName: "headRowDef", first: true, predicate: NgbHeadRowDef, descendants: true, read: TemplateRef, isSignal: true }, { propertyName: "columns", predicate: NgbColumn, isSignal: true }], viewQueries: [{ propertyName: "thead", first: true, predicate: ["thead"], descendants: true, read: ViewContainerRef, isSignal: true }, { propertyName: "tbody", first: true, predicate: ["tbody"], descendants: true, read: ViewContainerRef, isSignal: true }], ngImport: i0 }); }
240
438
  }
241
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0", ngImport: i0, type: NgbTable, decorators: [{
439
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: NgbTable, decorators: [{
242
440
  type: Directive,
243
441
  args: [{
244
442
  selector: 'table[ngbTable]',
245
443
  }]
246
- }], ctorParameters: () => [] });
444
+ }], ctorParameters: () => [], propDecorators: { thead: [{ type: i0.ViewChild, args: ['thead', { ...{ read: ViewContainerRef }, isSignal: true }] }], tbody: [{ type: i0.ViewChild, args: ['tbody', { ...{ read: ViewContainerRef }, isSignal: true }] }], bodyRowDef: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => NgbBodyRowDef), { ...{ read: TemplateRef }, isSignal: true }] }], headRowDef: [{ type: i0.ContentChild, args: [i0.forwardRef(() => NgbHeadRowDef), { ...{ read: TemplateRef }, isSignal: true }] }], columns: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => NgbColumn), { isSignal: true }] }], data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: true }] }], trackBy: [{ type: i0.Input, args: [{ isSignal: true, alias: "trackBy", required: false }] }] } });
247
445
  function aliasTable(table) {
248
446
  return { provide: NgbTable, useExisting: table };
249
447
  }
@@ -258,13 +456,13 @@ class NgbBodyRowDef {
258
456
  constructor() {
259
457
  this.ngbBodyRowDefColumns = input.required(...(ngDevMode ? [{ debugName: "ngbBodyRowDefColumns" }] : []));
260
458
  }
261
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.0", ngImport: i0, type: NgbBodyRowDef, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
262
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.2.0", type: NgbBodyRowDef, isStandalone: true, selector: "[ngbBodyRowDef]", inputs: { ngbBodyRowDefColumns: { classPropertyName: "ngbBodyRowDefColumns", publicName: "ngbBodyRowDefColumns", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0 }); }
459
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: NgbBodyRowDef, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
460
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.1.0", type: NgbBodyRowDef, isStandalone: true, selector: "[ngbBodyRowDef]", inputs: { ngbBodyRowDefColumns: { classPropertyName: "ngbBodyRowDefColumns", publicName: "ngbBodyRowDefColumns", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0 }); }
263
461
  }
264
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0", ngImport: i0, type: NgbBodyRowDef, decorators: [{
462
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: NgbBodyRowDef, decorators: [{
265
463
  type: Directive,
266
464
  args: [{ selector: '[ngbBodyRowDef]' }]
267
- }] });
465
+ }], propDecorators: { ngbBodyRowDefColumns: [{ type: i0.Input, args: [{ isSignal: true, alias: "ngbBodyRowDefColumns", required: true }] }] } });
268
466
  class NgbBodyRow {
269
467
  constructor() {
270
468
  this.rowData = inject(TABLE_ROW_DATA);
@@ -282,13 +480,14 @@ class NgbBodyRow {
282
480
  return indexA - indexB;
283
481
  });
284
482
  }, ...(ngDevMode ? [{ debugName: "sortedColumns" }] : []));
483
+ // Effect 1: Manage column creation/movement/removal (runs when columns change)
285
484
  effect(() => {
286
- const data = this.rowData();
287
485
  const columns = this.sortedColumns();
288
486
  const cols = this.rowDef.ngbBodyRowDefColumns();
289
487
  columns.forEach(row => {
290
488
  const index = cols.indexOf(row.ngbColumn());
291
489
  if (index === -1) {
490
+ // Remove column view
292
491
  const ref = this.ref.get(row);
293
492
  if (ref) {
294
493
  ref.destroy();
@@ -298,33 +497,42 @@ class NgbBodyRow {
298
497
  }
299
498
  let ref = this.ref.get(row);
300
499
  if (ref) {
301
- // move the row to the new index
500
+ // Move existing column to new index
302
501
  this.container().move(ref, index);
303
- ref.context.$implicit = data;
304
- ref.markForCheck();
305
502
  return;
306
503
  }
504
+ // Create new column view with current data
307
505
  ref = untracked(() => {
308
- // maintain the order of the columns
506
+ const data = this.rowData();
309
507
  return this.container().createEmbeddedView(row.cells(), { $implicit: data }, { index });
310
508
  });
311
509
  this.ref.set(row, ref);
312
510
  });
313
511
  });
512
+ // Effect 2: Update data in all existing column views (runs when data changes)
513
+ // This is lightweight and only updates the $implicit reference without touching DOM
514
+ effect(() => {
515
+ const data = this.rowData();
516
+ // Update $implicit for all existing column views
517
+ this.ref.forEach(ref => {
518
+ ref.context.$implicit = data;
519
+ ref.markForCheck();
520
+ });
521
+ });
314
522
  }
315
523
  ngOnDestroy() {
316
524
  this.container().clear();
317
525
  this.ref.clear();
318
526
  }
319
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.0", ngImport: i0, type: NgbBodyRow, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
320
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.2.0", version: "20.2.0", type: NgbBodyRow, isStandalone: true, selector: "[ngbBodyRow]", viewQueries: [{ propertyName: "container", first: true, predicate: ["container"], descendants: true, read: ViewContainerRef, isSignal: true }], ngImport: i0 }); }
527
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: NgbBodyRow, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
528
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.2.0", version: "21.1.0", type: NgbBodyRow, isStandalone: true, selector: "[ngbBodyRow]", viewQueries: [{ propertyName: "container", first: true, predicate: ["container"], descendants: true, read: ViewContainerRef, isSignal: true }], ngImport: i0 }); }
321
529
  }
322
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0", ngImport: i0, type: NgbBodyRow, decorators: [{
530
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: NgbBodyRow, decorators: [{
323
531
  type: Directive,
324
532
  args: [{
325
533
  selector: '[ngbBodyRow]',
326
534
  }]
327
- }], ctorParameters: () => [] });
535
+ }], ctorParameters: () => [], propDecorators: { container: [{ type: i0.ViewChild, args: ['container', { ...{ read: ViewContainerRef }, isSignal: true }] }] } });
328
536
  function aliasBodyRow(row) {
329
537
  return { provide: NgbBodyRow, useExisting: row };
330
538
  }
@@ -332,6 +540,7 @@ function aliasBodyRow(row) {
332
540
  class NgbSort {
333
541
  constructor() {
334
542
  this.table = inject(NgbTable);
543
+ this.destroyRef = inject(DestroyRef);
335
544
  this.sortFn = input(...(ngDevMode ? [undefined, { debugName: "sortFn" }] : []));
336
545
  this.disableClear = input(false, ...(ngDevMode ? [{ debugName: "disableClear" }] : []));
337
546
  this.sortColumn = model('', ...(ngDevMode ? [{ debugName: "sortColumn" }] : []));
@@ -352,19 +561,21 @@ class NgbSort {
352
561
  return direction === 'asc' ? comparison : -comparison;
353
562
  });
354
563
  };
355
- effect(cleanup => {
356
- if (this.sortMode() === 'client') {
357
- const sortFn = untracked(() => this.sortFn() || this.defaultSortFn);
358
- const fn = (data) => {
359
- const direction = this.sortDirection();
360
- const column = this.sortColumn();
361
- return direction && column ? sortFn(data, column, direction) : data;
362
- };
363
- this.table.plugins.update(plugins => new Set([...plugins, fn]));
364
- cleanup(() => {
365
- this.table.plugins.update(plugins => new Set([...plugins].filter(plugin => plugin !== fn)));
366
- });
564
+ const sortFn = untracked(() => this.sortFn() || this.defaultSortFn);
565
+ // Register plugin once with SORT priority - it will reactively read signals when executed
566
+ this.pluginKey = this.table.registerPlugin(data => {
567
+ // Only sort in client mode
568
+ if (this.sortMode() !== 'client') {
569
+ return data;
367
570
  }
571
+ // Read sort signals reactively
572
+ const direction = this.sortDirection();
573
+ const column = this.sortColumn();
574
+ return direction && column ? sortFn(data, column, direction) : data;
575
+ }, PluginPriority.SORT);
576
+ // Cleanup on destroy
577
+ this.destroyRef.onDestroy(() => {
578
+ this.table.unregisterPlugin(this.pluginKey);
368
579
  });
369
580
  }
370
581
  sort(column, direction) {
@@ -407,16 +618,16 @@ class NgbSort {
407
618
  direction: newDirection,
408
619
  });
409
620
  }
410
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.0", ngImport: i0, type: NgbSort, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
411
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.2.0", type: NgbSort, isStandalone: true, selector: "[ngbSort]", inputs: { sortFn: { classPropertyName: "sortFn", publicName: "sortFn", isSignal: true, isRequired: false, transformFunction: null }, disableClear: { classPropertyName: "disableClear", publicName: "disableClear", isSignal: true, isRequired: false, transformFunction: null }, sortColumn: { classPropertyName: "sortColumn", publicName: "sortColumn", isSignal: true, isRequired: false, transformFunction: null }, sortDirection: { classPropertyName: "sortDirection", publicName: "sortDirection", isSignal: true, isRequired: false, transformFunction: null }, sortMode: { classPropertyName: "sortMode", publicName: "sortMode", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { sortColumn: "sortColumnChange", sortDirection: "sortDirectionChange", sortChange: "sortChange" }, exportAs: ["ngbSort"], ngImport: i0 }); }
621
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: NgbSort, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
622
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.1.0", type: NgbSort, isStandalone: true, selector: "[ngbSort]", inputs: { sortFn: { classPropertyName: "sortFn", publicName: "sortFn", isSignal: true, isRequired: false, transformFunction: null }, disableClear: { classPropertyName: "disableClear", publicName: "disableClear", isSignal: true, isRequired: false, transformFunction: null }, sortColumn: { classPropertyName: "sortColumn", publicName: "sortColumn", isSignal: true, isRequired: false, transformFunction: null }, sortDirection: { classPropertyName: "sortDirection", publicName: "sortDirection", isSignal: true, isRequired: false, transformFunction: null }, sortMode: { classPropertyName: "sortMode", publicName: "sortMode", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { sortColumn: "sortColumnChange", sortDirection: "sortDirectionChange", sortChange: "sortChange" }, exportAs: ["ngbSort"], ngImport: i0 }); }
412
623
  }
413
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0", ngImport: i0, type: NgbSort, decorators: [{
624
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: NgbSort, decorators: [{
414
625
  type: Directive,
415
626
  args: [{
416
627
  selector: '[ngbSort]',
417
628
  exportAs: 'ngbSort',
418
629
  }]
419
- }], ctorParameters: () => [] });
630
+ }], ctorParameters: () => [], propDecorators: { sortFn: [{ type: i0.Input, args: [{ isSignal: true, alias: "sortFn", required: false }] }], disableClear: [{ type: i0.Input, args: [{ isSignal: true, alias: "disableClear", required: false }] }], sortColumn: [{ type: i0.Input, args: [{ isSignal: true, alias: "sortColumn", required: false }] }, { type: i0.Output, args: ["sortColumnChange"] }], sortDirection: [{ type: i0.Input, args: [{ isSignal: true, alias: "sortDirection", required: false }] }, { type: i0.Output, args: ["sortDirectionChange"] }], sortMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "sortMode", required: false }] }], sortChange: [{ type: i0.Output, args: ["sortChange"] }] } });
420
631
  class NgbSortHeader {
421
632
  constructor() {
422
633
  this.sort = inject(NgbSort);
@@ -434,10 +645,10 @@ class NgbSortHeader {
434
645
  toggle() {
435
646
  this.sort.sort(this.column.ngbColumn(), this.sortDirection() === 'asc' ? 'desc' : this.sortDirection() === 'desc' ? '' : 'asc');
436
647
  }
437
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.2.0", ngImport: i0, type: NgbSortHeader, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
438
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.2.0", type: NgbSortHeader, isStandalone: true, selector: "[ngbSortHeader]", inputs: { disableClear: { classPropertyName: "disableClear", publicName: "disableClear", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "attr.aria-sort": "sortDirection()" } }, ngImport: i0 }); }
648
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: NgbSortHeader, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
649
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.1.0", type: NgbSortHeader, isStandalone: true, selector: "[ngbSortHeader]", inputs: { disableClear: { classPropertyName: "disableClear", publicName: "disableClear", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "attr.aria-sort": "sortDirection()" } }, ngImport: i0 }); }
439
650
  }
440
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0", ngImport: i0, type: NgbSortHeader, decorators: [{
651
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: NgbSortHeader, decorators: [{
441
652
  type: Directive,
442
653
  args: [{
443
654
  selector: '[ngbSortHeader]',
@@ -445,7 +656,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.2.0", ngImpor
445
656
  '[attr.aria-sort]': 'sortDirection()',
446
657
  },
447
658
  }]
448
- }] });
659
+ }], propDecorators: { disableClear: [{ type: i0.Input, args: [{ isSignal: true, alias: "disableClear", required: false }] }] } });
449
660
  function aliasSort(directive) {
450
661
  return { provide: NgbSort, useExisting: directive };
451
662
  }
@@ -453,9 +664,296 @@ function aliasSortHeader(directive) {
453
664
  return { provide: NgbSortHeader, useExisting: directive };
454
665
  }
455
666
 
667
+ /**
668
+ * Virtual scroll directive for tables that only renders visible rows.
669
+ * Dramatically improves performance for large datasets by rendering only
670
+ * rows that are visible in the viewport plus a small buffer.
671
+ *
672
+ * @example
673
+ * ```html
674
+ * <div class="h-[600px] overflow-auto">
675
+ * <table
676
+ * ngbTable
677
+ * [data]="largeDataset"
678
+ * ngbVirtualScroll="50">
679
+ * <!-- table definition -->
680
+ * </table>
681
+ * </div>
682
+ * ```
683
+ */
684
+ class NgbTableVirtualScroll {
685
+ // ====== CONSTRUCTOR & INITIALIZATION ======
686
+ constructor() {
687
+ // ====== INPUTS ======
688
+ /**
689
+ * Height of each row in pixels (required).
690
+ * Must be consistent across all rows for proper virtual scrolling.
691
+ */
692
+ this.rowHeight = input.required({ ...(ngDevMode ? { debugName: "rowHeight" } : {}), alias: 'ngbVirtualScroll',
693
+ transform: (value) => Math.max(1, value) });
694
+ /**
695
+ * Number of extra rows to render beyond the visible viewport.
696
+ * Higher values provide smoother scrolling but render more rows.
697
+ * @default 5
698
+ */
699
+ this.bufferSize = input(5, { ...(ngDevMode ? { debugName: "bufferSize" } : {}), transform: (value) => Math.max(0, value) });
700
+ /**
701
+ * Optional custom scroll container element.
702
+ * If not provided, will find or create a scroll container.
703
+ */
704
+ this.scrollContainer = input(null, ...(ngDevMode ? [{ debugName: "scrollContainer" }] : []));
705
+ // ====== DEPENDENCIES ======
706
+ this.table = inject(NgbTable);
707
+ this.elementRef = inject(ElementRef);
708
+ this.renderer = inject(Renderer2);
709
+ this.destroyRef = inject(DestroyRef);
710
+ // ====== STATE SIGNALS ======
711
+ this.scrollTop = signal(0, ...(ngDevMode ? [{ debugName: "scrollTop" }] : []));
712
+ this.viewportHeight = signal(0, ...(ngDevMode ? [{ debugName: "viewportHeight" }] : []));
713
+ this.totalDataLength = signal(0, ...(ngDevMode ? [{ debugName: "totalDataLength" }] : []));
714
+ this.scrollContainerElement = signal(null, ...(ngDevMode ? [{ debugName: "scrollContainerElement" }] : []));
715
+ this.isInitialized = signal(false, ...(ngDevMode ? [{ debugName: "isInitialized" }] : []));
716
+ // DOM element references (set during initialization)
717
+ this.topSpacerRef = null;
718
+ this.bottomSpacerRef = null;
719
+ // ====== COMPUTED VALUES ======
720
+ /**
721
+ * Calculates the range of visible row indices based on scroll position and viewport size.
722
+ */
723
+ this.visibleRange = computed(() => {
724
+ const scroll = this.scrollTop();
725
+ const viewport = this.viewportHeight();
726
+ const rowHeight = this.rowHeight();
727
+ const buffer = this.bufferSize();
728
+ const totalLength = this.totalDataLength();
729
+ if (totalLength === 0 || rowHeight === 0) {
730
+ return { start: 0, end: 0, visibleStart: 0, visibleEnd: 0 };
731
+ }
732
+ // Calculate indices
733
+ const startIndex = Math.floor(scroll / rowHeight);
734
+ const visibleCount = Math.ceil(viewport / rowHeight);
735
+ // Apply buffer
736
+ const bufferedStart = Math.max(0, startIndex - buffer);
737
+ const bufferedEnd = Math.min(totalLength, startIndex + visibleCount + buffer);
738
+ return {
739
+ start: bufferedStart,
740
+ end: bufferedEnd,
741
+ visibleStart: startIndex,
742
+ visibleEnd: Math.min(totalLength, startIndex + visibleCount),
743
+ };
744
+ }, ...(ngDevMode ? [{ debugName: "visibleRange" }] : []));
745
+ /**
746
+ * Total height of all data items (for scrollbar sizing).
747
+ */
748
+ this.totalHeight = computed(() => {
749
+ return this.totalDataLength() * this.rowHeight();
750
+ }, ...(ngDevMode ? [{ debugName: "totalHeight" }] : []));
751
+ /**
752
+ * Vertical offset for virtual positioning.
753
+ */
754
+ this.offsetY = computed(() => {
755
+ const { start } = this.visibleRange();
756
+ return start * this.rowHeight();
757
+ }, ...(ngDevMode ? [{ debugName: "offsetY" }] : []));
758
+ /**
759
+ * Get the currently visible row index range.
760
+ * @returns Object with start and end indices of visible rows
761
+ */
762
+ this.getVisibleRange = computed(() => {
763
+ const { visibleStart, visibleEnd } = this.visibleRange();
764
+ return { start: visibleStart, end: visibleEnd };
765
+ }, ...(ngDevMode ? [{ debugName: "getVisibleRange" }] : []));
766
+ // Register plugin once with VIEW priority (lowest) - it will reactively read signals when executed
767
+ this.pluginKey = this.table.registerPlugin((data, originalData) => {
768
+ // Store total length for scrollbar calculation (untracked to avoid circular dependency)
769
+ untracked(() => this.totalDataLength.set(originalData.length));
770
+ // Get visible range (reactive - reads signals)
771
+ const { start, end } = this.visibleRange();
772
+ // Slice data to visible portion
773
+ return data.slice(start, end);
774
+ }, PluginPriority.VIEW);
775
+ // Wait for next render to ensure DOM is ready
776
+ afterNextRender(() => {
777
+ this.initializeVirtualScroll();
778
+ });
779
+ // Setup spacer updates
780
+ this.setupSpacerUpdates();
781
+ // Setup scroll tracking (only after initialization)
782
+ this.setupScrollTracking();
783
+ // Setup resize tracking (only after initialization)
784
+ this.setupResizeTracking();
785
+ // Cleanup on destroy
786
+ this.destroyRef.onDestroy(() => {
787
+ this.table.unregisterPlugin(this.pluginKey);
788
+ });
789
+ }
790
+ // ====== INITIALIZATION ======
791
+ initializeVirtualScroll() {
792
+ const table = this.elementRef.nativeElement;
793
+ // Find or create scroll container
794
+ const container = this.scrollContainer() || this.findOrCreateScrollContainer(table);
795
+ this.scrollContainerElement.set(container);
796
+ // Setup DOM structure
797
+ // this.setupTableStructure(table);
798
+ // Create spacers
799
+ this.createSpacers(table);
800
+ // Mark as initialized
801
+ this.isInitialized.set(true);
802
+ // Set initial viewport height
803
+ if (container) {
804
+ this.viewportHeight.set(container.clientHeight);
805
+ }
806
+ }
807
+ // ====== DOM STRUCTURE SETUP ======
808
+ findOrCreateScrollContainer(table) {
809
+ // Try to find parent with overflow
810
+ let parent = table.parentElement;
811
+ while (parent) {
812
+ const style = window.getComputedStyle(parent);
813
+ const overflow = style.overflow || style.overflowY;
814
+ if (overflow === 'auto' || overflow === 'scroll') {
815
+ return parent;
816
+ }
817
+ parent = parent.parentElement;
818
+ }
819
+ // If no scroll container found, wrap in one
820
+ const container = this.renderer.createElement('div');
821
+ this.renderer.setStyle(container, 'overflow', 'auto');
822
+ this.renderer.setStyle(container, 'position', 'relative');
823
+ this.renderer.setStyle(container, 'height', '100%');
824
+ const currentParent = table.parentElement;
825
+ if (currentParent) {
826
+ this.renderer.insertBefore(currentParent, container, table);
827
+ this.renderer.removeChild(currentParent, table);
828
+ this.renderer.appendChild(container, table);
829
+ }
830
+ return container;
831
+ }
832
+ // private setupTableStructure(table: HTMLElement) {
833
+ // Ensure tbody and thead display correctly for virtual scrolling
834
+ // const tbody = table.querySelector('tbody');
835
+ // if (tbody) {
836
+ // this.renderer.setStyle(tbody, 'display', 'block');
837
+ // }
838
+ // const thead = table.querySelector('thead');
839
+ // if (thead) {
840
+ // this.renderer.setStyle(thead, 'display', 'block');
841
+ // this.renderer.setStyle(thead, 'position', 'sticky');
842
+ // this.renderer.setStyle(thead, 'top', '0');
843
+ // this.renderer.setStyle(thead, 'z-index', '10');
844
+ // this.renderer.setStyle(thead, 'background', 'inherit');
845
+ // }
846
+ // }
847
+ createSpacers(table) {
848
+ const tbody = table.querySelector('tbody');
849
+ if (!tbody)
850
+ return;
851
+ // Top spacer - creates space for rows scrolled past
852
+ this.topSpacerRef = this.renderer.createElement('tr');
853
+ this.renderer.setStyle(this.topSpacerRef, 'height', '0px');
854
+ // this.renderer.setStyle(this.topSpacerRef, 'display', 'block');
855
+ this.renderer.insertBefore(tbody, this.topSpacerRef, tbody.firstChild);
856
+ // Bottom spacer - creates scrollable space for rows below viewport
857
+ this.bottomSpacerRef = this.renderer.createElement('tr');
858
+ this.renderer.setStyle(this.bottomSpacerRef, 'height', '0px');
859
+ // this.renderer.setStyle(this.bottomSpacerRef, 'display', 'block');
860
+ this.renderer.appendChild(tbody, this.bottomSpacerRef);
861
+ }
862
+ // ====== SPACER UPDATES ======
863
+ setupSpacerUpdates() {
864
+ effect(() => {
865
+ if (!this.isInitialized())
866
+ return;
867
+ const { start } = this.visibleRange();
868
+ const totalLength = this.totalDataLength();
869
+ const { end } = this.visibleRange();
870
+ const rowHeight = this.rowHeight();
871
+ if (!this.topSpacerRef || !this.bottomSpacerRef)
872
+ return;
873
+ // Top spacer height = rows scrolled past
874
+ const topHeight = start * rowHeight;
875
+ this.renderer.setStyle(this.topSpacerRef, 'height', `${topHeight}px`);
876
+ // Bottom spacer height = rows below viewport
877
+ const remainingRows = Math.max(0, totalLength - end);
878
+ const bottomHeight = remainingRows * rowHeight;
879
+ this.renderer.setStyle(this.bottomSpacerRef, 'height', `${bottomHeight}px`);
880
+ });
881
+ }
882
+ // ====== SCROLL TRACKING ======
883
+ setupScrollTracking() {
884
+ effect(onCleanup => {
885
+ const container = this.scrollContainerElement();
886
+ if (!container || !this.isInitialized())
887
+ return;
888
+ // Create scroll observable and convert to signal
889
+ const scroll$ = fromEvent(container, 'scroll').pipe(auditTime(0));
890
+ const subscription = scroll$.subscribe(() => {
891
+ this.scrollTop.set(container.scrollTop);
892
+ });
893
+ onCleanup(() => subscription.unsubscribe());
894
+ });
895
+ }
896
+ // ====== RESIZE TRACKING ======
897
+ setupResizeTracking() {
898
+ effect(onCleanup => {
899
+ const container = this.scrollContainerElement();
900
+ if (!container || !this.isInitialized())
901
+ return;
902
+ const resizeObserver = new ResizeObserver(entries => {
903
+ const entry = entries[0];
904
+ if (entry) {
905
+ this.viewportHeight.set(entry.contentRect.height);
906
+ }
907
+ });
908
+ resizeObserver.observe(container);
909
+ onCleanup(() => resizeObserver.disconnect());
910
+ });
911
+ }
912
+ // ====== PUBLIC API ======
913
+ /**
914
+ * Scroll to a specific row index.
915
+ * @param index The row index to scroll to
916
+ * @param behavior Scroll behavior ('auto' | 'smooth')
917
+ */
918
+ scrollToIndex(index, behavior = 'smooth') {
919
+ const container = this.scrollContainerElement();
920
+ if (!container)
921
+ return;
922
+ const targetScrollTop = index * this.rowHeight();
923
+ container.scrollTo({
924
+ top: targetScrollTop,
925
+ behavior,
926
+ });
927
+ }
928
+ /**
929
+ * Get the total number of rows in the dataset.
930
+ */
931
+ getTotalRows() {
932
+ return this.totalDataLength();
933
+ }
934
+ /**
935
+ * Get the current scroll position.
936
+ */
937
+ getScrollTop() {
938
+ return this.scrollTop();
939
+ }
940
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: NgbTableVirtualScroll, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
941
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.1.0", type: NgbTableVirtualScroll, isStandalone: true, selector: "table[ngbTable][ngbVirtualScroll]", inputs: { rowHeight: { classPropertyName: "rowHeight", publicName: "ngbVirtualScroll", isSignal: true, isRequired: true, transformFunction: null }, bufferSize: { classPropertyName: "bufferSize", publicName: "bufferSize", isSignal: true, isRequired: false, transformFunction: null }, scrollContainer: { classPropertyName: "scrollContainer", publicName: "scrollContainer", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "style.table-layout": "\"fixed\"", "style.width": "\"100%\"" } }, ngImport: i0 }); }
942
+ }
943
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: NgbTableVirtualScroll, decorators: [{
944
+ type: Directive,
945
+ args: [{
946
+ selector: 'table[ngbTable][ngbVirtualScroll]',
947
+ host: {
948
+ '[style.table-layout]': '"fixed"',
949
+ '[style.width]': '"100%"',
950
+ },
951
+ }]
952
+ }], ctorParameters: () => [], propDecorators: { rowHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "ngbVirtualScroll", required: true }] }], bufferSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "bufferSize", required: false }] }], scrollContainer: [{ type: i0.Input, args: [{ isSignal: true, alias: "scrollContainer", required: false }] }] } });
953
+
456
954
  /**
457
955
  * Generated bundle index. Do not edit.
458
956
  */
459
957
 
460
- export { NgbBodyRow, NgbBodyRowDef, NgbCell, NgbCellDef, NgbColumn, NgbHead, NgbHeadDef, NgbHeadRow, NgbHeadRowDef, NgbSort, NgbSortHeader, NgbTable, aliasBodyRow, aliasHeadRow, aliasSort, aliasSortHeader, aliasTable };
958
+ export { NgbBodyRow, NgbBodyRowDef, NgbCell, NgbCellDef, NgbColumn, NgbHead, NgbHeadDef, NgbHeadRow, NgbHeadRowDef, NgbSort, NgbSortHeader, NgbTable, NgbTableVirtualScroll, PluginPriority, aliasBodyRow, aliasHeadRow, aliasSort, aliasSortHeader, aliasTable };
461
959
  //# sourceMappingURL=ngbase-adk-table.mjs.map