infi-grid 1.0.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.
Files changed (51) hide show
  1. package/CHANGELOG.md +141 -0
  2. package/README.md +654 -0
  3. package/fesm2022/infi-grid.mjs +10314 -0
  4. package/fesm2022/infi-grid.mjs.map +1 -0
  5. package/index.d.ts +5 -0
  6. package/lib/components/cell-editor.component.d.ts +42 -0
  7. package/lib/components/filter-popup.component.d.ts +89 -0
  8. package/lib/components/filter-row.component.d.ts +104 -0
  9. package/lib/components/grid.component.d.ts +155 -0
  10. package/lib/components/header-row.component.d.ts +76 -0
  11. package/lib/components/row.component.d.ts +106 -0
  12. package/lib/components/summary-row.component.d.ts +40 -0
  13. package/lib/components/tooltip-controller.d.ts +43 -0
  14. package/lib/components/viewport.component.d.ts +217 -0
  15. package/lib/core/accessor.d.ts +6 -0
  16. package/lib/core/config-resolver.d.ts +16 -0
  17. package/lib/core/defaults.d.ts +7 -0
  18. package/lib/core/filter-engine.d.ts +44 -0
  19. package/lib/core/format.d.ts +11 -0
  20. package/lib/core/keys.d.ts +24 -0
  21. package/lib/core/row-ops.d.ts +20 -0
  22. package/lib/core/sort-engine.d.ts +11 -0
  23. package/lib/core/summary-engine.d.ts +35 -0
  24. package/lib/core/template-registry.d.ts +27 -0
  25. package/lib/core/theme.d.ts +2 -0
  26. package/lib/core/tooltip-position.d.ts +24 -0
  27. package/lib/core/values.d.ts +21 -0
  28. package/lib/core/virtual-math.d.ts +57 -0
  29. package/lib/directives/grid-template-component.d.ts +16 -0
  30. package/lib/directives/outlet.directive.d.ts +25 -0
  31. package/lib/directives/template.directives.d.ts +98 -0
  32. package/lib/grid.module.d.ts +15 -0
  33. package/lib/models/api.types.d.ts +249 -0
  34. package/lib/models/column.types.d.ts +184 -0
  35. package/lib/models/config.types.d.ts +390 -0
  36. package/lib/models/crud.types.d.ts +179 -0
  37. package/lib/models/data.types.d.ts +41 -0
  38. package/lib/models/events.types.d.ts +98 -0
  39. package/lib/models/filter.types.d.ts +78 -0
  40. package/lib/models/index.d.ts +12 -0
  41. package/lib/models/selection.types.d.ts +173 -0
  42. package/lib/models/sort.types.d.ts +22 -0
  43. package/lib/models/summary.types.d.ts +78 -0
  44. package/lib/models/template.types.d.ts +126 -0
  45. package/lib/models/tooltip.types.d.ts +48 -0
  46. package/lib/state/filter-popup.service.d.ts +30 -0
  47. package/lib/state/grid-api.d.ts +4 -0
  48. package/lib/state/grid-store.d.ts +584 -0
  49. package/lib/state/tooltip.service.d.ts +38 -0
  50. package/package.json +41 -0
  51. package/public-api.d.ts +8 -0
