eru-grid 0.0.41 → 0.0.43

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eru-grid",
3
- "version": "0.0.41",
3
+ "version": "0.0.43",
4
4
  "peerDependencies": {
5
5
  "@angular/common": "^21.1.2",
6
6
  "@angular/core": "^21.1.2",
@@ -68,6 +68,8 @@ interface GridFeatures {
68
68
  allowSelection?: boolean;
69
69
  actionColumn?: boolean;
70
70
  actionColumnPosition?: 'before' | 'after';
71
+ actions?: GridAction[];
72
+ action_display_type?: 'icons' | 'kebab';
71
73
  designMode?: boolean;
72
74
  groupBar?: boolean;
73
75
  excel_download?: boolean;
@@ -98,7 +100,9 @@ interface GridFeatures {
98
100
  boardCardSelectedBg?: string;
99
101
  boardCardSelectedOutline?: string;
100
102
  boardColumnMinWidth?: number;
103
+ boardColumnMaxWidth?: number;
101
104
  boardColumnHeight?: number;
105
+ boardWrapColumns?: boolean;
102
106
  }
103
107
  interface ExcelDownloadPayload {
104
108
  columns: Record<string, {
@@ -174,6 +178,24 @@ interface ServerValidationNotice {
174
178
  status: 'success' | 'error';
175
179
  msg: string;
176
180
  }
181
+ /**
182
+ * One action offered on every row, rendered in the action column.
183
+ *
184
+ * `action_name` is both the tooltip (icon mode) / label (kebab mode) and the
185
+ * identity the consumer matches on when the click comes back — eru-studio keys
186
+ * its configured 'Custom Action' subscription off it — so it has to be unique
187
+ * within a grid.
188
+ *
189
+ * `action_visible_condition` is a row-scoped expression in the same language
190
+ * eru-studio uses for its logic (`@field is not 'closed' AND @amount > 1000`),
191
+ * evaluated per row against that row's column values. Blank means always
192
+ * visible; see evaluateRowCondition().
193
+ */
194
+ interface GridAction {
195
+ action_name: string;
196
+ action_icon?: string;
197
+ action_visible_condition?: string;
198
+ }
177
199
  interface GridStyles {
178
200
  subTotalStyle?: 'bold' | 'italic' | 'highlighted';
179
201
  grandTotalStyle?: 'bold' | 'italic' | 'highlighted';
@@ -483,16 +505,67 @@ interface PivotResult {
483
505
  headerStructure?: PivotHeaderStructure;
484
506
  columnGroupState?: PivotColumnGroupState;
485
507
  }
508
+ /**
509
+ * A drill click on a data cell, in either table or pivot mode.
510
+ *
511
+ * `columnName` is the key the consumer matches on to decide what to do: a
512
+ * column name in table mode, and in pivot mode the leaf name — which for an
513
+ * aggregated cell is the aggregation's name. `pivotPath` carries the column
514
+ * dimension values that located the cell, and those are also merged into
515
+ * `rowData` so the whole coordinate of the clicked cell reads off one object.
516
+ */
517
+ /**
518
+ * What kind of pivot row a drilled cell sits on. A total aggregates rows the
519
+ * cell does not name, so a consumer has to treat it differently from a data
520
+ * cell — see Drilldown.scope.
521
+ */
522
+ type PivotRowKind = 'data' | 'row_subtotal' | 'row_grand_total';
523
+ /** What kind of pivot column a drilled cell sits in. */
524
+ type PivotColumnKind = 'data' | 'column_grand_total';
486
525
  interface Drilldown {
487
526
  frozenGrandTotalCell: boolean;
488
527
  columnName: string;
489
528
  rowId: string;
490
529
  rowData?: any;
491
530
  columnValue: any;
531
+ /** 'table' | 'pivot' — which surface the click came from. */
532
+ mode?: GridMode;
533
+ /** Pivot column-dimension values leading to this cell, outermost first. */
534
+ pivotPath?: string[];
535
+ /** The full leaf column name, pivot path included (pivot mode only). */
536
+ leafColumnName?: string;
537
+ /**
538
+ * Which row and column the cell belongs to, in total terms. A subtotal or
539
+ * grand-total cell is otherwise indistinguishable from a data cell — same
540
+ * column name, same shape of value — so a consumer could not tell that the
541
+ * number covers rows beyond the ones the cell names.
542
+ */
543
+ rowKind?: PivotRowKind;
544
+ columnKind?: PivotColumnKind;
545
+ /**
546
+ * The dimension values this cell is actually scoped to — what a consumer
547
+ * should filter the source by to reach the rows behind it.
548
+ *
549
+ * For a data cell that is every row and column dimension. For a row subtotal
550
+ * only the dimensions fixed at that level appear, because the rest are rolled
551
+ * up; for a grand total it is empty, meaning "everything". This is why the
552
+ * raw row cannot be used: on a total the transform overwrites the leading
553
+ * dimension with its label ("Subtotal - Rolling Test 2019") and blanks the
554
+ * rest, so filtering by the row's own fields would produce nonsense.
555
+ */
556
+ scope?: Record<string, any>;
557
+ /** How many source rows the cell aggregates, when the pivot reports it. */
558
+ sourceCount?: number;
492
559
  }
493
560
  interface ActionClick {
494
561
  rowId: string;
495
562
  rowData?: any;
563
+ /** Name of the configured action that was clicked; absent for the fallback icon. */
564
+ action_name?: string;
565
+ /** The full action descriptor, for consumers that need the icon/condition too. */
566
+ action?: GridAction | null;
567
+ mode?: 'table' | 'board';
568
+ group?: RowGroup;
496
569
  }
497
570
  interface RowDataRequest {
498
571
  groupId: string;
@@ -687,6 +760,17 @@ declare class PivotTransformService {
687
760
  /**
688
761
  * Add interleaved subtotals within column groups
689
762
  */
763
+ /**
764
+ * The column-dimension values a generated pivot column belongs to.
765
+ *
766
+ * Prefers the `parentPath` the generator already recorded. The fallback parses
767
+ * the name, which is "<dim>|<dim>|<aggregation>" — so the dimensions are every
768
+ * segment but the last. This used to be read as `name.split('_')[0]`, which
769
+ * only worked while no dimension value and no leading part of an aggregation
770
+ * name contained an underscore; one underscore in a dimension value silently
771
+ * grouped the columns wrongly.
772
+ */
773
+ private dimensionPartsOf;
690
774
  private addInterleavedSubtotals;
691
775
  /**
692
776
  * Group pivot columns by dimension prefixes for subtotal insertion
@@ -715,6 +799,48 @@ declare class PivotTransformService {
715
799
  /**
716
800
  * Apply aggregation function to array of values
717
801
  */
802
+ /**
803
+ * The function that combines already-aggregated cell values into a subtotal
804
+ * or grand total.
805
+ *
806
+ * Rolling a total up is NOT the same operation as computing the cells. A
807
+ * subtotal over `count` cells must ADD the counts; applying `count` again
808
+ * counts how many pivot rows contributed, which is why every subtotal read 1
809
+ * and the grand total read 7 (the number of pivot rows) instead of the real
810
+ * record counts. `sum`, `min` and `max` are associative so they roll up as
811
+ * themselves — which is why sums looked right and hid the bug.
812
+ *
813
+ * `avg` has no correct roll-up from the averages alone: the mean of means is
814
+ * only the true mean when every group has the same number of records. It is
815
+ * left as-is rather than silently reported as exact — see the note at the
816
+ * call sites.
817
+ */
818
+ private rollUpFunction;
819
+ /**
820
+ * The source records a pivot row covers, or null when they cannot be worked
821
+ * out and the caller must fall back to rolling up cells.
822
+ *
823
+ * A grand-total row covers everything; a subtotal row covers the records
824
+ * matching the dimension prefix in its key ("subtotal_<value>"); a data row
825
+ * covers the records matching all of its dimension values. Row keys are the
826
+ * dimension values joined by '|', which is what makes this recoverable — the
827
+ * row's own display fields are not usable on a total, where the transform has
828
+ * replaced the leading dimension with a label and blanked the rest.
829
+ */
830
+ /** Escape a value so it can be embedded in a RegExp as a literal. */
831
+ private escapeForRegExp;
832
+ private rowScope;
833
+ /**
834
+ * The source records a grand-total cell covers, or null when they cannot be
835
+ * determined and the caller should fall back to rolling up cells.
836
+ *
837
+ * `columnKey` is a generated column name. A data cell is
838
+ * "<dimValue>|…|<measure>", so the column-dimension values are the segments
839
+ * before the measure and the total spans every record matching them. A
840
+ * subtotal or column-grand-total column has no such coordinate — it is itself
841
+ * a roll-up — so those return null.
842
+ */
843
+ private grandTotalScope;
718
844
  private applyAggregationFunction;
719
845
  /**
720
846
  * Group rows by dimension values
@@ -931,6 +1057,30 @@ declare class EruGridStore {
931
1057
  getConfiguration(): GridConfiguration;
932
1058
  reorderColumns(fromIndex: number, toIndex: number): void;
933
1059
  updateColumnRequired(columnName: string, required: boolean): void;
1060
+ /**
1061
+ * The field the design panel is editing.
1062
+ *
1063
+ * A pivot aggregation is a real, author-configured field but it is not in
1064
+ * `columns()` — that holds the source columns the dimensions come from. The
1065
+ * panel resolved only against those, so an aggregation header had nothing to
1066
+ * open. Checked after columns so a dimension always wins, which is what an
1067
+ * author clicking a row-dimension header means.
1068
+ */
1069
+ readonly designField: _angular_core.Signal<Field | null>;
1070
+ /**
1071
+ * Everything the design panel can edit, grouped for its target picker.
1072
+ *
1073
+ * Needed because not every designable field has a header to click. With a
1074
+ * single measure the pivot omits the measure-name row, so the one header cell
1075
+ * stands for the column dimension AND the measure fused together — clicking
1076
+ * it can only open one of them, leaving the dimension unreachable. Rather
1077
+ * than overload that header, the panel lets you switch target directly.
1078
+ * Narrow headers and hidden columns are reachable the same way.
1079
+ */
1080
+ readonly designTargets: _angular_core.Signal<{
1081
+ group: string;
1082
+ fields: Field[];
1083
+ }[]>;
934
1084
  updateColumnMeta(columnName: string, patch: Partial<Field>): void;
935
1085
  /**
936
1086
  * Apply metadata resolved from a mapped entity field. Unlike
@@ -941,6 +1091,29 @@ declare class EruGridStore {
941
1091
  */
942
1092
  applyResolvedColumnMeta(columnName: string, patch: Partial<Field>): void;
943
1093
  selectDesignColumn(columnName: string | null): void;
1094
+ /**
1095
+ * The field a generated pivot column belongs to.
1096
+ *
1097
+ * A pivot leaf ("<dimValue>|…|<measure>", or a "_…_subtotal_<measure>" /
1098
+ * "_…_column_grand_total_<measure>" roll-up) is a cell position, not a field,
1099
+ * and exists in neither `columns()` nor the aggregation list under that name.
1100
+ * Anything keyed off the leaf name therefore matched nothing. Resolving to the
1101
+ * owning measure — or leaving a real column name untouched — is what lets
1102
+ * width and design edits land somewhere that survives the next transform.
1103
+ *
1104
+ * Longest name first so a measure whose name is a suffix of another
1105
+ * ("amount" vs "net_amount") cannot claim the wrong leaf.
1106
+ */
1107
+ pivotOwnerName(columnName: string): string;
1108
+ /**
1109
+ * Set a column's width, at the level the width is actually configured.
1110
+ *
1111
+ * In pivot mode the resized header is a generated leaf, so the width is
1112
+ * stored on the measure (or the dimension) it came from and inherited by
1113
+ * every column that measure produces — resizing one value's column resizes
1114
+ * them all. Writing it per generated column would be lost as soon as the
1115
+ * data changed which dimension values exist.
1116
+ */
944
1117
  updateColumnWidth(columnName: string, field_size: number): void;
945
1118
  setCellValueChange(change: CellValueChange): void;
946
1119
  setGroups(groups: RowGroup[]): void;
@@ -1024,7 +1197,29 @@ declare class EruGridStore {
1024
1197
  * Check if freeze grand total is enabled
1025
1198
  */
1026
1199
  isFreezeGrandTotalEnabled(): boolean;
1027
- setDrilldown(drilldown: Drilldown, columnValues: string): void;
1200
+ /**
1201
+ * Record a drill click. `pivotPath` is the list of column-dimension values
1202
+ * that located the cell (empty in table mode).
1203
+ *
1204
+ * The caller supplies `rowData` — the cell already holds the row it renders,
1205
+ * so there is nothing to look up. Only the frozen grand-total cell is
1206
+ * resolved here, because that row is not passed to a cell at all. Previously
1207
+ * this reconstructed the row from an index parsed out of the cell id, which
1208
+ * in table mode read `rows()[index - 2]` and so returned the wrong row, or
1209
+ * undefined for the first two.
1210
+ */
1211
+ setDrilldown(drilldown: Drilldown, pivotPath?: string[]): void;
1212
+ /**
1213
+ * Say what kind of pivot cell was drilled, and what it is scoped to.
1214
+ *
1215
+ * Without this a subtotal reports exactly like a data cell and a consumer
1216
+ * would filter the source by the row's own fields — which on a total row hold
1217
+ * the label ("Subtotal - Rolling Test 2019", "Grand Total") rather than the
1218
+ * dimension values, and blanks for the dimensions that were rolled up.
1219
+ */
1220
+ private describePivotCell;
1221
+ /** Drain the drill signal once a consumer has handled it. */
1222
+ clearDrilldown(): void;
1028
1223
  clearPivotDrilldown(): void;
1029
1224
  setActionClick(actionClick: ActionClick): void;
1030
1225
  setColumnResize(columnResize: ColumnResize): void;
@@ -1336,6 +1531,21 @@ declare class EruGridComponent implements OnInit, AfterViewInit, OnDestroy {
1336
1531
  mode: "table" | "board";
1337
1532
  group?: RowGroup;
1338
1533
  }>;
1534
+ /**
1535
+ * Fires when a user clicks a row action in the action column.
1536
+ *
1537
+ * Carries the same row/mode/group shape as `rowSelect` — the consumer that
1538
+ * handles a row click is the one that handles an action on it — plus the
1539
+ * action that was clicked, which is what tells the consumer which of its
1540
+ * configured handlers to run. `action` is null for the fallback more_horiz
1541
+ * icon shown when no `config.actions` were configured.
1542
+ */
1543
+ actionClick: EventEmitter<{
1544
+ action: GridAction | null;
1545
+ row: Row;
1546
+ mode: "table" | "board";
1547
+ group?: RowGroup;
1548
+ }>;
1339
1549
  emitRowSelect(row: Row, mode: 'table' | 'board', group?: RowGroup): void;
1340
1550
  /**
1341
1551
  * Fires when the user clicks the excel download icon (shown when
@@ -1441,6 +1651,14 @@ declare class EruGridComponent implements OnInit, AfterViewInit, OnDestroy {
1441
1651
  private readonly SCROLL_THRESHOLD;
1442
1652
  /** Rows per lazy page: grid config `pageSize` if set, else ROWS_PER_PAGE. */
1443
1653
  private get rowsPerPage();
1654
+ /** Pages requested per group by the pivot loader; the anti-runaway counter. */
1655
+ private pivotPagesRequested;
1656
+ /**
1657
+ * How many rows pivot mode will pull before it stops asking for more. Beyond
1658
+ * this the pivot transform would not process client-side anyway, so pulling
1659
+ * further pages only costs round-trips.
1660
+ */
1661
+ private pivotRowCeiling;
1444
1662
  private lastLoadedGroupIds;
1445
1663
  private requestedGroupIds;
1446
1664
  private columnsInitialized;
@@ -1493,6 +1711,30 @@ declare class EruGridComponent implements OnInit, AfterViewInit, OnDestroy {
1493
1711
  private requestRowsForGroup;
1494
1712
  isDesignMode(): boolean;
1495
1713
  onHeaderDesignClick(event: Event, column: Field): void;
1714
+ /**
1715
+ * The field a header's design control should edit.
1716
+ *
1717
+ * In table mode that is the column itself. In pivot mode a leaf column is a
1718
+ * generated cell position, not a field: "<dimValue>|<agg>" for an aggregated
1719
+ * cell, or a "_..._grand_total_<agg>" roll-up. Designing one of those would
1720
+ * format a single pivot cell and be lost the moment the data changed the set
1721
+ * of dimension values. What the author means is the AGGREGATION — format the
1722
+ * measure everywhere it appears — so the leaf resolves back to it. A row
1723
+ * dimension header is already a real source column and resolves to itself.
1724
+ */
1725
+ designTargetFor(column: Field): string;
1726
+ /**
1727
+ * Whether a pivot header can be resized.
1728
+ *
1729
+ * Only headers that stand for one field: a row dimension, or a header that
1730
+ * resolves to a measure. A column-dimension group header spans several
1731
+ * measures, so dragging it has no single width to set — and since widths are
1732
+ * now held per measure, resizing any one of that group's leaves widens the
1733
+ * matching column under every other dimension value anyway.
1734
+ */
1735
+ isResizablePivotHeader(header: any): boolean;
1736
+ /** True when this header's design control would edit a pivot aggregation. */
1737
+ isAggregationHeader(column: Field): boolean;
1496
1738
  trackByColumnFn(index: number, column: Field): string;
1497
1739
  trackByGroupItemFn(index: number, groupItem: GroupItem): string;
1498
1740
  trackByPivotRowFn(index: number, pivotRow: PivotRow): string;
@@ -1503,6 +1745,16 @@ declare class EruGridComponent implements OnInit, AfterViewInit, OnDestroy {
1503
1745
  trackByHeaderFn(index: number, header: any): string;
1504
1746
  hasNestedHeaders(): boolean;
1505
1747
  getHeaderRows(): any[][];
1748
+ /**
1749
+ * What a pivot leaf inherits from the field it was generated from.
1750
+ *
1751
+ * Presentation plus `enableDrilldown` — everything the author configures on
1752
+ * the measure or the dimension. Identity and layout (name, label,
1753
+ * grid_index, field_size, aggregationFunction) belong to the generated leaf
1754
+ * and are deliberately absent: a leaf's label is its pivot dimension value,
1755
+ * not the measure's name.
1756
+ */
1757
+ private static readonly PIVOT_INHERITED_KEYS;
1506
1758
  getLeafColumns(): Field[];
1507
1759
  isRowDimensionHeader(header: any): boolean;
1508
1760
  /**
@@ -1514,7 +1766,41 @@ declare class EruGridComponent implements OnInit, AfterViewInit, OnDestroy {
1514
1766
  private initializeColumnWidths;
1515
1767
  toggleRowSelection(event: Event, row: any): void;
1516
1768
  toggleGroupSelection(event: Event, groupId: string): void;
1517
- onActionClick(event: Event, row: any): void;
1769
+ /**
1770
+ * A row action was clicked. Announced two ways, because the two kinds of
1771
+ * consumer read the grid differently: the store signal is what processo's
1772
+ * data viewer already drains, and the output event carries the same shape as
1773
+ * `rowSelect` so an eru-studio page can wire it up with the event framework.
1774
+ *
1775
+ * `action` is absent when the column is showing its fallback more_horiz icon
1776
+ * — i.e. no `config.actions` were configured.
1777
+ */
1778
+ onActionClick(event: Event, row: any, action?: GridAction, mode?: 'table' | 'board', group?: RowGroup): void;
1779
+ /**
1780
+ * Row actions for the action column: blank names discarded, and at most one
1781
+ * entry per name.
1782
+ *
1783
+ * The name is what comes back on the click, so two entries sharing one are
1784
+ * indistinguishable to the consumer — they would draw two icons that do the
1785
+ * same thing. Collapsing them here also keeps the template's
1786
+ * `track action.action_name` keys unique; duplicates would otherwise abort
1787
+ * the render. Matching is case-insensitive and ignores surrounding space, so
1788
+ * the grouping agrees with how a consumer is likely to compare the name.
1789
+ */
1790
+ readonly gridActions: _angular_core.Signal<GridAction[]>;
1791
+ readonly hasConfiguredActions: _angular_core.Signal<boolean>;
1792
+ readonly actionDisplayType: _angular_core.Signal<"icons" | "kebab">;
1793
+ /**
1794
+ * The actions that apply to one row, after each action's
1795
+ * `action_visible_condition` is evaluated against that row's values.
1796
+ */
1797
+ visibleActionsFor(row: any): GridAction[];
1798
+ /**
1799
+ * Width of the action column. Icons sit side by side, so the column has to
1800
+ * grow with the number configured or they wrap; a kebab is always one icon.
1801
+ * Capped so a long action list scrolls the icons rather than eating the grid.
1802
+ */
1803
+ readonly actionColumnWidth: _angular_core.Signal<number>;
1518
1804
  onSortColumn(event: Event, column: Field, direction: 'asc' | 'desc'): void;
1519
1805
  getSortDirection(fieldName: string): 'asc' | 'desc' | null;
1520
1806
  getSortPriority(fieldName: string): number | null;
@@ -1680,6 +1966,12 @@ declare class EruGridComponent implements OnInit, AfterViewInit, OnDestroy {
1680
1966
  groupSeperatorColSpan(): number;
1681
1967
  readonly BOARD_CARD_ITEM_HEIGHT = 208;
1682
1968
  readonly isBoardMode: _angular_core.Signal<boolean>;
1969
+ /**
1970
+ * Whether board columns wrap onto further rows once they no longer fit, or
1971
+ * stay on one horizontally scrolling row. Defaults to wrapping, which is the
1972
+ * behaviour that lets a narrow viewport stack its columns.
1973
+ */
1974
+ readonly boardWrapColumns: _angular_core.Signal<boolean>;
1683
1975
  readonly visibleBoardFields: _angular_core.Signal<Field[]>;
1684
1976
  readonly visibleColumns: _angular_core.Signal<Field[]>;
1685
1977
  readonly hiddenColumns: _angular_core.Signal<Field[]>;
@@ -1693,7 +1985,7 @@ declare class EruGridComponent implements OnInit, AfterViewInit, OnDestroy {
1693
1985
  requestBoardRowsForGroup(group: RowGroup): void;
1694
1986
  loadBoardAll(): void;
1695
1987
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<EruGridComponent, never>;
1696
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<EruGridComponent, "eru-grid", never, { "gridConfig": { "alias": "gridConfig"; "required": false; }; "boardCardTemplate": { "alias": "boardCardTemplate"; "required": false; }; "personCardTemplate": { "alias": "personCardTemplate"; "required": false; }; "boardCardHeight": { "alias": "boardCardHeight"; "required": false; }; "boardCardGap": { "alias": "boardCardGap"; "required": false; }; "boardCardPadding": { "alias": "boardCardPadding"; "required": false; }; }, { "rowSelect": "rowSelect"; }, never, never, true, never>;
1988
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<EruGridComponent, "eru-grid", never, { "gridConfig": { "alias": "gridConfig"; "required": false; }; "boardCardTemplate": { "alias": "boardCardTemplate"; "required": false; }; "personCardTemplate": { "alias": "personCardTemplate"; "required": false; }; "boardCardHeight": { "alias": "boardCardHeight"; "required": false; }; "boardCardGap": { "alias": "boardCardGap"; "required": false; }; "boardCardPadding": { "alias": "boardCardPadding"; "required": false; }; }, { "rowSelect": "rowSelect"; "actionClick": "actionClick"; }, never, never, true, never>;
1697
1989
  }
1698
1990
  interface GroupItem {
1699
1991
  type: 'header' | 'row' | 'table-header' | 'row-place-holder' | 'ghost-loading';
@@ -1704,6 +1996,36 @@ interface GroupItem {
1704
1996
  declare const MATERIAL_PROVIDERS: Provider[];
1705
1997
  declare const MATERIAL_MODULES: any[];
1706
1998
 
1999
+ /**
2000
+ * Row-scoped condition evaluation, used by the action column to decide whether
2001
+ * an action's icon applies to a given row.
2002
+ *
2003
+ * The authoring language is the one eru-studio already uses for page logic —
2004
+ * `@field` names a value, AND/OR/NOT join clauses, and the `is` / `is empty` /
2005
+ * `contains` / `in` / `between` phrases read the same way — so an author moving
2006
+ * between a page and a grid writes one language. The studio service itself
2007
+ * cannot be reused here: the dependency runs studio -> grid, and it resolves
2008
+ * names against page data and state, neither of which a grid row has. Here a
2009
+ * name is a column of the row being rendered.
2010
+ *
2011
+ * Expressions are compiled once and cached by their text, because a condition
2012
+ * is re-evaluated for every visible row on every change detection pass. A
2013
+ * condition that fails to compile or throws is treated as visible, matching how
2014
+ * the studio evaluator defaults on error — an authoring mistake should not
2015
+ * silently remove an action from every row.
2016
+ */
2017
+ /**
2018
+ * Read a field off a row. A grid row keeps its values under `entity_data`, but
2019
+ * the array-backed sources (query rows, pivot rows) put them at the top level,
2020
+ * so both are checked before falling back to walking a dotted path.
2021
+ */
2022
+ declare function resolveRowValue(row: any, fieldName: string): any;
2023
+ /**
2024
+ * Evaluate a visibility condition against one row. A blank or absent
2025
+ * expression means always visible.
2026
+ */
2027
+ declare function evaluateRowCondition(expression: string | null | undefined, row: any): boolean;
2028
+
1707
2029
  interface AttachmentConfig {
1708
2030
  disabled?: boolean;
1709
2031
  required?: boolean;
@@ -2779,5 +3101,5 @@ declare class ThemeToggleComponent {
2779
3101
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<ThemeToggleComponent, "eru-theme-toggle", never, {}, {}, never, never, true, never>;
2780
3102
  }
2781
3103
 
2782
- export { AttachmentComponent, CheckboxComponent, ColumnConstraintsService, CurrencyComponent, CustomVirtualScrollStrategy, DATA_TYPES, DATETIME_FORMATS, DATE_FORMATS, DateComponent, DatetimeComponent, DurationComponent, EmailComponent, EruGridComponent, EruGridService, EruGridStore, INHERITED_FIELD_KEYS, LocationComponent, MATERIAL_MODULES, MATERIAL_PROVIDERS, MONTH_SHORT_NAMES, NumberComponent, PRESET_CONFIG_DEFAULTS, PRESET_MANAGED_FIELDS, PeopleComponent, PhoneComponent, PriorityComponent, ProgressComponent, RatingComponent, SelectComponent, StatusComponent, TagComponent, TextareaComponent, TextboxComponent, ThemeService, ThemeToggleComponent, WebsiteComponent, formatDateWithPattern, matchColorRange, normalizeDatatype, normalizeDateFormat, normalizeDateTimeFormat, parseDateWithPattern };
2783
- export type { ActionClick, AggregationFunction, AttachmentConfig, BoardCardContext, CellValueChange, ColorRangeBand, ColumnReorder, ColumnResize, ColumnWidthConstraints, CurrencyValidationResult, DataTypes, Drilldown, DurationValue, DynamicDataRequest, EmailValidationResult, ExcelDownloadPayload, ExcelDownloadRequest, Field, GridConfiguration, GridFeatures, GridMode, GridPreset, GridStyles, GridTokens, GroupItem$1 as GroupItem, LocationConfig, LocationValidationResult, NumberValidationResult, PeopleOption, PersonCardContext, PivotColumnGroupState, PivotColumnHeader, PivotConfiguration, PivotHeaderStructure, PivotMetadata, PivotResult, PivotRow, RatingConfig, Row, RowDataRequest, RowDataResponse, RowGrandTotal, RowGroup, ServerValidationNotice, TextareaValidationResult, TextboxValidationResult, Theme, WebsiteValidationResult };
3104
+ export { AttachmentComponent, CheckboxComponent, ColumnConstraintsService, CurrencyComponent, CustomVirtualScrollStrategy, DATA_TYPES, DATETIME_FORMATS, DATE_FORMATS, DateComponent, DatetimeComponent, DurationComponent, EmailComponent, EruGridComponent, EruGridService, EruGridStore, INHERITED_FIELD_KEYS, LocationComponent, MATERIAL_MODULES, MATERIAL_PROVIDERS, MONTH_SHORT_NAMES, NumberComponent, PRESET_CONFIG_DEFAULTS, PRESET_MANAGED_FIELDS, PeopleComponent, PhoneComponent, PriorityComponent, ProgressComponent, RatingComponent, SelectComponent, StatusComponent, TagComponent, TextareaComponent, TextboxComponent, ThemeService, ThemeToggleComponent, WebsiteComponent, evaluateRowCondition, formatDateWithPattern, matchColorRange, normalizeDatatype, normalizeDateFormat, normalizeDateTimeFormat, parseDateWithPattern, resolveRowValue };
3105
+ export type { ActionClick, AggregationFunction, AttachmentConfig, BoardCardContext, CellValueChange, ColorRangeBand, ColumnReorder, ColumnResize, ColumnWidthConstraints, CurrencyValidationResult, DataTypes, Drilldown, DurationValue, DynamicDataRequest, EmailValidationResult, ExcelDownloadPayload, ExcelDownloadRequest, Field, GridAction, GridConfiguration, GridFeatures, GridMode, GridPreset, GridStyles, GridTokens, GroupItem$1 as GroupItem, LocationConfig, LocationValidationResult, NumberValidationResult, PeopleOption, PersonCardContext, PivotColumnGroupState, PivotColumnHeader, PivotColumnKind, PivotConfiguration, PivotHeaderStructure, PivotMetadata, PivotResult, PivotRow, PivotRowKind, RatingConfig, Row, RowDataRequest, RowDataResponse, RowGrandTotal, RowGroup, ServerValidationNotice, TextareaValidationResult, TextboxValidationResult, Theme, WebsiteValidationResult };