@testgorilla/tgo-ui 9.3.3 → 10.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/fesm2022/testgorilla-tgo-ui-components-accordion.mjs +8 -8
- package/fesm2022/testgorilla-tgo-ui-components-accordion.mjs.map +1 -1
- package/fesm2022/testgorilla-tgo-ui-components-ai-audio-circle.mjs +15 -15
- package/fesm2022/testgorilla-tgo-ui-components-ai-audio-circle.mjs.map +1 -1
- package/fesm2022/testgorilla-tgo-ui-components-ai-caveat.mjs +7 -7
- package/fesm2022/testgorilla-tgo-ui-components-ai-feedback.mjs +23 -23
- package/fesm2022/testgorilla-tgo-ui-components-ai-feedback.mjs.map +1 -1
- package/fesm2022/testgorilla-tgo-ui-components-alert-banner.mjs +7 -7
- package/fesm2022/testgorilla-tgo-ui-components-audio-waveform.mjs +23 -23
- package/fesm2022/testgorilla-tgo-ui-components-audio-waveform.mjs.map +1 -1
- package/fesm2022/testgorilla-tgo-ui-components-autocomplete-v2.mjs +84 -84
- package/fesm2022/testgorilla-tgo-ui-components-autocomplete-v2.mjs.map +1 -1
- package/fesm2022/testgorilla-tgo-ui-components-autocomplete.mjs +21 -21
- package/fesm2022/testgorilla-tgo-ui-components-autocomplete.mjs.map +1 -1
- package/fesm2022/testgorilla-tgo-ui-components-avatar.mjs +10 -10
- package/fesm2022/testgorilla-tgo-ui-components-badge.mjs +10 -10
- package/fesm2022/testgorilla-tgo-ui-components-badge.mjs.map +1 -1
- package/fesm2022/testgorilla-tgo-ui-components-breadcrumb.mjs +20 -20
- package/fesm2022/testgorilla-tgo-ui-components-breadcrumb.mjs.map +1 -1
- package/fesm2022/testgorilla-tgo-ui-components-button.mjs +8 -8
- package/fesm2022/testgorilla-tgo-ui-components-card.mjs +8 -8
- package/fesm2022/testgorilla-tgo-ui-components-card.mjs.map +1 -1
- package/fesm2022/testgorilla-tgo-ui-components-checkbox.mjs +12 -12
- package/fesm2022/testgorilla-tgo-ui-components-checkbox.mjs.map +1 -1
- package/fesm2022/testgorilla-tgo-ui-components-checklist.mjs +15 -15
- package/fesm2022/testgorilla-tgo-ui-components-checklist.mjs.map +1 -1
- package/fesm2022/testgorilla-tgo-ui-components-core.mjs +44 -44
- package/fesm2022/testgorilla-tgo-ui-components-core.mjs.map +1 -1
- package/fesm2022/testgorilla-tgo-ui-components-datepicker.mjs +20 -20
- package/fesm2022/testgorilla-tgo-ui-components-datepicker.mjs.map +1 -1
- package/fesm2022/testgorilla-tgo-ui-components-dialog.mjs +25 -25
- package/fesm2022/testgorilla-tgo-ui-components-dialog.mjs.map +1 -1
- package/fesm2022/testgorilla-tgo-ui-components-divider.mjs +7 -7
- package/fesm2022/testgorilla-tgo-ui-components-donut-chart.mjs +10 -10
- package/fesm2022/testgorilla-tgo-ui-components-donut-chart.mjs.map +1 -1
- package/fesm2022/testgorilla-tgo-ui-components-dropdown.mjs +11 -11
- package/fesm2022/testgorilla-tgo-ui-components-dropdown.mjs.map +1 -1
- package/fesm2022/testgorilla-tgo-ui-components-elevation-shadow.mjs +7 -7
- package/fesm2022/testgorilla-tgo-ui-components-empty-state.mjs +7 -7
- package/fesm2022/testgorilla-tgo-ui-components-field.mjs +14 -14
- package/fesm2022/testgorilla-tgo-ui-components-field.mjs.map +1 -1
- package/fesm2022/testgorilla-tgo-ui-components-file-upload.mjs +10 -10
- package/fesm2022/testgorilla-tgo-ui-components-filter-button.mjs +20 -20
- package/fesm2022/testgorilla-tgo-ui-components-filter-button.mjs.map +1 -1
- package/fesm2022/testgorilla-tgo-ui-components-gaussian-chart.mjs +8 -8
- package/fesm2022/testgorilla-tgo-ui-components-gaussian-chart.mjs.map +1 -1
- package/fesm2022/testgorilla-tgo-ui-components-icon-label.mjs +7 -7
- package/fesm2022/testgorilla-tgo-ui-components-icon.mjs +23 -15
- package/fesm2022/testgorilla-tgo-ui-components-icon.mjs.map +1 -1
- package/fesm2022/testgorilla-tgo-ui-components-infinite-scroll-table.mjs +369 -0
- package/fesm2022/testgorilla-tgo-ui-components-infinite-scroll-table.mjs.map +1 -0
- package/fesm2022/testgorilla-tgo-ui-components-inline-field.mjs +33 -33
- package/fesm2022/testgorilla-tgo-ui-components-inline-field.mjs.map +1 -1
- package/fesm2022/testgorilla-tgo-ui-components-logo.mjs +7 -7
- package/fesm2022/testgorilla-tgo-ui-components-media-card.mjs +3 -3
- package/fesm2022/testgorilla-tgo-ui-components-media-dialog.mjs +3 -3
- package/fesm2022/testgorilla-tgo-ui-components-multi-input.mjs +23 -23
- package/fesm2022/testgorilla-tgo-ui-components-multi-input.mjs.map +1 -1
- package/fesm2022/testgorilla-tgo-ui-components-navbar.mjs +14 -14
- package/fesm2022/testgorilla-tgo-ui-components-navbar.mjs.map +1 -1
- package/fesm2022/testgorilla-tgo-ui-components-overflow-menu.mjs +10 -10
- package/fesm2022/testgorilla-tgo-ui-components-overflow-menu.mjs.map +1 -1
- package/fesm2022/testgorilla-tgo-ui-components-page-header.mjs +7 -7
- package/fesm2022/testgorilla-tgo-ui-components-paginator.mjs +8 -8
- package/fesm2022/testgorilla-tgo-ui-components-password-criteria.mjs +7 -7
- package/fesm2022/testgorilla-tgo-ui-components-password-strength.mjs +7 -7
- package/fesm2022/testgorilla-tgo-ui-components-phone-input.mjs +12 -12
- package/fesm2022/testgorilla-tgo-ui-components-phone-input.mjs.map +1 -1
- package/fesm2022/testgorilla-tgo-ui-components-popover.mjs +15 -15
- package/fesm2022/testgorilla-tgo-ui-components-popover.mjs.map +1 -1
- package/fesm2022/testgorilla-tgo-ui-components-progress-bar.mjs +7 -7
- package/fesm2022/testgorilla-tgo-ui-components-prompt.mjs +42 -42
- package/fesm2022/testgorilla-tgo-ui-components-prompt.mjs.map +1 -1
- package/fesm2022/testgorilla-tgo-ui-components-radial-progress.mjs +7 -7
- package/fesm2022/testgorilla-tgo-ui-components-radio-button.mjs +7 -7
- package/fesm2022/testgorilla-tgo-ui-components-rating.mjs +10 -10
- package/fesm2022/testgorilla-tgo-ui-components-scale-table.mjs +8 -8
- package/fesm2022/testgorilla-tgo-ui-components-scale-table.mjs.map +1 -1
- package/fesm2022/testgorilla-tgo-ui-components-scale.mjs +8 -8
- package/fesm2022/testgorilla-tgo-ui-components-scale.mjs.map +1 -1
- package/fesm2022/testgorilla-tgo-ui-components-segmented-bar.mjs +7 -7
- package/fesm2022/testgorilla-tgo-ui-components-segmented-button.mjs +7 -7
- package/fesm2022/testgorilla-tgo-ui-components-segmented-toggle.mjs +17 -17
- package/fesm2022/testgorilla-tgo-ui-components-segmented-toggle.mjs.map +1 -1
- package/fesm2022/testgorilla-tgo-ui-components-selectable-card.mjs +14 -14
- package/fesm2022/testgorilla-tgo-ui-components-selectable-card.mjs.map +1 -1
- package/fesm2022/testgorilla-tgo-ui-components-side-navigation.mjs +31 -31
- package/fesm2022/testgorilla-tgo-ui-components-side-navigation.mjs.map +1 -1
- package/fesm2022/testgorilla-tgo-ui-components-side-panel.mjs +12 -12
- package/fesm2022/testgorilla-tgo-ui-components-side-panel.mjs.map +1 -1
- package/fesm2022/testgorilla-tgo-ui-components-side-sheet.mjs +12 -12
- package/fesm2022/testgorilla-tgo-ui-components-side-sheet.mjs.map +1 -1
- package/fesm2022/testgorilla-tgo-ui-components-skeleton.mjs +3 -3
- package/fesm2022/testgorilla-tgo-ui-components-slider.mjs +12 -12
- package/fesm2022/testgorilla-tgo-ui-components-slider.mjs.map +1 -1
- package/fesm2022/testgorilla-tgo-ui-components-snackbar.mjs +10 -10
- package/fesm2022/testgorilla-tgo-ui-components-spider-chart.mjs +7 -7
- package/fesm2022/testgorilla-tgo-ui-components-spinner.mjs +7 -7
- package/fesm2022/testgorilla-tgo-ui-components-stepper.mjs +21 -21
- package/fesm2022/testgorilla-tgo-ui-components-stepper.mjs.map +1 -1
- package/fesm2022/testgorilla-tgo-ui-components-table.mjs +11 -11
- package/fesm2022/testgorilla-tgo-ui-components-tabs.mjs +25 -25
- package/fesm2022/testgorilla-tgo-ui-components-tabs.mjs.map +1 -1
- package/fesm2022/testgorilla-tgo-ui-components-tag.mjs +26 -26
- package/fesm2022/testgorilla-tgo-ui-components-tag.mjs.map +1 -1
- package/fesm2022/testgorilla-tgo-ui-components-toggle.mjs +7 -7
- package/fesm2022/testgorilla-tgo-ui-components-tooltip.mjs +10 -10
- package/fesm2022/testgorilla-tgo-ui-components-universal-skills.mjs +17 -17
- package/fesm2022/testgorilla-tgo-ui-components-validation-error.mjs +7 -7
- package/fesm2022/testgorilla-tgo-ui-components-write-with-ai.mjs +40 -40
- package/fesm2022/testgorilla-tgo-ui-components-write-with-ai.mjs.map +1 -1
- package/fesm2022/testgorilla-tgo-ui.mjs +7 -7
- package/mcp/catalog.json +1 -1
- package/package.json +96 -101
- package/projects/tgo-canopy-ui/assets/icons/rebrand/Grid-list-view-filled.svg +3 -0
- package/projects/tgo-canopy-ui/assets/icons/rebrand/Grid-list-view-in-line.svg +3 -0
- package/projects/tgo-canopy-ui/assets/icons/rebrand/Table-view-filled.svg +3 -0
- package/projects/tgo-canopy-ui/assets/icons/rebrand/Table-view-in-line.svg +3 -0
- package/{components/icon/index.d.ts → types/testgorilla-tgo-ui-components-icon.d.ts} +1 -1
- package/types/testgorilla-tgo-ui-components-infinite-scroll-table.d.ts +225 -0
- package/{components/inline-field/index.d.ts → types/testgorilla-tgo-ui-components-inline-field.d.ts} +8 -7
- package/{components/side-sheet/index.d.ts → types/testgorilla-tgo-ui-components-side-sheet.d.ts} +1 -1
- /package/{components/accordion/index.d.ts → types/testgorilla-tgo-ui-components-accordion.d.ts} +0 -0
- /package/{components/ai-audio-circle/index.d.ts → types/testgorilla-tgo-ui-components-ai-audio-circle.d.ts} +0 -0
- /package/{components/ai-caveat/index.d.ts → types/testgorilla-tgo-ui-components-ai-caveat.d.ts} +0 -0
- /package/{components/ai-feedback/index.d.ts → types/testgorilla-tgo-ui-components-ai-feedback.d.ts} +0 -0
- /package/{components/alert-banner/index.d.ts → types/testgorilla-tgo-ui-components-alert-banner.d.ts} +0 -0
- /package/{components/audio-waveform/index.d.ts → types/testgorilla-tgo-ui-components-audio-waveform.d.ts} +0 -0
- /package/{components/autocomplete-v2/index.d.ts → types/testgorilla-tgo-ui-components-autocomplete-v2.d.ts} +0 -0
- /package/{components/autocomplete/index.d.ts → types/testgorilla-tgo-ui-components-autocomplete.d.ts} +0 -0
- /package/{components/avatar/index.d.ts → types/testgorilla-tgo-ui-components-avatar.d.ts} +0 -0
- /package/{components/badge/index.d.ts → types/testgorilla-tgo-ui-components-badge.d.ts} +0 -0
- /package/{components/breadcrumb/index.d.ts → types/testgorilla-tgo-ui-components-breadcrumb.d.ts} +0 -0
- /package/{components/button/index.d.ts → types/testgorilla-tgo-ui-components-button.d.ts} +0 -0
- /package/{components/card/index.d.ts → types/testgorilla-tgo-ui-components-card.d.ts} +0 -0
- /package/{components/checkbox/index.d.ts → types/testgorilla-tgo-ui-components-checkbox.d.ts} +0 -0
- /package/{components/checklist/index.d.ts → types/testgorilla-tgo-ui-components-checklist.d.ts} +0 -0
- /package/{components/core/index.d.ts → types/testgorilla-tgo-ui-components-core.d.ts} +0 -0
- /package/{components/datepicker/index.d.ts → types/testgorilla-tgo-ui-components-datepicker.d.ts} +0 -0
- /package/{components/dialog/index.d.ts → types/testgorilla-tgo-ui-components-dialog.d.ts} +0 -0
- /package/{components/divider/index.d.ts → types/testgorilla-tgo-ui-components-divider.d.ts} +0 -0
- /package/{components/donut-chart/index.d.ts → types/testgorilla-tgo-ui-components-donut-chart.d.ts} +0 -0
- /package/{components/dropdown/index.d.ts → types/testgorilla-tgo-ui-components-dropdown.d.ts} +0 -0
- /package/{components/elevation-shadow/index.d.ts → types/testgorilla-tgo-ui-components-elevation-shadow.d.ts} +0 -0
- /package/{components/empty-state/index.d.ts → types/testgorilla-tgo-ui-components-empty-state.d.ts} +0 -0
- /package/{components/field/index.d.ts → types/testgorilla-tgo-ui-components-field.d.ts} +0 -0
- /package/{components/file-upload/index.d.ts → types/testgorilla-tgo-ui-components-file-upload.d.ts} +0 -0
- /package/{components/filter-button/index.d.ts → types/testgorilla-tgo-ui-components-filter-button.d.ts} +0 -0
- /package/{components/gaussian-chart/index.d.ts → types/testgorilla-tgo-ui-components-gaussian-chart.d.ts} +0 -0
- /package/{components/icon-label/index.d.ts → types/testgorilla-tgo-ui-components-icon-label.d.ts} +0 -0
- /package/{components/logo/index.d.ts → types/testgorilla-tgo-ui-components-logo.d.ts} +0 -0
- /package/{components/media-card/index.d.ts → types/testgorilla-tgo-ui-components-media-card.d.ts} +0 -0
- /package/{components/media-dialog/index.d.ts → types/testgorilla-tgo-ui-components-media-dialog.d.ts} +0 -0
- /package/{components/multi-input/index.d.ts → types/testgorilla-tgo-ui-components-multi-input.d.ts} +0 -0
- /package/{components/navbar/index.d.ts → types/testgorilla-tgo-ui-components-navbar.d.ts} +0 -0
- /package/{components/overflow-menu/index.d.ts → types/testgorilla-tgo-ui-components-overflow-menu.d.ts} +0 -0
- /package/{components/page-header/index.d.ts → types/testgorilla-tgo-ui-components-page-header.d.ts} +0 -0
- /package/{components/paginator/index.d.ts → types/testgorilla-tgo-ui-components-paginator.d.ts} +0 -0
- /package/{components/password-criteria/index.d.ts → types/testgorilla-tgo-ui-components-password-criteria.d.ts} +0 -0
- /package/{components/password-strength/index.d.ts → types/testgorilla-tgo-ui-components-password-strength.d.ts} +0 -0
- /package/{components/phone-input/index.d.ts → types/testgorilla-tgo-ui-components-phone-input.d.ts} +0 -0
- /package/{components/popover/index.d.ts → types/testgorilla-tgo-ui-components-popover.d.ts} +0 -0
- /package/{components/progress-bar/index.d.ts → types/testgorilla-tgo-ui-components-progress-bar.d.ts} +0 -0
- /package/{components/prompt/index.d.ts → types/testgorilla-tgo-ui-components-prompt.d.ts} +0 -0
- /package/{components/radial-progress/index.d.ts → types/testgorilla-tgo-ui-components-radial-progress.d.ts} +0 -0
- /package/{components/radio-button/index.d.ts → types/testgorilla-tgo-ui-components-radio-button.d.ts} +0 -0
- /package/{components/rating/index.d.ts → types/testgorilla-tgo-ui-components-rating.d.ts} +0 -0
- /package/{components/scale-table/index.d.ts → types/testgorilla-tgo-ui-components-scale-table.d.ts} +0 -0
- /package/{components/scale/index.d.ts → types/testgorilla-tgo-ui-components-scale.d.ts} +0 -0
- /package/{components/segmented-bar/index.d.ts → types/testgorilla-tgo-ui-components-segmented-bar.d.ts} +0 -0
- /package/{components/segmented-button/index.d.ts → types/testgorilla-tgo-ui-components-segmented-button.d.ts} +0 -0
- /package/{components/segmented-toggle/index.d.ts → types/testgorilla-tgo-ui-components-segmented-toggle.d.ts} +0 -0
- /package/{components/selectable-card/index.d.ts → types/testgorilla-tgo-ui-components-selectable-card.d.ts} +0 -0
- /package/{components/side-navigation/index.d.ts → types/testgorilla-tgo-ui-components-side-navigation.d.ts} +0 -0
- /package/{components/side-panel/index.d.ts → types/testgorilla-tgo-ui-components-side-panel.d.ts} +0 -0
- /package/{components/skeleton/index.d.ts → types/testgorilla-tgo-ui-components-skeleton.d.ts} +0 -0
- /package/{components/slider/index.d.ts → types/testgorilla-tgo-ui-components-slider.d.ts} +0 -0
- /package/{components/snackbar/index.d.ts → types/testgorilla-tgo-ui-components-snackbar.d.ts} +0 -0
- /package/{components/spider-chart/index.d.ts → types/testgorilla-tgo-ui-components-spider-chart.d.ts} +0 -0
- /package/{components/spinner/index.d.ts → types/testgorilla-tgo-ui-components-spinner.d.ts} +0 -0
- /package/{components/stepper/index.d.ts → types/testgorilla-tgo-ui-components-stepper.d.ts} +0 -0
- /package/{components/table/index.d.ts → types/testgorilla-tgo-ui-components-table.d.ts} +0 -0
- /package/{components/tabs/index.d.ts → types/testgorilla-tgo-ui-components-tabs.d.ts} +0 -0
- /package/{components/tag/index.d.ts → types/testgorilla-tgo-ui-components-tag.d.ts} +0 -0
- /package/{components/toggle/index.d.ts → types/testgorilla-tgo-ui-components-toggle.d.ts} +0 -0
- /package/{components/tooltip/index.d.ts → types/testgorilla-tgo-ui-components-tooltip.d.ts} +0 -0
- /package/{components/universal-skills/index.d.ts → types/testgorilla-tgo-ui-components-universal-skills.d.ts} +0 -0
- /package/{components/validation-error/index.d.ts → types/testgorilla-tgo-ui-components-validation-error.d.ts} +0 -0
- /package/{components/write-with-ai/index.d.ts → types/testgorilla-tgo-ui-components-write-with-ai.d.ts} +0 -0
- /package/{index.d.ts → types/testgorilla-tgo-ui.d.ts} +0 -0
|
@@ -0,0 +1,369 @@
|
|
|
1
|
+
import { CdkVirtualScrollViewport, CdkFixedSizeVirtualScroll, CdkVirtualForOf, ScrollingModule } from '@angular/cdk/scrolling';
|
|
2
|
+
import { NgTemplateOutlet, CommonModule } from '@angular/common';
|
|
3
|
+
import * as i0 from '@angular/core';
|
|
4
|
+
import { input, booleanAttribute, output, viewChild, signal, computed, effect, untracked, isDevMode, ChangeDetectionStrategy, Component, NgModule } from '@angular/core';
|
|
5
|
+
import { Subscription } from 'rxjs';
|
|
6
|
+
import { CheckboxComponent } from '@testgorilla/tgo-ui/components/checkbox';
|
|
7
|
+
import { SkeletonComponent } from '@testgorilla/tgo-ui/components/skeleton';
|
|
8
|
+
|
|
9
|
+
/** Default number of skeleton rows rendered for the initial (full-body) load. */
|
|
10
|
+
const DEFAULT_FIRST_LOAD_SKELETON_COUNT = 10;
|
|
11
|
+
/** Number of skeleton rows appended below existing rows while the next page is fetched. */
|
|
12
|
+
const LOAD_MORE_SKELETON_COUNT = 3;
|
|
13
|
+
/** Default distance (in rows) from the end at which `loadMore` fires. */
|
|
14
|
+
const DEFAULT_LOAD_MORE_THRESHOLD = 5;
|
|
15
|
+
/** Fixed width (px) of the checkbox selection column. Must match `.ui-ist__cell--checkbox` in the SCSS. */
|
|
16
|
+
const CHECKBOX_COLUMN_WIDTH = 56;
|
|
17
|
+
/**
|
|
18
|
+
* A generic, virtualized table with scroll-driven infinite loading.
|
|
19
|
+
*
|
|
20
|
+
* Owns rendering, fixed-height vertical virtualization (CDK), horizontal scroll, a pinned header,
|
|
21
|
+
* sticky first/last columns, first-load and load-more skeletons, and a guarded `loadMore` event.
|
|
22
|
+
* All content and layout come from consumer inputs — nothing domain-specific lives here.
|
|
23
|
+
*
|
|
24
|
+
* Independent of `ui-table`: it reuses only stable leaf primitives (`ui-skeleton`) and duplicates
|
|
25
|
+
* the column/context type shapes so consumers can migrate with a selector swap.
|
|
26
|
+
*/
|
|
27
|
+
class InfiniteScrollTableComponent {
|
|
28
|
+
constructor() {
|
|
29
|
+
/** Rows loaded so far. The consumer appends pages to this array. */
|
|
30
|
+
this.data = input.required(...(ngDevMode ? [{ debugName: "data" }] : /* istanbul ignore next */ []));
|
|
31
|
+
/** Column definitions. The first `isSticky` column pins left; the last `isSticky` column pins right. */
|
|
32
|
+
this.columns = input.required(...(ngDevMode ? [{ debugName: "columns" }] : /* istanbul ignore next */ []));
|
|
33
|
+
/**
|
|
34
|
+
* Fixed row height in px — used as the virtualization `itemSize`.
|
|
35
|
+
* Variable / multi-line row heights are unsupported in this variant.
|
|
36
|
+
*/
|
|
37
|
+
this.rowHeight = input.required(...(ngDevMode ? [{ debugName: "rowHeight" }] : /* istanbul ignore next */ []));
|
|
38
|
+
/** Optional stable row identity so recycled rows re-render correctly. Takes precedence over `rowIdKey`. */
|
|
39
|
+
this.trackBy = input(...(ngDevMode ? [undefined, { debugName: "trackBy" }] : /* istanbul ignore next */ []));
|
|
40
|
+
/** Optional key on each row that holds a stable id. Used when `trackBy` is not provided. */
|
|
41
|
+
this.rowIdKey = input(...(ngDevMode ? [undefined, { debugName: "rowIdKey" }] : /* istanbul ignore next */ []));
|
|
42
|
+
/**
|
|
43
|
+
* Accepted for API parity with `ui-table`. In this bounded layout the header is always rendered
|
|
44
|
+
* above the internal scroll region and stays visible regardless — `.ui-ist` has `overflow: hidden`,
|
|
45
|
+
* so the header cannot stick to an outer scrolling page. Kept so `ui-table` templates migrate
|
|
46
|
+
* unchanged. Default `true`.
|
|
47
|
+
*/
|
|
48
|
+
this.stickyHeader = input(true, { ...(ngDevMode ? { debugName: "stickyHeader" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
49
|
+
/** Max height of the internal scroll region (e.g. `'70vh'`). The body shrinks to fit fewer rows. */
|
|
50
|
+
this.maxHeight = input('70vh', ...(ngDevMode ? [{ debugName: "maxHeight" }] : /* istanbul ignore next */ []));
|
|
51
|
+
/** Condensed spacing. */
|
|
52
|
+
this.isCondensed = input(false, { ...(ngDevMode ? { debugName: "isCondensed" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
53
|
+
/**
|
|
54
|
+
* Enables row selection. When `true`, a dedicated checkbox column is prepended (pinned to the left)
|
|
55
|
+
* and each row's checkbox reflects the row's `selected` property; toggling it emits `selectionChange`.
|
|
56
|
+
* Selection stays data-driven and consumer-managed, exactly like `ui-table`. Default `false`.
|
|
57
|
+
*/
|
|
58
|
+
this.selectable = input(false, { ...(ngDevMode ? { debugName: "selectable" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
59
|
+
/** First-load state: renders a full body of skeleton rows. */
|
|
60
|
+
this.loading = input(false, { ...(ngDevMode ? { debugName: "loading" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
61
|
+
/** Appends skeleton rows below the existing rows while the next page is fetched. */
|
|
62
|
+
this.loadingMore = input(false, { ...(ngDevMode ? { debugName: "loadingMore" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
63
|
+
/** Whether more pages exist. When `false`, `loadMore` never fires and the load-more skeleton is hidden. */
|
|
64
|
+
this.hasMore = input(false, { ...(ngDevMode ? { debugName: "hasMore" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
65
|
+
/** Number of skeleton rows for the first-load state. */
|
|
66
|
+
this.skeletonRowCount = input(DEFAULT_FIRST_LOAD_SKELETON_COUNT, ...(ngDevMode ? [{ debugName: "skeletonRowCount" }] : /* istanbul ignore next */ []));
|
|
67
|
+
/** How many rows from the end trigger `loadMore`. */
|
|
68
|
+
this.loadMoreThreshold = input(DEFAULT_LOAD_MORE_THRESHOLD, ...(ngDevMode ? [{ debugName: "loadMoreThreshold" }] : /* istanbul ignore next */ []));
|
|
69
|
+
/** Empty-state template, shown when `data` is empty and not loading. */
|
|
70
|
+
this.noDataTemplate = input(...(ngDevMode ? [undefined, { debugName: "noDataTemplate" }] : /* istanbul ignore next */ []));
|
|
71
|
+
/** Error template, shown when `error` is `true`. Receives `{ $implicit: retry, retry }` as context. */
|
|
72
|
+
this.errorTemplate = input(...(ngDevMode ? [undefined, { debugName: "errorTemplate" }] : /* istanbul ignore next */ []));
|
|
73
|
+
/** Whether a page fetch failed. */
|
|
74
|
+
this.error = input(false, { ...(ngDevMode ? { debugName: "error" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
75
|
+
/**
|
|
76
|
+
* Fires when the user scrolls within `loadMoreThreshold` rows of the end.
|
|
77
|
+
* Guarded: emits only when `hasMore && !loading && !loadingMore`, and only once per approach.
|
|
78
|
+
*/
|
|
79
|
+
this.loadMore = output();
|
|
80
|
+
/** Fires from the error template's retry affordance. */
|
|
81
|
+
this.retry = output();
|
|
82
|
+
/** Fires when a data row is clicked; payload is the row plus its data index. */
|
|
83
|
+
this.rowClick = output();
|
|
84
|
+
/**
|
|
85
|
+
* Fires when a row's selection checkbox is toggled (only when `selectable`). Payload is the row,
|
|
86
|
+
* its data index, and the new selected state. The consumer updates its data's `selected` property.
|
|
87
|
+
*/
|
|
88
|
+
this.selectionChange = output();
|
|
89
|
+
/** Fixed width of the checkbox column; exposed so the template can offset a sticky first column. */
|
|
90
|
+
this.checkboxColumnWidth = CHECKBOX_COLUMN_WIDTH;
|
|
91
|
+
this.viewport = viewChild(CdkVirtualScrollViewport, ...(ngDevMode ? [{ debugName: "viewport" }] : /* istanbul ignore next */ []));
|
|
92
|
+
this.headerScroll = viewChild('headerScroll', ...(ngDevMode ? [{ debugName: "headerScroll" }] : /* istanbul ignore next */ []));
|
|
93
|
+
/** Horizontal-scroll state, mirroring the existing table's `scrollSettings`. */
|
|
94
|
+
this.scrollStart = signal(true, ...(ngDevMode ? [{ debugName: "scrollStart" }] : /* istanbul ignore next */ []));
|
|
95
|
+
this.scrollEnd = signal(false, ...(ngDevMode ? [{ debugName: "scrollEnd" }] : /* istanbul ignore next */ []));
|
|
96
|
+
this.horizontalScroll = signal(false, ...(ngDevMode ? [{ debugName: "horizontalScroll" }] : /* istanbul ignore next */ []));
|
|
97
|
+
/**
|
|
98
|
+
* Measured width (px) of the body viewport's vertical scrollbar. Reserved as right padding on the
|
|
99
|
+
* header so the header's content width exactly equals the body's, keeping every column — including
|
|
100
|
+
* the last — aligned between header and body regardless of browser/scrollbar behaviour.
|
|
101
|
+
*/
|
|
102
|
+
this.scrollbarWidth = signal(0, ...(ngDevMode ? [{ debugName: "scrollbarWidth" }] : /* istanbul ignore next */ []));
|
|
103
|
+
/** Guards `loadMore` to a single emission per approach to the end. */
|
|
104
|
+
this.loadMoreArmed = true;
|
|
105
|
+
this.skeletonTheme = {
|
|
106
|
+
background: '#F4F4F4',
|
|
107
|
+
'border-radius': '4px',
|
|
108
|
+
height: '24px',
|
|
109
|
+
'margin-bottom': '0',
|
|
110
|
+
};
|
|
111
|
+
// Sticky rule mirrors ui-table (positional): the LAST column pins right when it's sticky; any other
|
|
112
|
+
// sticky column pins left. This way an actions column (always the last column) is always pinned to
|
|
113
|
+
// the right, even when it's the only sticky column.
|
|
114
|
+
this.lastStickyKey = computed(() => {
|
|
115
|
+
const columns = this.columns();
|
|
116
|
+
const lastColumn = columns[columns.length - 1];
|
|
117
|
+
return lastColumn?.isSticky ? lastColumn.key : undefined;
|
|
118
|
+
}, ...(ngDevMode ? [{ debugName: "lastStickyKey" }] : /* istanbul ignore next */ []));
|
|
119
|
+
this.firstStickyKey = computed(() => {
|
|
120
|
+
const columns = this.columns();
|
|
121
|
+
const lastIndex = columns.length - 1;
|
|
122
|
+
return columns.find((column, index) => column.isSticky && index !== lastIndex)?.key;
|
|
123
|
+
}, ...(ngDevMode ? [{ debugName: "firstStickyKey" }] : /* istanbul ignore next */ []));
|
|
124
|
+
/** Real rows, with skeleton placeholders in first-load / load-more states, as one virtual list. */
|
|
125
|
+
this.renderRows = computed(() => {
|
|
126
|
+
if (this.loading()) {
|
|
127
|
+
return Array.from({ length: Math.max(1, this.skeletonRowCount()) }, (_, i) => ({
|
|
128
|
+
kind: 'skeleton',
|
|
129
|
+
id: `skeleton-first-${i}`,
|
|
130
|
+
}));
|
|
131
|
+
}
|
|
132
|
+
const rows = this.data().map((item, index) => ({ kind: 'data', item, index }));
|
|
133
|
+
if (this.loadingMore() && this.hasMore()) {
|
|
134
|
+
for (let i = 0; i < LOAD_MORE_SKELETON_COUNT; i++) {
|
|
135
|
+
rows.push({ kind: 'skeleton', id: `skeleton-more-${i}` });
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
return rows;
|
|
139
|
+
}, ...(ngDevMode ? [{ debugName: "renderRows" }] : /* istanbul ignore next */ []));
|
|
140
|
+
this.hasData = computed(() => this.data().length > 0, ...(ngDevMode ? [{ debugName: "hasData" }] : /* istanbul ignore next */ []));
|
|
141
|
+
/** The virtualized body is shown for the first-load skeletons and whenever there are rows. */
|
|
142
|
+
this.showViewport = computed(() => this.loading() || this.hasData(), ...(ngDevMode ? [{ debugName: "showViewport" }] : /* istanbul ignore next */ []));
|
|
143
|
+
this.showEmptyState = computed(() => !this.loading() && !this.error() && !this.hasData(), ...(ngDevMode ? [{ debugName: "showEmptyState" }] : /* istanbul ignore next */ []));
|
|
144
|
+
this.showErrorState = computed(() => !this.loading() && this.error() && !this.hasData(), ...(ngDevMode ? [{ debugName: "showErrorState" }] : /* istanbul ignore next */ []));
|
|
145
|
+
this.showErrorFooter = computed(() => !this.loading() && this.error() && this.hasData(), ...(ngDevMode ? [{ debugName: "showErrorFooter" }] : /* istanbul ignore next */ []));
|
|
146
|
+
/** Viewport height shrinks to the content and is capped at `maxHeight` (CSS `min()` mixes units). */
|
|
147
|
+
this.viewportHeight = computed(() => `min(${this.renderRows().length * this.rowHeight()}px, ${this.maxHeight()})`, ...(ngDevMode ? [{ debugName: "viewportHeight" }] : /* istanbul ignore next */ []));
|
|
148
|
+
/** Screen-reader announcement for the busy states. */
|
|
149
|
+
this.statusMessage = computed(() => {
|
|
150
|
+
if (this.loading()) {
|
|
151
|
+
return 'Loading';
|
|
152
|
+
}
|
|
153
|
+
if (this.loadingMore()) {
|
|
154
|
+
return 'Loading more rows';
|
|
155
|
+
}
|
|
156
|
+
return '';
|
|
157
|
+
}, ...(ngDevMode ? [{ debugName: "statusMessage" }] : /* istanbul ignore next */ []));
|
|
158
|
+
this.errorContext = {
|
|
159
|
+
$implicit: () => this.onRetry(),
|
|
160
|
+
retry: () => this.onRetry(),
|
|
161
|
+
};
|
|
162
|
+
this.renderRowTrackBy = (index, row) => {
|
|
163
|
+
if (row.kind === 'skeleton') {
|
|
164
|
+
return row.id;
|
|
165
|
+
}
|
|
166
|
+
const explicitTrackBy = this.trackBy();
|
|
167
|
+
if (explicitTrackBy) {
|
|
168
|
+
return explicitTrackBy(row.index, row.item);
|
|
169
|
+
}
|
|
170
|
+
const key = this.rowIdKey();
|
|
171
|
+
return key ? row.item[key] : row.index;
|
|
172
|
+
};
|
|
173
|
+
// (Re-)attach scroll listeners whenever the viewport enters or leaves the DOM (empty/error states).
|
|
174
|
+
// Keyed on `viewport()` only: the setup below reads other signals (through syncHorizontalScroll /
|
|
175
|
+
// checkLoadMore), so it runs inside `untracked()` to avoid re-running — and tearing down the
|
|
176
|
+
// subscriptions + ResizeObserver — on every data change or loading toggle.
|
|
177
|
+
effect(onCleanup => {
|
|
178
|
+
const viewport = this.viewport();
|
|
179
|
+
if (!viewport) {
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
untracked(() => {
|
|
183
|
+
const element = viewport.elementRef.nativeElement;
|
|
184
|
+
// CDK inserts a generic `.cdk-virtual-scroll-content-wrapper` between the viewport
|
|
185
|
+
// (role="rowgroup") and the rows (role="row"). Mark it presentational so the rows stay
|
|
186
|
+
// owned by the rowgroup and the table's ARIA tree isn't broken for assistive tech.
|
|
187
|
+
element.querySelector('.cdk-virtual-scroll-content-wrapper')?.setAttribute('role', 'presentation');
|
|
188
|
+
const subscription = new Subscription();
|
|
189
|
+
subscription.add(viewport.elementScrolled().subscribe(() => this.syncHorizontalScroll()));
|
|
190
|
+
subscription.add(viewport.renderedRangeStream.subscribe(() => this.checkLoadMore()));
|
|
191
|
+
// Keep the measured scrollbar width current: it changes when the vertical scrollbar appears
|
|
192
|
+
// or disappears (content grows/shrinks) and on viewport resize.
|
|
193
|
+
const measureScrollbar = () => this.scrollbarWidth.set(element.offsetWidth - element.clientWidth);
|
|
194
|
+
subscription.add(viewport.renderedRangeStream.subscribe(() => measureScrollbar()));
|
|
195
|
+
let resizeObserver;
|
|
196
|
+
if (typeof ResizeObserver !== 'undefined') {
|
|
197
|
+
resizeObserver = new ResizeObserver(() => measureScrollbar());
|
|
198
|
+
resizeObserver.observe(element);
|
|
199
|
+
}
|
|
200
|
+
measureScrollbar();
|
|
201
|
+
this.syncHorizontalScroll();
|
|
202
|
+
this.checkLoadMore();
|
|
203
|
+
// The first syncHorizontalScroll() runs before the CDK viewport lays out its rows, so the
|
|
204
|
+
// overflow measurement (and the sticky end-shadow) is stale. Re-sync after the next frame,
|
|
205
|
+
// once layout is settled. Guarded because requestAnimationFrame is browser-only (SSR).
|
|
206
|
+
let scrollSyncFrame;
|
|
207
|
+
if (typeof requestAnimationFrame !== 'undefined') {
|
|
208
|
+
scrollSyncFrame = requestAnimationFrame(() => this.syncHorizontalScroll());
|
|
209
|
+
}
|
|
210
|
+
onCleanup(() => {
|
|
211
|
+
subscription.unsubscribe();
|
|
212
|
+
resizeObserver?.disconnect();
|
|
213
|
+
// Cancel a still-pending re-sync so it can't fire after the viewport leaves the DOM
|
|
214
|
+
// (e.g. flipping to the empty/error state in the same tick).
|
|
215
|
+
if (scrollSyncFrame !== undefined) {
|
|
216
|
+
cancelAnimationFrame(scrollSyncFrame);
|
|
217
|
+
}
|
|
218
|
+
});
|
|
219
|
+
});
|
|
220
|
+
});
|
|
221
|
+
// Re-arm the loadMore guard whenever the `data` input changes — a page arrived, or the set was
|
|
222
|
+
// replaced (filter/search reset, even to a shorter or same-length list). It reads `data()` only,
|
|
223
|
+
// NOT `loadingMore()`: a failed fetch clears `loadingMore` without changing `data`, so the guard
|
|
224
|
+
// stays disarmed and never re-fires `loadMore` in a loop (the `error()` guard is a second layer).
|
|
225
|
+
effect(() => {
|
|
226
|
+
this.data();
|
|
227
|
+
this.loadMoreArmed = true;
|
|
228
|
+
});
|
|
229
|
+
// Dev-only: without `trackBy` or `rowIdKey`, row identity falls back to the data index — the
|
|
230
|
+
// weakest option exactly when rows recycle. If the consumer opts into selection without a stable
|
|
231
|
+
// id, surface the sharp edge so selection state can't silently attach to the wrong row after a
|
|
232
|
+
// reorder/prepend.
|
|
233
|
+
effect(() => {
|
|
234
|
+
if (isDevMode() && this.selectable() && !this.trackBy() && !this.rowIdKey()) {
|
|
235
|
+
console.warn('[ui-infinite-scroll-table] `selectable` is enabled without `trackBy` or `rowIdKey`. ' +
|
|
236
|
+
'Row identity falls back to the data index, so selection can attach to the wrong row ' +
|
|
237
|
+
'when rows are reordered or prepended. Provide `trackBy` or `rowIdKey` for stable identity.');
|
|
238
|
+
}
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
getCellValue(item, key) {
|
|
242
|
+
return item[key];
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Content-independent flex-basis for a column: its declared width, else its min-width, else the
|
|
246
|
+
* default. Using this (instead of `flex-basis: auto`) makes header and body cells size identically
|
|
247
|
+
* so every column stays aligned regardless of the text inside header vs body cells.
|
|
248
|
+
*/
|
|
249
|
+
cellBasis(column) {
|
|
250
|
+
return column.styles?.width ?? column.styles?.['min-width'] ?? '160px';
|
|
251
|
+
}
|
|
252
|
+
onRowClick(row) {
|
|
253
|
+
if (row.kind !== 'data') {
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
this.rowClick.emit({ ...row.item, index: row.index });
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* Whether a row should show the selected highlight. Mirrors `ui-table`: only when `selectable` is
|
|
260
|
+
* enabled and the row's data carries a truthy `selected` property. Skeleton rows are never selected.
|
|
261
|
+
*/
|
|
262
|
+
isRowSelected(row) {
|
|
263
|
+
return this.selectable() && row.kind === 'data' && Boolean(row.item.selected);
|
|
264
|
+
}
|
|
265
|
+
/** Emits the new selection state when a row's checkbox is toggled. Consumer-managed, like `ui-table`. */
|
|
266
|
+
onSelectionToggle(row, selected) {
|
|
267
|
+
if (row.kind !== 'data') {
|
|
268
|
+
return;
|
|
269
|
+
}
|
|
270
|
+
this.selectionChange.emit({
|
|
271
|
+
...row.item,
|
|
272
|
+
index: row.index,
|
|
273
|
+
selected,
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* Left offset (px) for a sticky-start consumer column: when the checkbox column is present it must
|
|
278
|
+
* sit to the right of it, so the first sticky column is pushed over by the checkbox column width.
|
|
279
|
+
*/
|
|
280
|
+
stickyStartOffset(column) {
|
|
281
|
+
return this.selectable() && column.key === this.firstStickyKey() ? this.checkboxColumnWidth : null;
|
|
282
|
+
}
|
|
283
|
+
/** Keyboard equivalent of a row click (Enter/Space) for the currently focused data row. */
|
|
284
|
+
onRowActivate(event, row) {
|
|
285
|
+
event.preventDefault();
|
|
286
|
+
this.onRowClick(row);
|
|
287
|
+
}
|
|
288
|
+
onRetry() {
|
|
289
|
+
this.retry.emit();
|
|
290
|
+
}
|
|
291
|
+
/** Keep the header horizontally aligned with the body and update the sticky-shadow state. */
|
|
292
|
+
syncHorizontalScroll() {
|
|
293
|
+
const viewport = this.viewport();
|
|
294
|
+
if (!viewport) {
|
|
295
|
+
return;
|
|
296
|
+
}
|
|
297
|
+
const left = viewport.measureScrollOffset('left');
|
|
298
|
+
const right = viewport.measureScrollOffset('right');
|
|
299
|
+
const header = this.headerScroll();
|
|
300
|
+
if (header) {
|
|
301
|
+
header.nativeElement.scrollLeft = left;
|
|
302
|
+
}
|
|
303
|
+
this.scrollStart.set(left <= 1);
|
|
304
|
+
this.scrollEnd.set(right <= 1);
|
|
305
|
+
this.horizontalScroll.set(left + right > 1);
|
|
306
|
+
}
|
|
307
|
+
/**
|
|
308
|
+
* Emits `loadMore` once when the rendered range reaches the trigger zone near the end,
|
|
309
|
+
* re-arming when the user scrolls back out. Mirrors the app's `ngx-infinite-scroll` semantics.
|
|
310
|
+
*/
|
|
311
|
+
checkLoadMore() {
|
|
312
|
+
const viewport = this.viewport();
|
|
313
|
+
// `error()` is part of the guard so a failed page pauses auto-loading until the consumer clears
|
|
314
|
+
// the error (e.g. via the retry affordance), instead of immediately re-firing `loadMore`.
|
|
315
|
+
if (!viewport || !this.hasMore() || this.loading() || this.loadingMore() || this.error()) {
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
const dataLength = this.data().length;
|
|
319
|
+
if (dataLength === 0) {
|
|
320
|
+
return;
|
|
321
|
+
}
|
|
322
|
+
const renderedEnd = viewport.getRenderedRange().end;
|
|
323
|
+
// Clamp so a negative threshold can't push the trigger point past the end and silently disable
|
|
324
|
+
// loadMore entirely.
|
|
325
|
+
const threshold = Math.max(0, this.loadMoreThreshold());
|
|
326
|
+
const inTriggerZone = renderedEnd >= dataLength - threshold;
|
|
327
|
+
if (!inTriggerZone) {
|
|
328
|
+
this.loadMoreArmed = true;
|
|
329
|
+
return;
|
|
330
|
+
}
|
|
331
|
+
if (this.loadMoreArmed) {
|
|
332
|
+
this.loadMoreArmed = false;
|
|
333
|
+
this.loadMore.emit();
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.18", ngImport: i0, type: InfiniteScrollTableComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
337
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.18", type: InfiniteScrollTableComponent, isStandalone: true, selector: "ui-infinite-scroll-table", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: true, transformFunction: null }, columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: true, transformFunction: null }, rowHeight: { classPropertyName: "rowHeight", publicName: "rowHeight", isSignal: true, isRequired: true, transformFunction: null }, trackBy: { classPropertyName: "trackBy", publicName: "trackBy", isSignal: true, isRequired: false, transformFunction: null }, rowIdKey: { classPropertyName: "rowIdKey", publicName: "rowIdKey", isSignal: true, isRequired: false, transformFunction: null }, stickyHeader: { classPropertyName: "stickyHeader", publicName: "stickyHeader", isSignal: true, isRequired: false, transformFunction: null }, maxHeight: { classPropertyName: "maxHeight", publicName: "maxHeight", isSignal: true, isRequired: false, transformFunction: null }, isCondensed: { classPropertyName: "isCondensed", publicName: "isCondensed", isSignal: true, isRequired: false, transformFunction: null }, selectable: { classPropertyName: "selectable", publicName: "selectable", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, loadingMore: { classPropertyName: "loadingMore", publicName: "loadingMore", isSignal: true, isRequired: false, transformFunction: null }, hasMore: { classPropertyName: "hasMore", publicName: "hasMore", isSignal: true, isRequired: false, transformFunction: null }, skeletonRowCount: { classPropertyName: "skeletonRowCount", publicName: "skeletonRowCount", isSignal: true, isRequired: false, transformFunction: null }, loadMoreThreshold: { classPropertyName: "loadMoreThreshold", publicName: "loadMoreThreshold", isSignal: true, isRequired: false, transformFunction: null }, noDataTemplate: { classPropertyName: "noDataTemplate", publicName: "noDataTemplate", isSignal: true, isRequired: false, transformFunction: null }, errorTemplate: { classPropertyName: "errorTemplate", publicName: "errorTemplate", isSignal: true, isRequired: false, transformFunction: null }, error: { classPropertyName: "error", publicName: "error", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { loadMore: "loadMore", retry: "retry", rowClick: "rowClick", selectionChange: "selectionChange" }, viewQueries: [{ propertyName: "viewport", first: true, predicate: CdkVirtualScrollViewport, descendants: true, isSignal: true }, { propertyName: "headerScroll", first: true, predicate: ["headerScroll"], descendants: true, isSignal: true }], ngImport: i0, template: "<div\n class=\"ui-ist\"\n role=\"table\"\n [class.ui-ist--condensed]=\"isCondensed()\"\n [class.ui-ist--scrolled-start]=\"!scrollStart()\"\n [class.ui-ist--scrolled-end]=\"horizontalScroll() && !scrollEnd()\"\n [attr.aria-rowcount]=\"hasMore() ? -1 : data().length + 1\"\n [attr.aria-busy]=\"loading() || loadingMore()\"\n>\n <!-- Header: a separate element above the viewport. It never scrolls vertically (stays pinned),\n and its horizontal scrollLeft is synced from the body so columns stay aligned. -->\n <div\n #headerScroll\n class=\"ui-ist__header\"\n [class.ui-ist__header--sticky]=\"stickyHeader()\"\n [style.margin-right.px]=\"scrollbarWidth()\"\n role=\"presentation\"\n >\n <div class=\"ui-ist__row ui-ist__row--header\" role=\"row\" aria-rowindex=\"1\">\n @if (selectable()) {\n <div\n class=\"ui-ist__cell ui-ist__cell--header ui-ist__cell--checkbox ui-ist__cell--sticky-start\"\n role=\"columnheader\"\n ></div>\n }\n @for (column of columns(); track column.key; let colIndex = $index) {\n <div\n class=\"ui-ist__cell ui-ist__cell--header\"\n role=\"columnheader\"\n [class.ui-ist__cell--sticky-start]=\"column.key === firstStickyKey()\"\n [class.ui-ist__cell--sticky-end]=\"column.key === lastStickyKey()\"\n [class.ui-ist__cell--right]=\"column.styles?.alignment === 'right'\"\n [class.ui-ist__cell--center]=\"column.styles?.alignment === 'center'\"\n [style.flex-basis]=\"cellBasis(column)\"\n [style.min-width]=\"column.styles?.['min-width']\"\n [style.left.px]=\"stickyStartOffset(column)\"\n >\n @if (column.headerCellTemplate) {\n <ng-container\n *ngTemplateOutlet=\"column.headerCellTemplate; context: { $implicit: column.title, column, colIndex }\"\n ></ng-container>\n } @else {\n <span class=\"ui-ist__cell-text\">{{ column.title }}</span>\n }\n </div>\n }\n </div>\n </div>\n\n <!-- Body: the CDK viewport owns BOTH vertical (virtualized) and horizontal scroll, so sticky\n columns pin against it and the horizontal scrollbar sits at the viewport bottom. -->\n @if (showViewport()) {\n <cdk-virtual-scroll-viewport\n class=\"ui-ist__body\"\n role=\"rowgroup\"\n [itemSize]=\"rowHeight()\"\n [style.height]=\"viewportHeight()\"\n >\n <div\n *cdkVirtualFor=\"let row of renderRows(); let rowIndex = index; trackBy: renderRowTrackBy\"\n class=\"ui-ist__row\"\n role=\"row\"\n [class.ui-ist__row--clickable]=\"row.kind === 'data'\"\n [class.ui-ist__row--selected]=\"isRowSelected(row)\"\n [attr.aria-selected]=\"isRowSelected(row) ? true : null\"\n [attr.aria-rowindex]=\"row.kind === 'data' ? row.index + 2 : null\"\n [attr.aria-hidden]=\"row.kind === 'skeleton' ? true : null\"\n [attr.tabindex]=\"row.kind === 'data' ? 0 : null\"\n [style.height.px]=\"rowHeight()\"\n (click)=\"onRowClick(row)\"\n (keydown.enter)=\"onRowActivate($event, row)\"\n (keydown.space)=\"onRowActivate($event, row)\"\n >\n @if (selectable()) {\n <div\n class=\"ui-ist__cell ui-ist__cell--checkbox ui-ist__cell--sticky-start\"\n role=\"cell\"\n (click)=\"$event.stopPropagation()\"\n (keydown)=\"$event.stopPropagation()\"\n >\n @if (row.kind === 'data') {\n <ui-checkbox\n [checked]=\"isRowSelected(row)\"\n [ariaLabel]=\"'Select row ' + (row.index + 1)\"\n (changed)=\"onSelectionToggle(row, $event)\"\n ></ui-checkbox>\n }\n </div>\n }\n @for (column of columns(); track column.key) {\n <div\n class=\"ui-ist__cell\"\n role=\"cell\"\n [class.ui-ist__cell--sticky-start]=\"column.key === firstStickyKey()\"\n [class.ui-ist__cell--sticky-end]=\"column.key === lastStickyKey()\"\n [class.ui-ist__cell--right]=\"column.styles?.alignment === 'right'\"\n [class.ui-ist__cell--center]=\"column.styles?.alignment === 'center'\"\n [style.flex-basis]=\"cellBasis(column)\"\n [style.min-width]=\"column.styles?.['min-width']\"\n [style.left.px]=\"stickyStartOffset(column)\"\n >\n @if (row.kind === 'skeleton') {\n <ui-skeleton class=\"ui-ist__skeleton\" [count]=\"1\" [theme]=\"skeletonTheme\" appearance=\"line\"></ui-skeleton>\n } @else if (column.rowCellTemplate) {\n <ng-container\n *ngTemplateOutlet=\"column.rowCellTemplate; context: { $implicit: row.item, rowIndex: row.index }\"\n ></ng-container>\n } @else {\n <span class=\"ui-ist__cell-text\">{{ getCellValue(row.item, column.key) }}</span>\n }\n </div>\n }\n </div>\n </cdk-virtual-scroll-viewport>\n }\n\n <!-- Empty and error states render the consumer template in-frame below the header, mirroring how\n ui-table drops `noDataRowTpl` into the table body. Mid-scroll errors sit below the loaded rows. -->\n @if (showErrorFooter() && errorTemplate(); as errorTpl) {\n <div class=\"ui-ist__state\" role=\"alert\">\n <ng-container *ngTemplateOutlet=\"errorTpl; context: errorContext\"></ng-container>\n </div>\n }\n\n @if (showErrorState() && errorTemplate(); as errorTpl) {\n <div class=\"ui-ist__state\" role=\"alert\">\n <ng-container *ngTemplateOutlet=\"errorTpl; context: errorContext\"></ng-container>\n </div>\n }\n\n @if (showEmptyState() && noDataTemplate(); as emptyTpl) {\n <div class=\"ui-ist__state\">\n <ng-container *ngTemplateOutlet=\"emptyTpl\"></ng-container>\n </div>\n }\n\n <span class=\"ui-ist__sr-only\" role=\"status\" aria-live=\"polite\">{{ statusMessage() }}</span>\n</div>\n", styles: [".bg-teal-60b{background:#1c443c}.bg-teal-30b{background:#31766a}.bg-teal-default{background:#46a997}.bg-teal-30w{background:#7ec3b6}.bg-teal-60w{background:#b5ddd5}.bg-teal-secondary{background:#cbd6cb}.bg-teal-90w{background:#ecf6f5}.bg-petrol-60b{background:#102930}.bg-petrol-30b{background:#1b4754}.bg-petrol-default{background:#276678}.bg-petrol-30w{background:#6894a0}.bg-petrol-60w{background:#a9c2c9}.bg-petrol-secondary{background:#c8d7de}.bg-petrol-90w{background:#e9f0f1}.bg-error-60b{background:#513131}.bg-error-30b{background:#8e5655}.bg-error-60w{background:#e3c3c6}.bg-error-secondary{background:#f0dad9}.bg-error-default{background:#cb7b7a}.bg-warning-secondary{background:#f0d6bb}.bg-warning-default{background:#cca45f}.bg-black{background:#000}.bg-dark{background:#888}.bg-medium{background:#e0e0e0}.bg-grey{background:#ededed}.bg-light{background:#f6f6f6}.bg-white{background:#fff}.bg-box-shadow{background:#00000014}.bg-navigation-subtitle{background:#528593}.bgc-teal-60b{background-color:#1c443c}.bgc-teal-30b{background-color:#31766a}.bgc-teal-default{background-color:#46a997}.bgc-teal-30w{background-color:#7ec3b6}.bgc-teal-60w{background-color:#b5ddd5}.bgc-teal-secondary{background-color:#cbd6cb}.bgc-teal-90w{background-color:#ecf6f5}.bgc-petrol-60b{background-color:#102930}.bgc-petrol-30b{background-color:#1b4754}.bgc-petrol-default{background-color:#276678}.bgc-petrol-30w{background-color:#6894a0}.bgc-petrol-60w{background-color:#a9c2c9}.bgc-petrol-secondary{background-color:#c8d7de}.bgc-petrol-90w{background-color:#e9f0f1}.bgc-error-60b{background-color:#513131}.bgc-error-30b{background-color:#8e5655}.bgc-error-60w{background-color:#e3c3c6}.bgc-error-secondary{background-color:#f0dad9}.bgc-error-default{background-color:#cb7b7a}.bgc-warning-secondary{background-color:#f0d6bb}.bgc-warning-default{background-color:#cca45f}.bgc-black{background-color:#000}.bgc-dark{background-color:#888}.bgc-medium{background-color:#e0e0e0}.bgc-grey{background-color:#ededed}.bgc-light{background-color:#f6f6f6}.bgc-white{background-color:#fff}.bgc-box-shadow{background-color:#00000014}.bgc-navigation-subtitle{background-color:#528593}:host{display:block}.ui-ist{display:flex;flex-direction:column;border:1px solid #e0e0e0;border-radius:8px;overflow:hidden;background:#fff}.ui-ist__header{flex:0 0 auto;box-sizing:border-box;overflow:hidden;border-bottom:1px solid #e0e0e0;background:#fff}.ui-ist__header--sticky{position:sticky;top:0;z-index:3}.ui-ist__body{flex:1 1 auto;overflow:auto;scrollbar-width:auto}.ui-ist__body::-webkit-scrollbar{width:8px;height:8px}.ui-ist__body::-webkit-scrollbar-button{display:none}.ui-ist__body::-webkit-scrollbar-thumb{background-color:#00000059;border-radius:4px}.ui-ist__body::-webkit-scrollbar-track:hover{background-color:#00000026}.ui-ist__row{display:flex;width:max-content;min-width:100%;box-sizing:border-box}.ui-ist__row--header{min-height:56px}.ui-ist__row:not(.ui-ist__row--header){border-bottom:1px solid #d3d3d3}.ui-ist__row--clickable:not(.ui-ist__row--selected):hover{background:#fff2fc}.ui-ist__row--clickable:not(.ui-ist__row--selected):hover .ui-ist__cell{background:#fff2fc}.ui-ist__row--selected .ui-ist__cell{background:#f4f4f4}.ui-ist__cell{flex-grow:1;flex-shrink:0;box-sizing:border-box;display:flex;align-items:center;min-width:160px;padding:8px 24px;font-size:14px;line-height:20px;overflow:hidden;background:#fff}.ui-ist__cell--header{background:#fff;font-weight:700;font-size:14px;line-height:16px}.ui-ist__cell--right{justify-content:flex-end;text-align:right}.ui-ist__cell--center{justify-content:center;text-align:center}.ui-ist__cell--sticky-start{position:sticky;left:0;z-index:2}.ui-ist__cell--sticky-end{position:sticky;right:0;z-index:2}.ui-ist__cell--checkbox{flex:0 0 56px;min-width:56px;justify-content:center;padding:0}.ui-ist__cell-text{overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.ui-ist__skeleton{display:block;width:100%}.ui-ist--scrolled-start .ui-ist__cell--sticky-start{box-shadow:24px 8px 24px #24242414}.ui-ist--scrolled-end .ui-ist__cell--sticky-end{box-shadow:0 8px 24px 4px #24242414}.ui-ist__state{padding:8px 24px;font-size:14px;line-height:20px}.ui-ist--condensed .ui-ist__cell{padding:8px 12px}.ui-ist--condensed .ui-ist__cell:first-child{padding-left:24px}.ui-ist--condensed .ui-ist__cell:last-child{padding-right:24px}.ui-ist__sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: CdkVirtualScrollViewport, selector: "cdk-virtual-scroll-viewport", inputs: ["orientation", "appendOnly"], outputs: ["scrolledIndexChange"] }, { kind: "directive", type: CdkFixedSizeVirtualScroll, selector: "cdk-virtual-scroll-viewport[itemSize]", inputs: ["itemSize", "minBufferPx", "maxBufferPx"] }, { kind: "directive", type: CdkVirtualForOf, selector: "[cdkVirtualFor][cdkVirtualForOf]", inputs: ["cdkVirtualForOf", "cdkVirtualForTrackBy", "cdkVirtualForTemplate", "cdkVirtualForTemplateCacheSize"] }, { kind: "component", type: SkeletonComponent, selector: "ui-skeleton", inputs: ["count", "theme", "appearance", "isAiTheme", "applicationTheme"] }, { kind: "component", type: CheckboxComponent, selector: "ui-checkbox", inputs: ["disabled", "checked", "indeterminate", "companyColor", "name", "label", "multiple", "applicationTheme", "ariaLabel", "ariaRequired", "hasError", "hideBuiltInErrors", "hideLabelInErrors", "ariaLabelledby", "ariaDescribedby", "truncateText", "alignment", "tabIndex"], outputs: ["changed"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
338
|
+
}
|
|
339
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.18", ngImport: i0, type: InfiniteScrollTableComponent, decorators: [{
|
|
340
|
+
type: Component,
|
|
341
|
+
args: [{ selector: 'ui-infinite-scroll-table', changeDetection: ChangeDetectionStrategy.OnPush, imports: [
|
|
342
|
+
NgTemplateOutlet,
|
|
343
|
+
CdkVirtualScrollViewport,
|
|
344
|
+
CdkFixedSizeVirtualScroll,
|
|
345
|
+
CdkVirtualForOf,
|
|
346
|
+
SkeletonComponent,
|
|
347
|
+
CheckboxComponent,
|
|
348
|
+
], template: "<div\n class=\"ui-ist\"\n role=\"table\"\n [class.ui-ist--condensed]=\"isCondensed()\"\n [class.ui-ist--scrolled-start]=\"!scrollStart()\"\n [class.ui-ist--scrolled-end]=\"horizontalScroll() && !scrollEnd()\"\n [attr.aria-rowcount]=\"hasMore() ? -1 : data().length + 1\"\n [attr.aria-busy]=\"loading() || loadingMore()\"\n>\n <!-- Header: a separate element above the viewport. It never scrolls vertically (stays pinned),\n and its horizontal scrollLeft is synced from the body so columns stay aligned. -->\n <div\n #headerScroll\n class=\"ui-ist__header\"\n [class.ui-ist__header--sticky]=\"stickyHeader()\"\n [style.margin-right.px]=\"scrollbarWidth()\"\n role=\"presentation\"\n >\n <div class=\"ui-ist__row ui-ist__row--header\" role=\"row\" aria-rowindex=\"1\">\n @if (selectable()) {\n <div\n class=\"ui-ist__cell ui-ist__cell--header ui-ist__cell--checkbox ui-ist__cell--sticky-start\"\n role=\"columnheader\"\n ></div>\n }\n @for (column of columns(); track column.key; let colIndex = $index) {\n <div\n class=\"ui-ist__cell ui-ist__cell--header\"\n role=\"columnheader\"\n [class.ui-ist__cell--sticky-start]=\"column.key === firstStickyKey()\"\n [class.ui-ist__cell--sticky-end]=\"column.key === lastStickyKey()\"\n [class.ui-ist__cell--right]=\"column.styles?.alignment === 'right'\"\n [class.ui-ist__cell--center]=\"column.styles?.alignment === 'center'\"\n [style.flex-basis]=\"cellBasis(column)\"\n [style.min-width]=\"column.styles?.['min-width']\"\n [style.left.px]=\"stickyStartOffset(column)\"\n >\n @if (column.headerCellTemplate) {\n <ng-container\n *ngTemplateOutlet=\"column.headerCellTemplate; context: { $implicit: column.title, column, colIndex }\"\n ></ng-container>\n } @else {\n <span class=\"ui-ist__cell-text\">{{ column.title }}</span>\n }\n </div>\n }\n </div>\n </div>\n\n <!-- Body: the CDK viewport owns BOTH vertical (virtualized) and horizontal scroll, so sticky\n columns pin against it and the horizontal scrollbar sits at the viewport bottom. -->\n @if (showViewport()) {\n <cdk-virtual-scroll-viewport\n class=\"ui-ist__body\"\n role=\"rowgroup\"\n [itemSize]=\"rowHeight()\"\n [style.height]=\"viewportHeight()\"\n >\n <div\n *cdkVirtualFor=\"let row of renderRows(); let rowIndex = index; trackBy: renderRowTrackBy\"\n class=\"ui-ist__row\"\n role=\"row\"\n [class.ui-ist__row--clickable]=\"row.kind === 'data'\"\n [class.ui-ist__row--selected]=\"isRowSelected(row)\"\n [attr.aria-selected]=\"isRowSelected(row) ? true : null\"\n [attr.aria-rowindex]=\"row.kind === 'data' ? row.index + 2 : null\"\n [attr.aria-hidden]=\"row.kind === 'skeleton' ? true : null\"\n [attr.tabindex]=\"row.kind === 'data' ? 0 : null\"\n [style.height.px]=\"rowHeight()\"\n (click)=\"onRowClick(row)\"\n (keydown.enter)=\"onRowActivate($event, row)\"\n (keydown.space)=\"onRowActivate($event, row)\"\n >\n @if (selectable()) {\n <div\n class=\"ui-ist__cell ui-ist__cell--checkbox ui-ist__cell--sticky-start\"\n role=\"cell\"\n (click)=\"$event.stopPropagation()\"\n (keydown)=\"$event.stopPropagation()\"\n >\n @if (row.kind === 'data') {\n <ui-checkbox\n [checked]=\"isRowSelected(row)\"\n [ariaLabel]=\"'Select row ' + (row.index + 1)\"\n (changed)=\"onSelectionToggle(row, $event)\"\n ></ui-checkbox>\n }\n </div>\n }\n @for (column of columns(); track column.key) {\n <div\n class=\"ui-ist__cell\"\n role=\"cell\"\n [class.ui-ist__cell--sticky-start]=\"column.key === firstStickyKey()\"\n [class.ui-ist__cell--sticky-end]=\"column.key === lastStickyKey()\"\n [class.ui-ist__cell--right]=\"column.styles?.alignment === 'right'\"\n [class.ui-ist__cell--center]=\"column.styles?.alignment === 'center'\"\n [style.flex-basis]=\"cellBasis(column)\"\n [style.min-width]=\"column.styles?.['min-width']\"\n [style.left.px]=\"stickyStartOffset(column)\"\n >\n @if (row.kind === 'skeleton') {\n <ui-skeleton class=\"ui-ist__skeleton\" [count]=\"1\" [theme]=\"skeletonTheme\" appearance=\"line\"></ui-skeleton>\n } @else if (column.rowCellTemplate) {\n <ng-container\n *ngTemplateOutlet=\"column.rowCellTemplate; context: { $implicit: row.item, rowIndex: row.index }\"\n ></ng-container>\n } @else {\n <span class=\"ui-ist__cell-text\">{{ getCellValue(row.item, column.key) }}</span>\n }\n </div>\n }\n </div>\n </cdk-virtual-scroll-viewport>\n }\n\n <!-- Empty and error states render the consumer template in-frame below the header, mirroring how\n ui-table drops `noDataRowTpl` into the table body. Mid-scroll errors sit below the loaded rows. -->\n @if (showErrorFooter() && errorTemplate(); as errorTpl) {\n <div class=\"ui-ist__state\" role=\"alert\">\n <ng-container *ngTemplateOutlet=\"errorTpl; context: errorContext\"></ng-container>\n </div>\n }\n\n @if (showErrorState() && errorTemplate(); as errorTpl) {\n <div class=\"ui-ist__state\" role=\"alert\">\n <ng-container *ngTemplateOutlet=\"errorTpl; context: errorContext\"></ng-container>\n </div>\n }\n\n @if (showEmptyState() && noDataTemplate(); as emptyTpl) {\n <div class=\"ui-ist__state\">\n <ng-container *ngTemplateOutlet=\"emptyTpl\"></ng-container>\n </div>\n }\n\n <span class=\"ui-ist__sr-only\" role=\"status\" aria-live=\"polite\">{{ statusMessage() }}</span>\n</div>\n", styles: [".bg-teal-60b{background:#1c443c}.bg-teal-30b{background:#31766a}.bg-teal-default{background:#46a997}.bg-teal-30w{background:#7ec3b6}.bg-teal-60w{background:#b5ddd5}.bg-teal-secondary{background:#cbd6cb}.bg-teal-90w{background:#ecf6f5}.bg-petrol-60b{background:#102930}.bg-petrol-30b{background:#1b4754}.bg-petrol-default{background:#276678}.bg-petrol-30w{background:#6894a0}.bg-petrol-60w{background:#a9c2c9}.bg-petrol-secondary{background:#c8d7de}.bg-petrol-90w{background:#e9f0f1}.bg-error-60b{background:#513131}.bg-error-30b{background:#8e5655}.bg-error-60w{background:#e3c3c6}.bg-error-secondary{background:#f0dad9}.bg-error-default{background:#cb7b7a}.bg-warning-secondary{background:#f0d6bb}.bg-warning-default{background:#cca45f}.bg-black{background:#000}.bg-dark{background:#888}.bg-medium{background:#e0e0e0}.bg-grey{background:#ededed}.bg-light{background:#f6f6f6}.bg-white{background:#fff}.bg-box-shadow{background:#00000014}.bg-navigation-subtitle{background:#528593}.bgc-teal-60b{background-color:#1c443c}.bgc-teal-30b{background-color:#31766a}.bgc-teal-default{background-color:#46a997}.bgc-teal-30w{background-color:#7ec3b6}.bgc-teal-60w{background-color:#b5ddd5}.bgc-teal-secondary{background-color:#cbd6cb}.bgc-teal-90w{background-color:#ecf6f5}.bgc-petrol-60b{background-color:#102930}.bgc-petrol-30b{background-color:#1b4754}.bgc-petrol-default{background-color:#276678}.bgc-petrol-30w{background-color:#6894a0}.bgc-petrol-60w{background-color:#a9c2c9}.bgc-petrol-secondary{background-color:#c8d7de}.bgc-petrol-90w{background-color:#e9f0f1}.bgc-error-60b{background-color:#513131}.bgc-error-30b{background-color:#8e5655}.bgc-error-60w{background-color:#e3c3c6}.bgc-error-secondary{background-color:#f0dad9}.bgc-error-default{background-color:#cb7b7a}.bgc-warning-secondary{background-color:#f0d6bb}.bgc-warning-default{background-color:#cca45f}.bgc-black{background-color:#000}.bgc-dark{background-color:#888}.bgc-medium{background-color:#e0e0e0}.bgc-grey{background-color:#ededed}.bgc-light{background-color:#f6f6f6}.bgc-white{background-color:#fff}.bgc-box-shadow{background-color:#00000014}.bgc-navigation-subtitle{background-color:#528593}:host{display:block}.ui-ist{display:flex;flex-direction:column;border:1px solid #e0e0e0;border-radius:8px;overflow:hidden;background:#fff}.ui-ist__header{flex:0 0 auto;box-sizing:border-box;overflow:hidden;border-bottom:1px solid #e0e0e0;background:#fff}.ui-ist__header--sticky{position:sticky;top:0;z-index:3}.ui-ist__body{flex:1 1 auto;overflow:auto;scrollbar-width:auto}.ui-ist__body::-webkit-scrollbar{width:8px;height:8px}.ui-ist__body::-webkit-scrollbar-button{display:none}.ui-ist__body::-webkit-scrollbar-thumb{background-color:#00000059;border-radius:4px}.ui-ist__body::-webkit-scrollbar-track:hover{background-color:#00000026}.ui-ist__row{display:flex;width:max-content;min-width:100%;box-sizing:border-box}.ui-ist__row--header{min-height:56px}.ui-ist__row:not(.ui-ist__row--header){border-bottom:1px solid #d3d3d3}.ui-ist__row--clickable:not(.ui-ist__row--selected):hover{background:#fff2fc}.ui-ist__row--clickable:not(.ui-ist__row--selected):hover .ui-ist__cell{background:#fff2fc}.ui-ist__row--selected .ui-ist__cell{background:#f4f4f4}.ui-ist__cell{flex-grow:1;flex-shrink:0;box-sizing:border-box;display:flex;align-items:center;min-width:160px;padding:8px 24px;font-size:14px;line-height:20px;overflow:hidden;background:#fff}.ui-ist__cell--header{background:#fff;font-weight:700;font-size:14px;line-height:16px}.ui-ist__cell--right{justify-content:flex-end;text-align:right}.ui-ist__cell--center{justify-content:center;text-align:center}.ui-ist__cell--sticky-start{position:sticky;left:0;z-index:2}.ui-ist__cell--sticky-end{position:sticky;right:0;z-index:2}.ui-ist__cell--checkbox{flex:0 0 56px;min-width:56px;justify-content:center;padding:0}.ui-ist__cell-text{overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.ui-ist__skeleton{display:block;width:100%}.ui-ist--scrolled-start .ui-ist__cell--sticky-start{box-shadow:24px 8px 24px #24242414}.ui-ist--scrolled-end .ui-ist__cell--sticky-end{box-shadow:0 8px 24px 4px #24242414}.ui-ist__state{padding:8px 24px;font-size:14px;line-height:20px}.ui-ist--condensed .ui-ist__cell{padding:8px 12px}.ui-ist--condensed .ui-ist__cell:first-child{padding-left:24px}.ui-ist--condensed .ui-ist__cell:last-child{padding-right:24px}.ui-ist__sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}\n"] }]
|
|
349
|
+
}], ctorParameters: () => [], propDecorators: { data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: true }] }], columns: [{ type: i0.Input, args: [{ isSignal: true, alias: "columns", required: true }] }], rowHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowHeight", required: true }] }], trackBy: [{ type: i0.Input, args: [{ isSignal: true, alias: "trackBy", required: false }] }], rowIdKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "rowIdKey", required: false }] }], stickyHeader: [{ type: i0.Input, args: [{ isSignal: true, alias: "stickyHeader", required: false }] }], maxHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxHeight", required: false }] }], isCondensed: [{ type: i0.Input, args: [{ isSignal: true, alias: "isCondensed", required: false }] }], selectable: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectable", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], loadingMore: [{ type: i0.Input, args: [{ isSignal: true, alias: "loadingMore", required: false }] }], hasMore: [{ type: i0.Input, args: [{ isSignal: true, alias: "hasMore", required: false }] }], skeletonRowCount: [{ type: i0.Input, args: [{ isSignal: true, alias: "skeletonRowCount", required: false }] }], loadMoreThreshold: [{ type: i0.Input, args: [{ isSignal: true, alias: "loadMoreThreshold", required: false }] }], noDataTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "noDataTemplate", required: false }] }], errorTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorTemplate", required: false }] }], error: [{ type: i0.Input, args: [{ isSignal: true, alias: "error", required: false }] }], loadMore: [{ type: i0.Output, args: ["loadMore"] }], retry: [{ type: i0.Output, args: ["retry"] }], rowClick: [{ type: i0.Output, args: ["rowClick"] }], selectionChange: [{ type: i0.Output, args: ["selectionChange"] }], viewport: [{ type: i0.ViewChild, args: [i0.forwardRef(() => CdkVirtualScrollViewport), { isSignal: true }] }], headerScroll: [{ type: i0.ViewChild, args: ['headerScroll', { isSignal: true }] }] } });
|
|
350
|
+
|
|
351
|
+
class InfiniteScrollTableComponentModule {
|
|
352
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.18", ngImport: i0, type: InfiniteScrollTableComponentModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
|
|
353
|
+
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.2.18", ngImport: i0, type: InfiniteScrollTableComponentModule, imports: [CommonModule, ScrollingModule, InfiniteScrollTableComponent], exports: [InfiniteScrollTableComponent] }); }
|
|
354
|
+
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.2.18", ngImport: i0, type: InfiniteScrollTableComponentModule, imports: [CommonModule, ScrollingModule, InfiniteScrollTableComponent] }); }
|
|
355
|
+
}
|
|
356
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.18", ngImport: i0, type: InfiniteScrollTableComponentModule, decorators: [{
|
|
357
|
+
type: NgModule,
|
|
358
|
+
args: [{
|
|
359
|
+
imports: [CommonModule, ScrollingModule, InfiniteScrollTableComponent],
|
|
360
|
+
exports: [InfiniteScrollTableComponent],
|
|
361
|
+
}]
|
|
362
|
+
}] });
|
|
363
|
+
|
|
364
|
+
/**
|
|
365
|
+
* Generated bundle index. Do not edit.
|
|
366
|
+
*/
|
|
367
|
+
|
|
368
|
+
export { InfiniteScrollTableComponent, InfiniteScrollTableComponentModule };
|
|
369
|
+
//# sourceMappingURL=testgorilla-tgo-ui-components-infinite-scroll-table.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"testgorilla-tgo-ui-components-infinite-scroll-table.mjs","sources":["../../../components/infinite-scroll-table/infinite-scroll-table.component.ts","../../../components/infinite-scroll-table/infinite-scroll-table.component.html","../../../components/infinite-scroll-table/infinite-scroll-table.component.module.ts","../../../components/infinite-scroll-table/testgorilla-tgo-ui-components-infinite-scroll-table.ts"],"sourcesContent":["import { CdkFixedSizeVirtualScroll, CdkVirtualForOf, CdkVirtualScrollViewport } from '@angular/cdk/scrolling';\nimport { NgTemplateOutlet } from '@angular/common';\nimport {\n booleanAttribute,\n ChangeDetectionStrategy,\n Component,\n computed,\n effect,\n ElementRef,\n input,\n isDevMode,\n output,\n signal,\n TemplateRef,\n TrackByFunction,\n untracked,\n viewChild,\n} from '@angular/core';\nimport { Subscription } from 'rxjs';\n\nimport { CheckboxComponent } from '@testgorilla/tgo-ui/components/checkbox';\nimport { SkeletonComponent } from '@testgorilla/tgo-ui/components/skeleton';\n\nimport {\n InfiniteScrollTableColumn,\n InfiniteScrollTableErrorContext,\n InfiniteScrollTableRowClick,\n InfiniteScrollTableRowSelection,\n} from './infinite-scroll-table.model';\n\n/** Internal row wrapper so real rows and skeleton placeholders flow through one virtual list. */\ntype RenderRow<T> = { kind: 'data'; item: T; index: number } | { kind: 'skeleton'; id: string };\n\n/** Default number of skeleton rows rendered for the initial (full-body) load. */\nconst DEFAULT_FIRST_LOAD_SKELETON_COUNT = 10;\n/** Number of skeleton rows appended below existing rows while the next page is fetched. */\nconst LOAD_MORE_SKELETON_COUNT = 3;\n/** Default distance (in rows) from the end at which `loadMore` fires. */\nconst DEFAULT_LOAD_MORE_THRESHOLD = 5;\n\n/** Fixed width (px) of the checkbox selection column. Must match `.ui-ist__cell--checkbox` in the SCSS. */\nconst CHECKBOX_COLUMN_WIDTH = 56;\n\n/**\n * A generic, virtualized table with scroll-driven infinite loading.\n *\n * Owns rendering, fixed-height vertical virtualization (CDK), horizontal scroll, a pinned header,\n * sticky first/last columns, first-load and load-more skeletons, and a guarded `loadMore` event.\n * All content and layout come from consumer inputs — nothing domain-specific lives here.\n *\n * Independent of `ui-table`: it reuses only stable leaf primitives (`ui-skeleton`) and duplicates\n * the column/context type shapes so consumers can migrate with a selector swap.\n */\n@Component({\n selector: 'ui-infinite-scroll-table',\n templateUrl: './infinite-scroll-table.component.html',\n styleUrls: ['./infinite-scroll-table.component.scss'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [\n NgTemplateOutlet,\n CdkVirtualScrollViewport,\n CdkFixedSizeVirtualScroll,\n CdkVirtualForOf,\n SkeletonComponent,\n CheckboxComponent,\n ],\n})\nexport class InfiniteScrollTableComponent<T> {\n /** Rows loaded so far. The consumer appends pages to this array. */\n readonly data = input.required<T[]>();\n\n /** Column definitions. The first `isSticky` column pins left; the last `isSticky` column pins right. */\n readonly columns = input.required<InfiniteScrollTableColumn<T>[]>();\n\n /**\n * Fixed row height in px — used as the virtualization `itemSize`.\n * Variable / multi-line row heights are unsupported in this variant.\n */\n readonly rowHeight = input.required<number>();\n\n /** Optional stable row identity so recycled rows re-render correctly. Takes precedence over `rowIdKey`. */\n readonly trackBy = input<TrackByFunction<T>>();\n /** Optional key on each row that holds a stable id. Used when `trackBy` is not provided. */\n readonly rowIdKey = input<string>();\n\n /**\n * Accepted for API parity with `ui-table`. In this bounded layout the header is always rendered\n * above the internal scroll region and stays visible regardless — `.ui-ist` has `overflow: hidden`,\n * so the header cannot stick to an outer scrolling page. Kept so `ui-table` templates migrate\n * unchanged. Default `true`.\n */\n readonly stickyHeader = input(true, { transform: booleanAttribute });\n\n /** Max height of the internal scroll region (e.g. `'70vh'`). The body shrinks to fit fewer rows. */\n readonly maxHeight = input<string>('70vh');\n\n /** Condensed spacing. */\n readonly isCondensed = input(false, { transform: booleanAttribute });\n\n /**\n * Enables row selection. When `true`, a dedicated checkbox column is prepended (pinned to the left)\n * and each row's checkbox reflects the row's `selected` property; toggling it emits `selectionChange`.\n * Selection stays data-driven and consumer-managed, exactly like `ui-table`. Default `false`.\n */\n readonly selectable = input(false, { transform: booleanAttribute });\n\n /** First-load state: renders a full body of skeleton rows. */\n readonly loading = input(false, { transform: booleanAttribute });\n\n /** Appends skeleton rows below the existing rows while the next page is fetched. */\n readonly loadingMore = input(false, { transform: booleanAttribute });\n\n /** Whether more pages exist. When `false`, `loadMore` never fires and the load-more skeleton is hidden. */\n readonly hasMore = input(false, { transform: booleanAttribute });\n\n /** Number of skeleton rows for the first-load state. */\n readonly skeletonRowCount = input<number>(DEFAULT_FIRST_LOAD_SKELETON_COUNT);\n\n /** How many rows from the end trigger `loadMore`. */\n readonly loadMoreThreshold = input<number>(DEFAULT_LOAD_MORE_THRESHOLD);\n\n /** Empty-state template, shown when `data` is empty and not loading. */\n readonly noDataTemplate = input<TemplateRef<unknown>>();\n\n /** Error template, shown when `error` is `true`. Receives `{ $implicit: retry, retry }` as context. */\n readonly errorTemplate = input<TemplateRef<InfiniteScrollTableErrorContext>>();\n\n /** Whether a page fetch failed. */\n readonly error = input(false, { transform: booleanAttribute });\n\n /**\n * Fires when the user scrolls within `loadMoreThreshold` rows of the end.\n * Guarded: emits only when `hasMore && !loading && !loadingMore`, and only once per approach.\n */\n readonly loadMore = output<void>();\n\n /** Fires from the error template's retry affordance. */\n readonly retry = output<void>();\n\n /** Fires when a data row is clicked; payload is the row plus its data index. */\n readonly rowClick = output<InfiniteScrollTableRowClick<T>>();\n\n /**\n * Fires when a row's selection checkbox is toggled (only when `selectable`). Payload is the row,\n * its data index, and the new selected state. The consumer updates its data's `selected` property.\n */\n readonly selectionChange = output<InfiniteScrollTableRowSelection<T>>();\n\n /** Fixed width of the checkbox column; exposed so the template can offset a sticky first column. */\n protected readonly checkboxColumnWidth = CHECKBOX_COLUMN_WIDTH;\n\n protected readonly viewport = viewChild(CdkVirtualScrollViewport);\n protected readonly headerScroll = viewChild<ElementRef<HTMLElement>>('headerScroll');\n\n /** Horizontal-scroll state, mirroring the existing table's `scrollSettings`. */\n protected readonly scrollStart = signal(true);\n protected readonly scrollEnd = signal(false);\n protected readonly horizontalScroll = signal(false);\n\n /**\n * Measured width (px) of the body viewport's vertical scrollbar. Reserved as right padding on the\n * header so the header's content width exactly equals the body's, keeping every column — including\n * the last — aligned between header and body regardless of browser/scrollbar behaviour.\n */\n protected readonly scrollbarWidth = signal(0);\n\n /** Guards `loadMore` to a single emission per approach to the end. */\n private loadMoreArmed = true;\n\n protected readonly skeletonTheme = {\n background: '#F4F4F4',\n 'border-radius': '4px',\n height: '24px',\n 'margin-bottom': '0',\n };\n\n // Sticky rule mirrors ui-table (positional): the LAST column pins right when it's sticky; any other\n // sticky column pins left. This way an actions column (always the last column) is always pinned to\n // the right, even when it's the only sticky column.\n protected readonly lastStickyKey = computed(() => {\n const columns = this.columns();\n const lastColumn = columns[columns.length - 1];\n return lastColumn?.isSticky ? lastColumn.key : undefined;\n });\n protected readonly firstStickyKey = computed(() => {\n const columns = this.columns();\n const lastIndex = columns.length - 1;\n return columns.find((column, index) => column.isSticky && index !== lastIndex)?.key;\n });\n\n /** Real rows, with skeleton placeholders in first-load / load-more states, as one virtual list. */\n protected readonly renderRows = computed<RenderRow<T>[]>(() => {\n if (this.loading()) {\n return Array.from({ length: Math.max(1, this.skeletonRowCount()) }, (_, i) => ({\n kind: 'skeleton' as const,\n id: `skeleton-first-${i}`,\n }));\n }\n\n const rows: RenderRow<T>[] = this.data().map((item, index) => ({ kind: 'data' as const, item, index }));\n\n if (this.loadingMore() && this.hasMore()) {\n for (let i = 0; i < LOAD_MORE_SKELETON_COUNT; i++) {\n rows.push({ kind: 'skeleton' as const, id: `skeleton-more-${i}` });\n }\n }\n\n return rows;\n });\n\n protected readonly hasData = computed(() => this.data().length > 0);\n /** The virtualized body is shown for the first-load skeletons and whenever there are rows. */\n protected readonly showViewport = computed(() => this.loading() || this.hasData());\n protected readonly showEmptyState = computed(() => !this.loading() && !this.error() && !this.hasData());\n protected readonly showErrorState = computed(() => !this.loading() && this.error() && !this.hasData());\n protected readonly showErrorFooter = computed(() => !this.loading() && this.error() && this.hasData());\n\n /** Viewport height shrinks to the content and is capped at `maxHeight` (CSS `min()` mixes units). */\n protected readonly viewportHeight = computed(\n () => `min(${this.renderRows().length * this.rowHeight()}px, ${this.maxHeight()})`\n );\n\n /** Screen-reader announcement for the busy states. */\n protected readonly statusMessage = computed(() => {\n if (this.loading()) {\n return 'Loading';\n }\n if (this.loadingMore()) {\n return 'Loading more rows';\n }\n return '';\n });\n\n protected readonly errorContext: InfiniteScrollTableErrorContext = {\n $implicit: () => this.onRetry(),\n retry: () => this.onRetry(),\n };\n\n protected readonly renderRowTrackBy: TrackByFunction<RenderRow<T>> = (index, row): unknown => {\n if (row.kind === 'skeleton') {\n return row.id;\n }\n const explicitTrackBy = this.trackBy();\n if (explicitTrackBy) {\n return explicitTrackBy(row.index, row.item) as unknown;\n }\n const key = this.rowIdKey();\n return key ? (row.item as Record<string, unknown>)[key] : row.index;\n };\n\n constructor() {\n // (Re-)attach scroll listeners whenever the viewport enters or leaves the DOM (empty/error states).\n // Keyed on `viewport()` only: the setup below reads other signals (through syncHorizontalScroll /\n // checkLoadMore), so it runs inside `untracked()` to avoid re-running — and tearing down the\n // subscriptions + ResizeObserver — on every data change or loading toggle.\n effect(onCleanup => {\n const viewport = this.viewport();\n if (!viewport) {\n return;\n }\n untracked(() => {\n const element = viewport.elementRef.nativeElement;\n\n // CDK inserts a generic `.cdk-virtual-scroll-content-wrapper` between the viewport\n // (role=\"rowgroup\") and the rows (role=\"row\"). Mark it presentational so the rows stay\n // owned by the rowgroup and the table's ARIA tree isn't broken for assistive tech.\n element.querySelector('.cdk-virtual-scroll-content-wrapper')?.setAttribute('role', 'presentation');\n\n const subscription = new Subscription();\n subscription.add(viewport.elementScrolled().subscribe(() => this.syncHorizontalScroll()));\n subscription.add(viewport.renderedRangeStream.subscribe(() => this.checkLoadMore()));\n\n // Keep the measured scrollbar width current: it changes when the vertical scrollbar appears\n // or disappears (content grows/shrinks) and on viewport resize.\n const measureScrollbar = (): void => this.scrollbarWidth.set(element.offsetWidth - element.clientWidth);\n subscription.add(viewport.renderedRangeStream.subscribe(() => measureScrollbar()));\n\n let resizeObserver: ResizeObserver | undefined;\n if (typeof ResizeObserver !== 'undefined') {\n resizeObserver = new ResizeObserver(() => measureScrollbar());\n resizeObserver.observe(element);\n }\n\n measureScrollbar();\n this.syncHorizontalScroll();\n this.checkLoadMore();\n\n // The first syncHorizontalScroll() runs before the CDK viewport lays out its rows, so the\n // overflow measurement (and the sticky end-shadow) is stale. Re-sync after the next frame,\n // once layout is settled. Guarded because requestAnimationFrame is browser-only (SSR).\n let scrollSyncFrame: number | undefined;\n if (typeof requestAnimationFrame !== 'undefined') {\n scrollSyncFrame = requestAnimationFrame(() => this.syncHorizontalScroll());\n }\n\n onCleanup(() => {\n subscription.unsubscribe();\n resizeObserver?.disconnect();\n // Cancel a still-pending re-sync so it can't fire after the viewport leaves the DOM\n // (e.g. flipping to the empty/error state in the same tick).\n if (scrollSyncFrame !== undefined) {\n cancelAnimationFrame(scrollSyncFrame);\n }\n });\n });\n });\n\n // Re-arm the loadMore guard whenever the `data` input changes — a page arrived, or the set was\n // replaced (filter/search reset, even to a shorter or same-length list). It reads `data()` only,\n // NOT `loadingMore()`: a failed fetch clears `loadingMore` without changing `data`, so the guard\n // stays disarmed and never re-fires `loadMore` in a loop (the `error()` guard is a second layer).\n effect(() => {\n this.data();\n this.loadMoreArmed = true;\n });\n\n // Dev-only: without `trackBy` or `rowIdKey`, row identity falls back to the data index — the\n // weakest option exactly when rows recycle. If the consumer opts into selection without a stable\n // id, surface the sharp edge so selection state can't silently attach to the wrong row after a\n // reorder/prepend.\n effect(() => {\n if (isDevMode() && this.selectable() && !this.trackBy() && !this.rowIdKey()) {\n console.warn(\n '[ui-infinite-scroll-table] `selectable` is enabled without `trackBy` or `rowIdKey`. ' +\n 'Row identity falls back to the data index, so selection can attach to the wrong row ' +\n 'when rows are reordered or prepended. Provide `trackBy` or `rowIdKey` for stable identity.'\n );\n }\n });\n }\n\n protected getCellValue(item: T, key: string): unknown {\n return (item as Record<string, unknown>)[key];\n }\n\n /**\n * Content-independent flex-basis for a column: its declared width, else its min-width, else the\n * default. Using this (instead of `flex-basis: auto`) makes header and body cells size identically\n * so every column stays aligned regardless of the text inside header vs body cells.\n */\n protected cellBasis(column: InfiniteScrollTableColumn<T>): string {\n return column.styles?.width ?? column.styles?.['min-width'] ?? '160px';\n }\n\n protected onRowClick(row: RenderRow<T>): void {\n if (row.kind !== 'data') {\n return;\n }\n this.rowClick.emit({ ...(row.item as object), index: row.index } as InfiniteScrollTableRowClick<T>);\n }\n\n /**\n * Whether a row should show the selected highlight. Mirrors `ui-table`: only when `selectable` is\n * enabled and the row's data carries a truthy `selected` property. Skeleton rows are never selected.\n */\n protected isRowSelected(row: RenderRow<T>): boolean {\n return this.selectable() && row.kind === 'data' && Boolean((row.item as { selected?: unknown }).selected);\n }\n\n /** Emits the new selection state when a row's checkbox is toggled. Consumer-managed, like `ui-table`. */\n protected onSelectionToggle(row: RenderRow<T>, selected: boolean): void {\n if (row.kind !== 'data') {\n return;\n }\n this.selectionChange.emit({\n ...(row.item as object),\n index: row.index,\n selected,\n } as InfiniteScrollTableRowSelection<T>);\n }\n\n /**\n * Left offset (px) for a sticky-start consumer column: when the checkbox column is present it must\n * sit to the right of it, so the first sticky column is pushed over by the checkbox column width.\n */\n protected stickyStartOffset(column: InfiniteScrollTableColumn<T>): number | null {\n return this.selectable() && column.key === this.firstStickyKey() ? this.checkboxColumnWidth : null;\n }\n\n /** Keyboard equivalent of a row click (Enter/Space) for the currently focused data row. */\n protected onRowActivate(event: Event, row: RenderRow<T>): void {\n event.preventDefault();\n this.onRowClick(row);\n }\n\n private onRetry(): void {\n this.retry.emit();\n }\n\n /** Keep the header horizontally aligned with the body and update the sticky-shadow state. */\n private syncHorizontalScroll(): void {\n const viewport = this.viewport();\n if (!viewport) {\n return;\n }\n const left = viewport.measureScrollOffset('left');\n const right = viewport.measureScrollOffset('right');\n\n const header = this.headerScroll();\n if (header) {\n header.nativeElement.scrollLeft = left;\n }\n this.scrollStart.set(left <= 1);\n this.scrollEnd.set(right <= 1);\n this.horizontalScroll.set(left + right > 1);\n }\n\n /**\n * Emits `loadMore` once when the rendered range reaches the trigger zone near the end,\n * re-arming when the user scrolls back out. Mirrors the app's `ngx-infinite-scroll` semantics.\n */\n private checkLoadMore(): void {\n const viewport = this.viewport();\n // `error()` is part of the guard so a failed page pauses auto-loading until the consumer clears\n // the error (e.g. via the retry affordance), instead of immediately re-firing `loadMore`.\n if (!viewport || !this.hasMore() || this.loading() || this.loadingMore() || this.error()) {\n return;\n }\n\n const dataLength = this.data().length;\n if (dataLength === 0) {\n return;\n }\n\n const renderedEnd = viewport.getRenderedRange().end;\n // Clamp so a negative threshold can't push the trigger point past the end and silently disable\n // loadMore entirely.\n const threshold = Math.max(0, this.loadMoreThreshold());\n const inTriggerZone = renderedEnd >= dataLength - threshold;\n\n if (!inTriggerZone) {\n this.loadMoreArmed = true;\n return;\n }\n\n if (this.loadMoreArmed) {\n this.loadMoreArmed = false;\n this.loadMore.emit();\n }\n }\n}\n","<div\n class=\"ui-ist\"\n role=\"table\"\n [class.ui-ist--condensed]=\"isCondensed()\"\n [class.ui-ist--scrolled-start]=\"!scrollStart()\"\n [class.ui-ist--scrolled-end]=\"horizontalScroll() && !scrollEnd()\"\n [attr.aria-rowcount]=\"hasMore() ? -1 : data().length + 1\"\n [attr.aria-busy]=\"loading() || loadingMore()\"\n>\n <!-- Header: a separate element above the viewport. It never scrolls vertically (stays pinned),\n and its horizontal scrollLeft is synced from the body so columns stay aligned. -->\n <div\n #headerScroll\n class=\"ui-ist__header\"\n [class.ui-ist__header--sticky]=\"stickyHeader()\"\n [style.margin-right.px]=\"scrollbarWidth()\"\n role=\"presentation\"\n >\n <div class=\"ui-ist__row ui-ist__row--header\" role=\"row\" aria-rowindex=\"1\">\n @if (selectable()) {\n <div\n class=\"ui-ist__cell ui-ist__cell--header ui-ist__cell--checkbox ui-ist__cell--sticky-start\"\n role=\"columnheader\"\n ></div>\n }\n @for (column of columns(); track column.key; let colIndex = $index) {\n <div\n class=\"ui-ist__cell ui-ist__cell--header\"\n role=\"columnheader\"\n [class.ui-ist__cell--sticky-start]=\"column.key === firstStickyKey()\"\n [class.ui-ist__cell--sticky-end]=\"column.key === lastStickyKey()\"\n [class.ui-ist__cell--right]=\"column.styles?.alignment === 'right'\"\n [class.ui-ist__cell--center]=\"column.styles?.alignment === 'center'\"\n [style.flex-basis]=\"cellBasis(column)\"\n [style.min-width]=\"column.styles?.['min-width']\"\n [style.left.px]=\"stickyStartOffset(column)\"\n >\n @if (column.headerCellTemplate) {\n <ng-container\n *ngTemplateOutlet=\"column.headerCellTemplate; context: { $implicit: column.title, column, colIndex }\"\n ></ng-container>\n } @else {\n <span class=\"ui-ist__cell-text\">{{ column.title }}</span>\n }\n </div>\n }\n </div>\n </div>\n\n <!-- Body: the CDK viewport owns BOTH vertical (virtualized) and horizontal scroll, so sticky\n columns pin against it and the horizontal scrollbar sits at the viewport bottom. -->\n @if (showViewport()) {\n <cdk-virtual-scroll-viewport\n class=\"ui-ist__body\"\n role=\"rowgroup\"\n [itemSize]=\"rowHeight()\"\n [style.height]=\"viewportHeight()\"\n >\n <div\n *cdkVirtualFor=\"let row of renderRows(); let rowIndex = index; trackBy: renderRowTrackBy\"\n class=\"ui-ist__row\"\n role=\"row\"\n [class.ui-ist__row--clickable]=\"row.kind === 'data'\"\n [class.ui-ist__row--selected]=\"isRowSelected(row)\"\n [attr.aria-selected]=\"isRowSelected(row) ? true : null\"\n [attr.aria-rowindex]=\"row.kind === 'data' ? row.index + 2 : null\"\n [attr.aria-hidden]=\"row.kind === 'skeleton' ? true : null\"\n [attr.tabindex]=\"row.kind === 'data' ? 0 : null\"\n [style.height.px]=\"rowHeight()\"\n (click)=\"onRowClick(row)\"\n (keydown.enter)=\"onRowActivate($event, row)\"\n (keydown.space)=\"onRowActivate($event, row)\"\n >\n @if (selectable()) {\n <div\n class=\"ui-ist__cell ui-ist__cell--checkbox ui-ist__cell--sticky-start\"\n role=\"cell\"\n (click)=\"$event.stopPropagation()\"\n (keydown)=\"$event.stopPropagation()\"\n >\n @if (row.kind === 'data') {\n <ui-checkbox\n [checked]=\"isRowSelected(row)\"\n [ariaLabel]=\"'Select row ' + (row.index + 1)\"\n (changed)=\"onSelectionToggle(row, $event)\"\n ></ui-checkbox>\n }\n </div>\n }\n @for (column of columns(); track column.key) {\n <div\n class=\"ui-ist__cell\"\n role=\"cell\"\n [class.ui-ist__cell--sticky-start]=\"column.key === firstStickyKey()\"\n [class.ui-ist__cell--sticky-end]=\"column.key === lastStickyKey()\"\n [class.ui-ist__cell--right]=\"column.styles?.alignment === 'right'\"\n [class.ui-ist__cell--center]=\"column.styles?.alignment === 'center'\"\n [style.flex-basis]=\"cellBasis(column)\"\n [style.min-width]=\"column.styles?.['min-width']\"\n [style.left.px]=\"stickyStartOffset(column)\"\n >\n @if (row.kind === 'skeleton') {\n <ui-skeleton class=\"ui-ist__skeleton\" [count]=\"1\" [theme]=\"skeletonTheme\" appearance=\"line\"></ui-skeleton>\n } @else if (column.rowCellTemplate) {\n <ng-container\n *ngTemplateOutlet=\"column.rowCellTemplate; context: { $implicit: row.item, rowIndex: row.index }\"\n ></ng-container>\n } @else {\n <span class=\"ui-ist__cell-text\">{{ getCellValue(row.item, column.key) }}</span>\n }\n </div>\n }\n </div>\n </cdk-virtual-scroll-viewport>\n }\n\n <!-- Empty and error states render the consumer template in-frame below the header, mirroring how\n ui-table drops `noDataRowTpl` into the table body. Mid-scroll errors sit below the loaded rows. -->\n @if (showErrorFooter() && errorTemplate(); as errorTpl) {\n <div class=\"ui-ist__state\" role=\"alert\">\n <ng-container *ngTemplateOutlet=\"errorTpl; context: errorContext\"></ng-container>\n </div>\n }\n\n @if (showErrorState() && errorTemplate(); as errorTpl) {\n <div class=\"ui-ist__state\" role=\"alert\">\n <ng-container *ngTemplateOutlet=\"errorTpl; context: errorContext\"></ng-container>\n </div>\n }\n\n @if (showEmptyState() && noDataTemplate(); as emptyTpl) {\n <div class=\"ui-ist__state\">\n <ng-container *ngTemplateOutlet=\"emptyTpl\"></ng-container>\n </div>\n }\n\n <span class=\"ui-ist__sr-only\" role=\"status\" aria-live=\"polite\">{{ statusMessage() }}</span>\n</div>\n","import { ScrollingModule } from '@angular/cdk/scrolling';\nimport { CommonModule } from '@angular/common';\nimport { NgModule } from '@angular/core';\n\nimport { InfiniteScrollTableComponent } from './infinite-scroll-table.component';\n\n@NgModule({\n imports: [CommonModule, ScrollingModule, InfiniteScrollTableComponent],\n exports: [InfiniteScrollTableComponent],\n})\nexport class InfiniteScrollTableComponentModule {}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|