@@ -0,0 +1,43 @@
1
+ import type { GridRowKey } from '../models/data.types';
2
+ import type { GridStore } from '../state/grid-store';
3
+ import type { GridTooltipService } from '../state/tooltip.service';
4
+ /**
5
+ * What a tooltip points at. Body cells are identified by row key and field, not by element: elements are
6
+ * recycled while scrolling, so a recycled element can never keep a stale tooltip.
7
+ */
8
+ export interface TooltipTarget {
9
+ readonly kind: 'cell' | 'header' | 'summary';
10
+ readonly field: string;
11
+ /** The element the tooltip is placed against. */
12
+ readonly element: HTMLElement;
13
+ readonly key?: GridRowKey;
14
+ readonly row?: unknown;
15
+ readonly rowIndex?: number;
16
+ }
17
+ /**
18
+ * Decides when the grid's tooltip shows and with what: the target under the pointer or the keyboard focus,
19
+ * whether its text is cut off (measured once per target, never per frame), the show and hide delays, and the
20
+ * content (a column's `tooltip` function, a tooltip template, or the text).
21
+ */
22
+ export declare class GridTooltipController<TRow> {
23
+ private readonly store;
24
+ private readonly tooltip;
25
+ private target;
26
+ private timer;
27
+ constructor(store: GridStore<TRow>, tooltip: GridTooltipService);
28
+ /** The pointer (or the keyboard focus) is now on `next`, or on nothing. */
29
+ point(next: TooltipTarget | null): void;
30
+ /** Hides it and forgets the target (scrolling, re-rendering): the next pointer move finds the new target. */
31
+ reset(): void;
32
+ /** Hides it but keeps the target, so it only comes back on another target (pointer down, key press). */
33
+ dismiss(): void;
34
+ destroy(): void;
35
+ private schedule;
36
+ private clearTimer;
37
+ /** What a target shows, or null (tooltip off, text not cut off, nothing to say). */
38
+ private content;
39
+ private cellContent;
40
+ private headerContent;
41
+ /** Summary cells show their label and value when they are cut off. */
42
+ private summaryContent;
43
+ }
@@ -0,0 +1,217 @@
1
+ import { OnDestroy } from '@angular/core';
2
+ import type { VirtualizationState } from '../models/api.types';
3
+ import type { FilterModel } from '../models/filter.types';
4
+ import type { SortModelItem } from '../models/sort.types';
5
+ import type { GridCellSelectionSource } from '../models/selection.types';
6
+ import type { GridSummaryResult } from '../models/summary.types';
7
+ import { type IndexRange, type VerticalMetrics } from '../core/virtual-math';
8
+ import { type ColumnLayout, type EditSession, type LayoutColumn, type ViewportHandle } from '../state/grid-store';
9
+ import * as i0 from "@angular/core";
10
+ /**
11
+ * A reusable row slot. Slot `k` renders the row whose index ≡ k (mod pool size).
12
+ * Slots are never destroyed while scrolling: an unused slot keeps its last row and is hidden,
13
+ * because creating or destroying views makes Angular check the whole application.
14
+ */
15
+ interface RowSlot<TRow> {
16
+ readonly key: number;
17
+ row: TRow | null;
18
+ hidden: boolean;
19
+ columns: readonly LayoutColumn<TRow>[];
20
+ rowIndex: number;
21
+ dataIndex: number;
22
+ top: number;
23
+ transform: string;
24
+ version: number;
25
+ edit: EditSession<TRow> | null;
26
+ focusField: string | null;
27
+ selected: boolean;
28
+ selectable: boolean;
29
+ /** The row of the selected cell, with `cellSelection.activeRow`. */
30
+ active: boolean;
31
+ stamp: number;
32
+ }
33
+ interface RenderWindow<TRow> {
34
+ slots: RowSlot<TRow>[];
35
+ columns: readonly LayoutColumn<TRow>[];
36
+ /** Number of plain-cell slots per row (never shrinks while scrolling). */
37
+ columnPool: number;
38
+ /** Number of template-cell slots per row (never shrinks while scrolling). */
39
+ templatePool: number;
40
+ layout: ColumnLayout<TRow>;
41
+ rowRange: IndexRange;
42
+ colRange: IndexRange;
43
+ metrics: VerticalMetrics;
44
+ rowCount: number;
45
+ /** Displayed data columns. */
46
+ columnCount: number;
47
+ /** `aria-colcount`: data columns plus the checkbox and action columns. */
48
+ ariaColCount: number;
49
+ rowHeight: number;
50
+ headerHeight: number;
51
+ /** Height of the filter row (0 without one). */
52
+ filterRowHeight: number;
53
+ /** Rows above the data rows for `aria-rowindex`: the header, and the filter row. */
54
+ headerRows: number;
55
+ summaryHeight: number;
56
+ summaryVisible: boolean;
57
+ summarySticky: boolean;
58
+ summaries: Readonly<Record<string, GridSummaryResult>>;
59
+ sortModel: readonly SortModelItem[];
60
+ filterModel: FilterModel;
61
+ openFilterField: string | null;
62
+ gridEditMode: boolean;
63
+ renderNonce: number;
64
+ canvasWidth: number;
65
+ canvasRowsHeight: number;
66
+ rowsViewportHeight: number;
67
+ /** `virtualization.syncScroll`: the content is positioned by `applyScroll()`. */
68
+ syncScroll: boolean;
69
+ /** Width of the stage with syncScroll: the viewport without its scrollbar. */
70
+ stageWidth: number;
71
+ /** Top of the rows area in the canvas: the header block and the top add row. */
72
+ rowsTop: number;
73
+ /** Height of the rows area (at least the viewport's rows height with a sticky summary row). */
74
+ rowsBoxHeight: number;
75
+ ariaLabel: string;
76
+ selectionOn: boolean;
77
+ multiselect: boolean;
78
+ leadingWidth: number;
79
+ trailingWidth: number;
80
+ selectAllVisible: boolean;
81
+ headerSelectionState: 'none' | 'some' | 'all';
82
+ /** The inline add row's session, and where its band is pinned. */
83
+ addSession: EditSession<TRow> | null;
84
+ addTop: boolean;
85
+ addBottom: boolean;
86
+ /** Bottom offset of the bottom add band (above a sticky summary row). */
87
+ addBottomOffset: number;
88
+ }
89
+ /**
90
+ * The scroll container: header (sticky), virtualized rows, summary row (sticky or inline).
91
+ *
92
+ * Performance design:
93
+ * - scroll, resize, click and key listeners run outside Angular's zone;
94
+ * - on scroll, only this component is checked (`detectChanges()`), and only when the rendered
95
+ * row/column window actually changed — the rest of the application is never checked;
96
+ * - rows live in a fixed pool of slots that are reused, so fast scrolling rebinds existing DOM
97
+ * instead of creating and destroying it;
98
+ * - with `virtualization.syncScroll` (default), the drawn content stays in view while the browser scrolls on its own
99
+ * thread, and moves in the same frame as the rows and columns drawn for the new position: fast scrolling never
100
+ * shows areas that aren't drawn yet (see applyScroll()).
101
+ */
102
+ export declare class GridViewportComponent<TRow = any> implements ViewportHandle, OnDestroy {
103
+ private scrollerRef;
104
+ private rowsRef;
105
+ private innerRef?;
106
+ private trackRef?;
107
+ private readonly store;
108
+ private readonly cdr;
109
+ private readonly zone;
110
+ private readonly tips;
111
+ private scrollTop;
112
+ private scrollLeft;
113
+ private viewportWidth;
114
+ private viewportHeight;
115
+ private focusRow;
116
+ private focusField;
117
+ /** Offsets written by applyScroll(). */
118
+ private appliedLeft;
119
+ private appliedTop;
120
+ private win;
121
+ private memo;
122
+ private slots;
123
+ private columnPool;
124
+ private templatePool;
125
+ private poolLayout;
126
+ private poolWidth;
127
+ private stamp;
128
+ private resizeObserver;
129
+ private readonly cleanup;
130
+ private destroyed;
131
+ constructor();
132
+ ngOnDestroy(): void;
133
+ /** Called from the template. Returns the cached window unless an input of the window changed. */
134
+ renderWindow(): RenderWindow<TRow>;
135
+ /**
136
+ * syncScroll: moves the content to the current scroll position. The stage is sticky, so while the browser scrolls
137
+ * on its own thread it stays in view with the content drawn for the last position (the rows track sticks under the
138
+ * header the same way). The content only moves here: from the scroll handler, in the same task that draws the rows
139
+ * and columns for the new position, so a frame never shows the new position without them. Not template bindings:
140
+ * the offsets change on every scroll frame, also when the drawn window doesn't (no change detection then).
141
+ *
142
+ * The offsets are the ones the browser gives the sticky elements: the stage moves right by `scrollLeft` (the inner
143
+ * block moves back by the same amount), the track moves down by `scrollTop`, up to the end of the rows area.
144
+ */
145
+ private applyScroll;
146
+ /**
147
+ * syncScroll: places the pinned regions (checkbox and action columns of the rows, header, filter and summary rows)
148
+ * at the viewport edges. Without syncScroll they are sticky, but a sticky element in every row makes the browser
149
+ * give every row its own layer: dozens of layers to update while scrolling. With syncScroll the grid moves the
150
+ * content itself, so it places them too (`is-placed`, absolutely positioned): rows place theirs when they are drawn
151
+ * (`GridStore.pinPlacement`), and this moves the ones already drawn, in the frame the content moves.
152
+ */
153
+ private placePins;
154
+ /**
155
+ * Sizes the cell pools for the widest window the layout can produce, once per layout/viewport
156
+ * width, so scrolling sideways never grows them (growing creates views, which makes Angular check
157
+ * the whole application). Pools only grow; they are capped at the number of displayed columns.
158
+ */
159
+ private sizeColumnPools;
160
+ scrollToRow(rowIndex: number, position: 'auto' | 'start' | 'center' | 'end'): void;
161
+ scrollToColumn(columnIndex: number, position: 'auto' | 'start' | 'center' | 'end'): void;
162
+ /** Horizontal scroll position that shows a column next to (not under) the pinned regions. */
163
+ private alignColumn;
164
+ getVirtualizationState(): VirtualizationState;
165
+ focus(): void;
166
+ focusCell(rowIndex: number, field: string, source?: GridCellSelectionSource): void;
167
+ private attach;
168
+ private measure;
169
+ /** Scroll handler (outside the zone). Checks only this component, and only if the window changed. */
170
+ private onScroll;
171
+ /** True when the new scroll position needs different rows/columns (or scaled positions). */
172
+ private windowChanged;
173
+ /** The row (and cell) under a pointer event, from the DOM attributes the viewport renders. */
174
+ private hitRow;
175
+ private dataIndexAt;
176
+ private cellEvent;
177
+ /**
178
+ * Emits the click (or double-click) events of a row. They always fire; a handler that sets `cancel`
179
+ * stops the grid's built-in reaction. Returns true when a handler cancelled.
180
+ */
181
+ private emitClickEvents;
182
+ /** Click events waiting for a possible double click (`events.clickMode: 'waitForDoubleClick'`). */
183
+ private pendingClick;
184
+ private clearPendingClick;
185
+ private onClick;
186
+ /** Makes a row's checkbox show that row's selection state. */
187
+ private syncSelectorBox;
188
+ private onRowClick;
189
+ /** Buttons of the action column: edit, delete, save and cancel on rows (and the add row), add in the header. */
190
+ private onActionClick;
191
+ private onContextMenu;
192
+ /** The hovered cell, identified by row key and field (not by element: elements are recycled). */
193
+ private hover;
194
+ private hoverFrame;
195
+ private hoverEvent;
196
+ private listensToHover;
197
+ /** At most one hit test per animation frame, however fast the pointer moves. */
198
+ private onPointerMove;
199
+ /** The cell, header or summary cell under the pointer that can have a tooltip. */
200
+ private tooltipTarget;
201
+ /** Keyboard focus on a header's filter button shows the header tooltip. */
202
+ private onFocusIn;
203
+ /** Keyboard focus moved to a cell: its tooltip shows after the delay, as on hover. */
204
+ private focusTooltip;
205
+ /** Changes the hovered cell, emitting leave for the old one and enter for the new one. */
206
+ private setHover;
207
+ private onDoubleClick;
208
+ private onKeydown;
209
+ private focusEditorAt;
210
+ /** The focused cell. With cell selection it is the selected cell (by key, so it is right also before a re-render). */
211
+ private focusPosition;
212
+ /** Moves the focus to a cell; with cell selection, that cell becomes the selected cell (`source` and `event` say why). */
213
+ private setFocus;
214
+ static ɵfac: i0.ɵɵFactoryDeclaration<GridViewportComponent<any>, never>;
215
+ static ɵcmp: i0.ɵɵComponentDeclaration<GridViewportComponent<any>, "infi-grid-viewport", never, {}, {}, never, never, true, never>;
216
+ }
217
+ export {};
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Compiled field accessors. `'price'` reads `row.price`; `'customer.name'` reads `row.customer?.name`.
3
+ * Compiling once per column keeps the per-cell cost to a property read.
4
+ */
5
+ export declare function compileGetter(field: string): (row: any) => any;
6
+ export declare function compileSetter(field: string): ((row: any, value: any) => void) | null;
@@ -0,0 +1,16 @@
1
+ import type { ColumnConfig, ResolvedColumn } from '../models/column.types';
2
+ import type { GridConfig, ResolvedGridConfig } from '../models/config.types';
3
+ import type { GridErrorEvent } from '../models/events.types';
4
+ import type { TemplateRegistry } from './template-registry';
5
+ /** Copies an object without its `undefined` properties, so they don't override defaults when spread. */
6
+ export declare function stripUndefined<T extends object>(value: T): Partial<T>;
7
+ /** Fills every default of the grid configuration. */
8
+ export declare function resolveConfig<TRow>(config: GridConfig<TRow> | null | undefined): ResolvedGridConfig<TRow>;
9
+ /**
10
+ * Merges each column with `defaultColumn` and the global flags (column settings win),
11
+ * compiles accessors/formatters, and resolves templates (most specific first):
12
+ * column property → field directive → type template (config, then directive) → default column → built-in.
13
+ */
14
+ export declare function resolveColumns<TRow>(columns: readonly ColumnConfig<TRow>[] | null | undefined, config: ResolvedGridConfig<TRow>, registry: TemplateRegistry, onError?: (event: GridErrorEvent) => void): ResolvedColumn<TRow>[];
15
+ /** Whether a column is editable for a given row (it must also be writable). */
16
+ export declare function isColumnEditable<TRow>(column: ResolvedColumn<TRow>, row: TRow): boolean;
@@ -0,0 +1,7 @@
1
+ import type { GridText } from '../models/config.types';
2
+ export declare const DEFAULT_ROW_HEIGHT = 36;
3
+ export declare const DEFAULT_HEADER_HEIGHT = 40;
4
+ export declare const DEFAULT_COLUMN_WIDTH = 150;
5
+ export declare const DEFAULT_MIN_COLUMN_WIDTH = 48;
6
+ export declare const DEFAULT_MAX_COLUMN_WIDTH = 4000;
7
+ export declare const DEFAULT_TEXT: GridText;
@@ -0,0 +1,44 @@
1
+ import type { GridDataType, ResolvedColumn } from '../models/column.types';
2
+ import { type ColumnFilterModel, type FilterCondition, type FilterModel } from '../models/filter.types';
3
+ export type RowPredicate<TRow> = (row: TRow) => boolean;
4
+ type ValuePredicate = (value: unknown, row: any) => boolean;
5
+ /** True when the model would remove rows. */
6
+ export declare function isColumnFilterActive(model: ColumnFilterModel | null | undefined): boolean;
7
+ /** Removes inactive column entries. */
8
+ export declare function normalizeFilterModel(model: FilterModel | null | undefined): FilterModel;
9
+ /**
10
+ * Key used by the Excel-style value list: text → string, number → number,
11
+ * date → `'YYYY-MM-DD'`, boolean → true/false. Blanks → `null`.
12
+ */
13
+ export declare function valueKey(value: unknown, type: GridDataType): string | number | boolean | null;
14
+ /** Compiles one condition; `null` means the condition is incomplete and is ignored. */
15
+ export declare function compileCondition<TRow>(column: ResolvedColumn<TRow>, cond: FilterCondition): ValuePredicate | null;
16
+ /** Compiles the filter of one column into a row predicate, or `null` when it removes nothing. */
17
+ export declare function compileColumnFilter<TRow>(column: ResolvedColumn<TRow>, model: ColumnFilterModel): RowPredicate<TRow> | null;
18
+ /** Compiles the whole filter model (optionally skipping one column, for Excel-style cascading value lists). */
19
+ export declare function compileFilterModel<TRow>(model: FilterModel, columns: ReadonlyMap<string, ResolvedColumn<TRow>>, excludeField?: string): RowPredicate<TRow>[];
20
+ /**
21
+ * Keeps the rows that pass every predicate, preserving `order` (sorted indexes, or natural order when null).
22
+ * Rows in `alwaysInclude` pass regardless (rows just added, kept visible until the filter changes).
23
+ * Returns `null` when nothing is filtered, so callers can reuse `order` without copying.
24
+ */
25
+ export declare function filterIndices<TRow>(data: readonly TRow[], order: readonly number[] | null, predicates: readonly RowPredicate<TRow>[], alwaysInclude?: ReadonlySet<TRow> | null): number[] | null;
26
+ export interface ValueListItem {
27
+ key: string | number | boolean | null;
28
+ label: string;
29
+ count: number;
30
+ }
31
+ export interface ValueListResult {
32
+ items: ValueListItem[];
33
+ truncated: boolean;
34
+ }
35
+ /**
36
+ * Distinct values of a column for the Excel-style checkbox list, from the rows that pass
37
+ * the filters of all *other* columns (like Excel). Sorted ascending, blanks last.
38
+ */
39
+ export declare function distinctValues<TRow>(data: readonly TRow[], column: ResolvedColumn<TRow>, model: FilterModel, columns: ReadonlyMap<string, ResolvedColumn<TRow>>, options: {
40
+ locale: string | undefined;
41
+ blanksLabel: string;
42
+ limit: number;
43
+ }): ValueListResult;
44
+ export {};
@@ -0,0 +1,11 @@
1
+ import type { ColumnConfig, GridDataType } from '../models/column.types';
2
+ import type { GridText } from '../models/config.types';
3
+ /** `Intl.NumberFormat` instances are expensive to create, so they are cached by locale + options. */
4
+ export declare function getNumberFormat(locale: string | undefined, options?: Intl.NumberFormatOptions): Intl.NumberFormat;
5
+ export declare function getDateFormat(locale: string | undefined, options?: Intl.DateTimeFormatOptions): Intl.DateTimeFormat;
6
+ export type ValueFormatter = (value: any, row?: any) => string;
7
+ /**
8
+ * Builds the display formatter of a column. A failing custom `valueFormatter`
9
+ * shows `#ERROR` in the cell and is reported once through `onError`.
10
+ */
11
+ export declare function createFormatter(column: Pick<ColumnConfig, 'valueFormatter' | 'numberFormat' | 'dateFormat' | 'booleanLabels'>, type: GridDataType, locale: string | undefined, text: GridText, onError?: (error: unknown) => void): ValueFormatter;
@@ -0,0 +1,24 @@
1
+ import type { GridRowKey } from '../models/data.types';
2
+ /** Returns the key of a row. */
3
+ export type KeyAccessor<TRow> = (row: TRow) => GridRowKey;
4
+ /** Compiles `config.primaryKey` (field, dot path or function). Without one, the row object is the key. */
5
+ export declare function compileKeyAccessor<TRow>(primaryKey: string | ((row: TRow) => GridRowKey) | null): KeyAccessor<TRow>;
6
+ /** A key that can't identify a row: `null`, `undefined`, `''` or `NaN`. */
7
+ export declare function isMissingKey(key: unknown): boolean;
8
+ /** Data position of each key, built once per data version. */
9
+ export interface KeyIndex {
10
+ /** Key → position in the data array (the first row wins when keys repeat). */
11
+ readonly positions: ReadonlyMap<GridRowKey, number>;
12
+ /** Distinct keys that occur more than once (at most 10 are listed). */
13
+ readonly duplicates: readonly GridRowKey[];
14
+ /** Number of distinct repeated keys (`duplicates` lists at most 10 of them). */
15
+ readonly distinctDuplicateCount: number;
16
+ /** Rows sharing a key with an earlier row. */
17
+ readonly duplicateCount: number;
18
+ /** Rows without a usable key. */
19
+ readonly missingCount: number;
20
+ }
21
+ /** Builds the key index of `data` in one pass. `checkMissing` is false when rows are their own keys. */
22
+ export declare function buildKeyIndex<TRow>(data: readonly TRow[], keyOf: KeyAccessor<TRow>, checkMissing: boolean): KeyIndex;
23
+ /** Human-readable description of the problems in a key index, or null when the keys are valid. */
24
+ export declare function describeKeyProblems(index: KeyIndex, primaryKey: string | null): string | null;
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Helpers for adding, updating and deleting rows: emptiness, row copies (for `oldRow` snapshots and
3
+ * validation previews), positions and validation results.
4
+ */
5
+ import type { GridAddPosition, GridRowValidationResult } from '../models/crud.types';
6
+ /** Values a `required` field doesn't accept: null, undefined, blank text, NaN and invalid dates. */
7
+ export declare function isEmptyValue(value: unknown): boolean;
8
+ /** Shallow copy that keeps the prototype, so class instances keep their methods and getters. */
9
+ export declare function shallowCopy<T>(value: T): T;
10
+ /**
11
+ * Copy of a row in which the objects along each dot path are copied too, so that writing those paths on
12
+ * the copy leaves the row unchanged (and the copy keeps the old values when the row is written).
13
+ * With `oneLevel`, every object property of the row is copied as well, for custom `valueSetter`s that may
14
+ * write into nested objects outside their field path.
15
+ */
16
+ export declare function copyAlongPaths<T>(row: T, paths: Iterable<string>, oneLevel?: boolean): T;
17
+ /** Data index for a new row. */
18
+ export declare function resolveAddPosition(position: GridAddPosition | undefined, fallback: 'top' | 'bottom', length: number): number;
19
+ /** Adds the messages of a `rowValidator` result to `errors` (`'$row'` for a row-level message). Existing messages win. */
20
+ export declare function mergeRowValidation(result: GridRowValidationResult, errors: Record<string, string>): void;
@@ -0,0 +1,11 @@
1
+ import type { ResolvedColumn } from '../models/column.types';
2
+ import type { SortModelItem } from '../models/sort.types';
3
+ export interface SortOptions {
4
+ locale: string | undefined;
5
+ nulls: 'first' | 'last';
6
+ }
7
+ /**
8
+ * Returns data indexes in sorted order, or `null` when the model has no usable entry
9
+ * (natural data order). The sort is stable; ties keep their original order.
10
+ */
11
+ export declare function sortIndices<TRow>(data: readonly TRow[], model: readonly SortModelItem[], columns: ReadonlyMap<string, ResolvedColumn<TRow>>, options: SortOptions): number[] | null;
@@ -0,0 +1,35 @@
1
+ import type { GridApi } from '../models/api.types';
2
+ import type { ResolvedColumn } from '../models/column.types';
3
+ import type { GridErrorEvent } from '../models/events.types';
4
+ import type { FilterModel } from '../models/filter.types';
5
+ import type { SortModelItem } from '../models/sort.types';
6
+ import type { GridSummaryHelpers, GridSummaryResult } from '../models/summary.types';
7
+ export declare const SUMMARY_HELPERS: GridSummaryHelpers;
8
+ export interface SummaryInput<TRow> {
9
+ data: readonly TRow[];
10
+ /** Rows after filtering (and sorting). */
11
+ rows: readonly TRow[];
12
+ columns: readonly ResolvedColumn<TRow>[];
13
+ /** Edit counter per field; a summary is recalculated only when its fields changed. */
14
+ fieldVersion: (field: string) => number;
15
+ /** Increases on every edit; used for custom summaries without `dependsOn`. */
16
+ editVersion: number;
17
+ /** Changes on `recalculateSummary()` for the given field (or all fields). */
18
+ forceVersion: (field: string) => string;
19
+ api: GridApi<TRow>;
20
+ filterModel: FilterModel;
21
+ sortModel: readonly SortModelItem[];
22
+ locale: string | undefined;
23
+ onError?: (event: GridErrorEvent) => void;
24
+ }
25
+ /**
26
+ * Calculates column summaries with a per-column cache. A column is recalculated only when
27
+ * its rows, its column definition, or the fields it depends on changed, so editing one cell
28
+ * recalculates one summary instead of all of them.
29
+ */
30
+ export declare class SummaryEngine<TRow> {
31
+ private cache;
32
+ compute(input: SummaryInput<TRow>): Record<string, GridSummaryResult>;
33
+ clear(): void;
34
+ private format;
35
+ }
@@ -0,0 +1,27 @@
1
+ import type { GridDataType } from '../models/column.types';
2
+ import type { GridTemplate } from '../models/template.types';
3
+ /** Templates declared with `<ng-template infiGrid…>` directives inside `<infi-grid>`. */
4
+ export interface TemplateRegistry {
5
+ readonly display: TemplateGroup;
6
+ readonly edit: TemplateGroup;
7
+ readonly header: TemplateGroup;
8
+ readonly summary: TemplateGroup;
9
+ readonly cellTooltip: TemplateGroup;
10
+ readonly headerTooltip: TemplateGroup;
11
+ readonly loading: GridTemplate<any> | null;
12
+ readonly empty: GridTemplate<any> | null;
13
+ readonly error: GridTemplate<any> | null;
14
+ }
15
+ export interface TemplateGroup {
16
+ readonly byField: ReadonlyMap<string, GridTemplate<any>>;
17
+ readonly byType: ReadonlyMap<GridDataType, GridTemplate<any>>;
18
+ /** Directive without `field` or `type`: applies to every column. */
19
+ readonly fallback: GridTemplate<any> | null;
20
+ }
21
+ export declare const EMPTY_TEMPLATE_REGISTRY: TemplateRegistry;
22
+ export interface TemplateDirectiveLike {
23
+ readonly template: GridTemplate<any>;
24
+ readonly field: string | undefined;
25
+ readonly type: GridDataType | undefined;
26
+ }
27
+ export declare function buildTemplateGroup(directives: readonly TemplateDirectiveLike[]): TemplateGroup;
@@ -0,0 +1,2 @@
1
+ /** CSS custom properties used for theming (copied onto the filter popup, which lives in `<body>`). */
2
+ export declare const THEME_VARIABLES: readonly string[];
@@ -0,0 +1,24 @@
1
+ import type { GridTooltipPlacement } from '../models/tooltip.types';
2
+ export interface TooltipRect {
3
+ readonly left: number;
4
+ readonly top: number;
5
+ readonly width: number;
6
+ readonly height: number;
7
+ }
8
+ export interface TooltipPosition {
9
+ readonly left: number;
10
+ readonly top: number;
11
+ /** The side used: the preferred one, or the opposite side when the preferred one has no room. */
12
+ readonly placement: GridTooltipPlacement;
13
+ }
14
+ /**
15
+ * Places a tooltip of `size` next to `anchor` (both in viewport coordinates), centered on it.
16
+ * Flips to the opposite side when the preferred side has no room, then keeps it inside the viewport.
17
+ */
18
+ export declare function placeTooltip(anchor: TooltipRect, size: {
19
+ readonly width: number;
20
+ readonly height: number;
21
+ }, viewport: {
22
+ readonly width: number;
23
+ readonly height: number;
24
+ }, placement: GridTooltipPlacement, gap?: number, margin?: number): TooltipPosition;
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Value normalization shared by sorting, filtering, formatting and summaries.
3
+ * Everything here is allocation-free on the hot path and never throws.
4
+ */
5
+ export declare function isBlank(value: unknown): boolean;
6
+ /** Number or null. Booleans become 1/0, dates their timestamp. */
7
+ export declare function toNumber(value: unknown): number | null;
8
+ /** Timestamp (ms) or null. `'YYYY-MM-DD'` strings are read as local dates. */
9
+ export declare function toTimestamp(value: unknown): number | null;
10
+ /** true / false / null. Accepts booleans, 1/0 and 'true'/'false'/'yes'/'no'. */
11
+ export declare function toBoolean(value: unknown): boolean | null;
12
+ /** Local calendar day as a sortable number: 2024-05-01 → 20240501. */
13
+ export declare function dayNumber(timestamp: number): number;
14
+ /** Local calendar day as `'YYYY-MM-DD'`. */
15
+ export declare function dayKey(timestamp: number): string;
16
+ /** Timestamp of local midnight for a `'YYYY-MM-DD'` key. */
17
+ export declare function dayKeyToTimestamp(key: string): number | null;
18
+ /** Relative float comparison so that computed values like 0.1 + 0.2 equal 0.3. */
19
+ export declare function numbersEqual(a: number, b: number): boolean;
20
+ /** Cached, case-insensitive, number-aware collator ("item 2" < "item 10"). */
21
+ export declare function getCollator(locale: string | undefined): Intl.Collator;
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Pure virtualization math. Row heights are fixed, so every position is O(1);
3
+ * column positions use prefix sums and binary search.
4
+ */
5
+ /**
6
+ * Browsers cap element height (Chrome ~33.5M px, Firefox ~17.9M px). Above this height the
7
+ * rows canvas stays at this size and scroll positions are scaled to the real row positions.
8
+ */
9
+ export declare const MAX_CANVAS_HEIGHT = 15000000;
10
+ export interface VerticalMetrics {
11
+ /** Height of all rows (rowCount × rowHeight). */
12
+ totalHeight: number;
13
+ /** Height of the scrollable rows canvas (≤ MAX_CANVAS_HEIGHT). */
14
+ canvasHeight: number;
15
+ /** totalHeight / canvasHeight scroll ratio, 1 when no scaling is needed. */
16
+ scale: number;
17
+ /** Scroll position in real row coordinates. */
18
+ virtualTop: number;
19
+ /** Subtract from `rowIndex × rowHeight` to get the row's position inside the canvas. */
20
+ offset: number;
21
+ }
22
+ export declare function computeVerticalMetrics(scrollTop: number, viewportHeight: number, rowCount: number, rowHeight: number, maxCanvasHeight?: number): VerticalMetrics;
23
+ export interface IndexRange {
24
+ /** First rendered index (inclusive). */
25
+ start: number;
26
+ /** Last rendered index (exclusive). */
27
+ end: number;
28
+ /** First index inside the viewport (inclusive). */
29
+ visibleStart: number;
30
+ /** Last index inside the viewport (exclusive). */
31
+ visibleEnd: number;
32
+ }
33
+ export declare function computeRowRange(metrics: VerticalMetrics, viewportHeight: number, rowCount: number, rowHeight: number, buffer: number, virtualize: boolean): IndexRange;
34
+ /** Pool size needed to cover the viewport plus buffers; rendered rows reuse these slots. */
35
+ export declare function rowPoolSize(viewportHeight: number, rowHeight: number, buffer: number): number;
36
+ export interface ColumnOffsets {
37
+ offsets: number[];
38
+ total: number;
39
+ }
40
+ export declare function computeColumnOffsets(widths: readonly number[]): ColumnOffsets;
41
+ /** Index of the column containing x (the last column whose left edge is ≤ x). */
42
+ export declare function columnIndexAt(offsets: readonly number[], x: number): number;
43
+ export declare function computeColumnRange(scrollLeft: number, viewportWidth: number, offsets: readonly number[], buffer: number, virtualize: boolean): IndexRange;
44
+ /**
45
+ * Largest column window any horizontal scroll position can render (visible columns + buffers),
46
+ * and the largest number of flagged columns (e.g. columns with templates) in such a window.
47
+ * Used to size the cell pools once, so they never grow (and create views) while scrolling.
48
+ */
49
+ export declare function maxColumnWindow(offsets: readonly number[], totalWidth: number, viewportWidth: number, buffer: number, flags: readonly (readonly boolean[])[]): {
50
+ columns: number;
51
+ flagged: number[];
52
+ };
53
+ export type ScrollAlign = 'auto' | 'start' | 'center' | 'end';
54
+ /** Target position (in real coordinates) that brings [itemStart, itemStart + itemSize) into view. */
55
+ export declare function alignedScrollTarget(itemStart: number, itemSize: number, viewportSize: number, current: number, contentSize: number, align: ScrollAlign): number;
56
+ /** Converts a real row position to the element's scrollTop (undoes scroll scaling). */
57
+ export declare function virtualToScrollTop(virtualTop: number, metrics: VerticalMetrics): number;
@@ -0,0 +1,16 @@
1
+ import * as i0 from "@angular/core";
2
+ /**
3
+ * Base class for components used as grid templates (cell, edit, header, summary, loading, empty, error).
4
+ * It declares the `context` input the grid sets.
5
+ *
6
+ * ```ts
7
+ * @Component({ template: `<b>{{ context().value }}</b>` })
8
+ * export class PriceCell extends GridTemplateComponent<GridCellContext<Order, number>> {}
9
+ * ```
10
+ * Components that don't extend it can declare their own `context` input instead.
11
+ */
12
+ export declare abstract class GridTemplateComponent<C> {
13
+ readonly context: import("@angular/core").InputSignal<C>;
14
+ static ɵfac: i0.ɵɵFactoryDeclaration<GridTemplateComponent<any>, never>;
15
+ static ɵdir: i0.ɵɵDirectiveDeclaration<GridTemplateComponent<any>, never, never, { "context": { "alias": "context"; "required": true; "isSignal": true; }; }, {}, never, never, true, never>;
16
+ }
@@ -0,0 +1,25 @@
1
+ import { OnChanges, OnDestroy } from '@angular/core';
2
+ import type { GridTemplate } from '../models/template.types';
3
+ import * as i0 from "@angular/core";
4
+ /**
5
+ * Renders a `TemplateRef` or a component with a context object.
6
+ *
7
+ * The view is created once and reused when rows are recycled during scrolling:
8
+ * for templates the new context is copied into the existing view context (no re-creation,
9
+ * no proxy); for components the `context` input is updated.
10
+ */
11
+ export declare class GridOutletDirective<C extends object = any> implements OnChanges, OnDestroy {
12
+ template: GridTemplate<C> | null;
13
+ context: C | null;
14
+ private readonly vcr;
15
+ private viewRef;
16
+ private componentRef;
17
+ private rendered;
18
+ ngOnChanges(): void;
19
+ ngOnDestroy(): void;
20
+ private create;
21
+ private update;
22
+ private clear;
23
+ static ɵfac: i0.ɵɵFactoryDeclaration<GridOutletDirective<any>, never>;
24
+ static ɵdir: i0.ɵɵDirectiveDeclaration<GridOutletDirective<any>, "[infiGridOutlet]", never, { "template": { "alias": "infiGridOutlet"; "required": false; }; "context": { "alias": "infiGridOutletContext"; "required": false; }; }, {}, never, never, true, never>;
25
+ }