@ngbase/adk 0.1.16 → 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.
- package/fesm2022/ngbase-adk-a11y.mjs +42 -42
- package/fesm2022/ngbase-adk-a11y.mjs.map +1 -1
- package/fesm2022/ngbase-adk-accordion.mjs +20 -26
- package/fesm2022/ngbase-adk-accordion.mjs.map +1 -1
- package/fesm2022/ngbase-adk-autocomplete.mjs +11 -11
- package/fesm2022/ngbase-adk-autocomplete.mjs.map +1 -1
- package/fesm2022/ngbase-adk-avatar.mjs +13 -13
- package/fesm2022/ngbase-adk-avatar.mjs.map +1 -1
- package/fesm2022/ngbase-adk-bidi.mjs +3 -3
- package/fesm2022/ngbase-adk-bidi.mjs.map +1 -1
- package/fesm2022/ngbase-adk-breadcrumb.mjs +14 -14
- package/fesm2022/ngbase-adk-breadcrumb.mjs.map +1 -1
- package/fesm2022/ngbase-adk-cache.mjs +3 -3
- package/fesm2022/ngbase-adk-cache.mjs.map +1 -1
- package/fesm2022/ngbase-adk-carousel.mjs +18 -18
- package/fesm2022/ngbase-adk-carousel.mjs.map +1 -1
- package/fesm2022/ngbase-adk-checkbox.mjs +15 -21
- package/fesm2022/ngbase-adk-checkbox.mjs.map +1 -1
- package/fesm2022/ngbase-adk-chip.mjs +12 -12
- package/fesm2022/ngbase-adk-chip.mjs.map +1 -1
- package/fesm2022/ngbase-adk-clipboard.mjs +7 -5
- package/fesm2022/ngbase-adk-clipboard.mjs.map +1 -1
- package/fesm2022/ngbase-adk-collections.mjs.map +1 -1
- package/fesm2022/ngbase-adk-color-picker.mjs +44 -53
- package/fesm2022/ngbase-adk-color-picker.mjs.map +1 -1
- package/fesm2022/ngbase-adk-cookies.mjs +3 -3
- package/fesm2022/ngbase-adk-cookies.mjs.map +1 -1
- package/fesm2022/ngbase-adk-datepicker.mjs +70 -89
- package/fesm2022/ngbase-adk-datepicker.mjs.map +1 -1
- package/fesm2022/ngbase-adk-dialog.mjs +17 -39
- package/fesm2022/ngbase-adk-dialog.mjs.map +1 -1
- package/fesm2022/ngbase-adk-drag.mjs +20 -20
- package/fesm2022/ngbase-adk-drag.mjs.map +1 -1
- package/fesm2022/ngbase-adk-form-field.mjs +65 -118
- package/fesm2022/ngbase-adk-form-field.mjs.map +1 -1
- package/fesm2022/ngbase-adk-hover-card.mjs +5 -5
- package/fesm2022/ngbase-adk-hover-card.mjs.map +1 -1
- package/fesm2022/ngbase-adk-icon.mjs +9 -11
- package/fesm2022/ngbase-adk-icon.mjs.map +1 -1
- package/fesm2022/ngbase-adk-inline-edit.mjs +27 -35
- package/fesm2022/ngbase-adk-inline-edit.mjs.map +1 -1
- package/fesm2022/ngbase-adk-jwt.mjs +319 -41
- package/fesm2022/ngbase-adk-jwt.mjs.map +1 -1
- package/fesm2022/ngbase-adk-keys.mjs +6 -6
- package/fesm2022/ngbase-adk-keys.mjs.map +1 -1
- package/fesm2022/ngbase-adk-layout.mjs.map +1 -1
- package/fesm2022/ngbase-adk-list.mjs +10 -10
- package/fesm2022/ngbase-adk-list.mjs.map +1 -1
- package/fesm2022/ngbase-adk-mask.mjs +8 -8
- package/fesm2022/ngbase-adk-mask.mjs.map +1 -1
- package/fesm2022/ngbase-adk-menu.mjs +69 -79
- package/fesm2022/ngbase-adk-menu.mjs.map +1 -1
- package/fesm2022/ngbase-adk-network.mjs +3 -3
- package/fesm2022/ngbase-adk-network.mjs.map +1 -1
- package/fesm2022/ngbase-adk-otp.mjs +24 -45
- package/fesm2022/ngbase-adk-otp.mjs.map +1 -1
- package/fesm2022/ngbase-adk-pagination.mjs +9 -9
- package/fesm2022/ngbase-adk-pagination.mjs.map +1 -1
- package/fesm2022/ngbase-adk-popover.mjs +120 -89
- package/fesm2022/ngbase-adk-popover.mjs.map +1 -1
- package/fesm2022/ngbase-adk-portal.mjs +134 -47
- package/fesm2022/ngbase-adk-portal.mjs.map +1 -1
- package/fesm2022/ngbase-adk-progress.mjs +7 -7
- package/fesm2022/ngbase-adk-progress.mjs.map +1 -1
- package/fesm2022/ngbase-adk-radio.mjs +20 -27
- package/fesm2022/ngbase-adk-radio.mjs.map +1 -1
- package/fesm2022/ngbase-adk-resizable.mjs +138 -48
- package/fesm2022/ngbase-adk-resizable.mjs.map +1 -1
- package/fesm2022/ngbase-adk-scroll-area.mjs +28 -20
- package/fesm2022/ngbase-adk-scroll-area.mjs.map +1 -1
- package/fesm2022/ngbase-adk-select.mjs +58 -80
- package/fesm2022/ngbase-adk-select.mjs.map +1 -1
- package/fesm2022/ngbase-adk-selectable.mjs +19 -30
- package/fesm2022/ngbase-adk-selectable.mjs.map +1 -1
- package/fesm2022/ngbase-adk-sheet.mjs +6 -20
- package/fesm2022/ngbase-adk-sheet.mjs.map +1 -1
- package/fesm2022/ngbase-adk-sidenav.mjs +65 -46
- package/fesm2022/ngbase-adk-sidenav.mjs.map +1 -1
- package/fesm2022/ngbase-adk-slider.mjs +40 -53
- package/fesm2022/ngbase-adk-slider.mjs.map +1 -1
- package/fesm2022/ngbase-adk-sonner.mjs +12 -19
- package/fesm2022/ngbase-adk-sonner.mjs.map +1 -1
- package/fesm2022/ngbase-adk-stepper.mjs +17 -25
- package/fesm2022/ngbase-adk-stepper.mjs.map +1 -1
- package/fesm2022/ngbase-adk-switch.mjs +25 -32
- package/fesm2022/ngbase-adk-switch.mjs.map +1 -1
- package/fesm2022/ngbase-adk-table.mjs +581 -83
- package/fesm2022/ngbase-adk-table.mjs.map +1 -1
- package/fesm2022/ngbase-adk-tabs.mjs +37 -35
- package/fesm2022/ngbase-adk-tabs.mjs.map +1 -1
- package/fesm2022/ngbase-adk-test.mjs.map +1 -1
- package/fesm2022/ngbase-adk-toggle-group.mjs +20 -34
- package/fesm2022/ngbase-adk-toggle-group.mjs.map +1 -1
- package/fesm2022/ngbase-adk-toggle.mjs +14 -19
- package/fesm2022/ngbase-adk-toggle.mjs.map +1 -1
- package/fesm2022/ngbase-adk-tooltip.mjs +12 -19
- package/fesm2022/ngbase-adk-tooltip.mjs.map +1 -1
- package/fesm2022/ngbase-adk-tour.mjs +52 -52
- package/fesm2022/ngbase-adk-tour.mjs.map +1 -1
- package/fesm2022/ngbase-adk-translate.mjs +8 -10
- package/fesm2022/ngbase-adk-translate.mjs.map +1 -1
- package/fesm2022/ngbase-adk-tree.mjs +20 -20
- package/fesm2022/ngbase-adk-tree.mjs.map +1 -1
- package/fesm2022/ngbase-adk-utils.mjs +30 -43
- package/fesm2022/ngbase-adk-utils.mjs.map +1 -1
- package/fesm2022/ngbase-adk-virtualizer.mjs +9 -9
- package/fesm2022/ngbase-adk-virtualizer.mjs.map +1 -1
- package/package.json +91 -91
- package/schematics/components/files/accordion/accordion.ts.template +9 -6
- package/schematics/components/files/audio/AudioPlayer.ts.template +245 -0
- package/schematics/components/files/audio/AudioRecorder.ts.template +377 -0
- package/schematics/components/files/audio/AudioVisualizer.ts.template +175 -0
- package/schematics/components/files/audio/index.ts.template +3 -0
- package/schematics/components/files/button/button-llm.md.template +3 -2
- package/schematics/components/files/charts/area-chart.component.ts.template +278 -0
- package/schematics/components/files/charts/bar-chart.component.ts.template +262 -0
- package/schematics/components/files/charts/chart-tooltip.component.ts.template +168 -0
- package/schematics/components/files/charts/index.ts.template +4 -0
- package/schematics/components/files/charts/line-chart.component.ts.template +238 -0
- package/schematics/components/files/charts/pie-chart.component.ts.template +283 -0
- package/schematics/components/files/checkbox/checkbox.ts.template +2 -2
- package/schematics/components/files/color-picker/color-picker.ts.template +2 -2
- package/schematics/components/files/dialog/dialog.ts.template +18 -14
- package/schematics/components/files/drawer/drawer.ts.template +30 -27
- package/schematics/components/files/form-field/form-field.ts.template +51 -23
- package/schematics/components/files/pagination/pagination.ts.template +4 -4
- package/schematics/components/files/picasa/picasa-base.component.ts.template +15 -30
- package/schematics/components/files/popover/popover.ts.template +15 -4
- package/schematics/components/files/select/list-selection.ts.template +0 -2
- package/schematics/components/files/select/option.ts.template +1 -1
- package/schematics/components/files/selectable/selectable.ts.template +2 -2
- package/schematics/components/files/sheet/sheet.ts.template +26 -14
- package/schematics/components/files/sidenav/sidenav.ts.template +7 -5
- package/schematics/components/files/sonner/sonner.ts.template +1 -2
- package/schematics/components/files/stepper/stepper.ts.template +2 -4
- package/schematics/components/files/switch/switch.ts.template +2 -2
- package/schematics/components/files/table/table.ts.template +43 -3
- package/schematics/components/files/tabs/tab.ts.template +3 -3
- package/schematics/components/files/theme/theme.service.ts.template +3 -3
- package/schematics/components/files/toggle/toggle.ts.template +1 -1
- package/schematics/components/files/toggle-group/toggle-group.ts.template +1 -1
- package/schematics/components/files/tooltip/tooltip.ts.template +2 -3
- package/schematics/components/schema.json +2 -0
- package/{accordion/index.d.ts → types/ngbase-adk-accordion.d.ts} +1 -3
- package/{autocomplete/index.d.ts → types/ngbase-adk-autocomplete.d.ts} +2 -7
- package/{checkbox/index.d.ts → types/ngbase-adk-checkbox.d.ts} +8 -14
- package/types/ngbase-adk-clipboard.d.ts +12 -0
- package/{color-picker/index.d.ts → types/ngbase-adk-color-picker.d.ts} +14 -26
- package/{datepicker/index.d.ts → types/ngbase-adk-datepicker.d.ts} +9 -18
- package/{dialog/index.d.ts → types/ngbase-adk-dialog.d.ts} +3 -8
- package/types/ngbase-adk-form-field.d.ts +88 -0
- package/{inline-edit/index.d.ts → types/ngbase-adk-inline-edit.d.ts} +8 -16
- package/types/ngbase-adk-jwt.d.ts +64 -0
- package/{menu/index.d.ts → types/ngbase-adk-menu.d.ts} +6 -5
- package/{otp/index.d.ts → types/ngbase-adk-otp.d.ts} +8 -16
- package/{popover/index.d.ts → types/ngbase-adk-popover.d.ts} +14 -2
- package/{portal/index.d.ts → types/ngbase-adk-portal.d.ts} +29 -8
- package/{radio/index.d.ts → types/ngbase-adk-radio.d.ts} +9 -12
- package/{resizable/index.d.ts → types/ngbase-adk-resizable.d.ts} +4 -4
- package/{scroll-area/index.d.ts → types/ngbase-adk-scroll-area.d.ts} +2 -1
- package/{select/index.d.ts → types/ngbase-adk-select.d.ts} +8 -22
- package/{selectable/index.d.ts → types/ngbase-adk-selectable.d.ts} +6 -10
- package/{sheet/index.d.ts → types/ngbase-adk-sheet.d.ts} +4 -3
- package/{sidenav/index.d.ts → types/ngbase-adk-sidenav.d.ts} +6 -6
- package/{slider/index.d.ts → types/ngbase-adk-slider.d.ts} +8 -17
- package/{sonner/index.d.ts → types/ngbase-adk-sonner.d.ts} +1 -3
- package/{stepper/index.d.ts → types/ngbase-adk-stepper.d.ts} +1 -4
- package/{switch/index.d.ts → types/ngbase-adk-switch.d.ts} +7 -14
- package/{table/index.d.ts → types/ngbase-adk-table.d.ts} +126 -3
- package/{test/index.d.ts → types/ngbase-adk-test.d.ts} +1 -1
- package/{toggle-group/index.d.ts → types/ngbase-adk-toggle-group.d.ts} +5 -10
- package/types/ngbase-adk-toggle.d.ts +14 -0
- package/{tooltip/index.d.ts → types/ngbase-adk-tooltip.d.ts} +9 -11
- package/{tour/index.d.ts → types/ngbase-adk-tour.d.ts} +4 -6
- package/{utils/index.d.ts → types/ngbase-adk-utils.d.ts} +15 -11
- package/clipboard/index.d.ts +0 -11
- package/form-field/index.d.ts +0 -97
- package/jwt/index.d.ts +0 -20
- package/toggle/index.d.ts +0 -16
- /package/{a11y/index.d.ts → types/ngbase-adk-a11y.d.ts} +0 -0
- /package/{avatar/index.d.ts → types/ngbase-adk-avatar.d.ts} +0 -0
- /package/{bidi/index.d.ts → types/ngbase-adk-bidi.d.ts} +0 -0
- /package/{breadcrumb/index.d.ts → types/ngbase-adk-breadcrumb.d.ts} +0 -0
- /package/{cache/index.d.ts → types/ngbase-adk-cache.d.ts} +0 -0
- /package/{carousel/index.d.ts → types/ngbase-adk-carousel.d.ts} +0 -0
- /package/{chip/index.d.ts → types/ngbase-adk-chip.d.ts} +0 -0
- /package/{collections/index.d.ts → types/ngbase-adk-collections.d.ts} +0 -0
- /package/{cookies/index.d.ts → types/ngbase-adk-cookies.d.ts} +0 -0
- /package/{drag/index.d.ts → types/ngbase-adk-drag.d.ts} +0 -0
- /package/{hover-card/index.d.ts → types/ngbase-adk-hover-card.d.ts} +0 -0
- /package/{icon/index.d.ts → types/ngbase-adk-icon.d.ts} +0 -0
- /package/{keys/index.d.ts → types/ngbase-adk-keys.d.ts} +0 -0
- /package/{layout/index.d.ts → types/ngbase-adk-layout.d.ts} +0 -0
- /package/{list/index.d.ts → types/ngbase-adk-list.d.ts} +0 -0
- /package/{mask/index.d.ts → types/ngbase-adk-mask.d.ts} +0 -0
- /package/{network/index.d.ts → types/ngbase-adk-network.d.ts} +0 -0
- /package/{pagination/index.d.ts → types/ngbase-adk-pagination.d.ts} +0 -0
- /package/{progress/index.d.ts → types/ngbase-adk-progress.d.ts} +0 -0
- /package/{tabs/index.d.ts → types/ngbase-adk-tabs.d.ts} +0 -0
- /package/{translate/index.d.ts → types/ngbase-adk-translate.d.ts} +0 -0
- /package/{tree/index.d.ts → types/ngbase-adk-tree.d.ts} +0 -0
- /package/{virtualizer/index.d.ts → types/ngbase-adk-virtualizer.d.ts} +0 -0
- /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: "
|
|
10
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "
|
|
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: "
|
|
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: "
|
|
23
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "
|
|
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: "
|
|
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 ?
|
|
37
|
-
this.heads = contentChild(NgbHeadDef, ...(ngDevMode ?
|
|
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: "
|
|
40
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.2.0", version: "
|
|
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: "
|
|
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: "
|
|
54
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "
|
|
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: "
|
|
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: "
|
|
67
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "
|
|
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: "
|
|
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: "
|
|
82
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "
|
|
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: "
|
|
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: "
|
|
135
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.2.0", version: "
|
|
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: "
|
|
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 ?
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
188
|
-
const
|
|
189
|
-
const
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
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
|
-
|
|
201
|
-
|
|
202
|
-
|
|
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
|
-
|
|
239
|
-
|
|
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: "
|
|
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: "
|
|
262
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "
|
|
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: "
|
|
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
|
-
//
|
|
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
|
-
|
|
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: "
|
|
320
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.2.0", version: "
|
|
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: "
|
|
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
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
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: "
|
|
411
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "
|
|
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: "
|
|
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: "
|
|
438
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "
|
|
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: "
|
|
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
|