eru-grid 0.0.49 → 0.0.50

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.49",
3
+ "version": "0.0.50",
4
4
  "peerDependencies": {
5
5
  "@angular/common": "^21.1.2",
6
6
  "@angular/core": "^21.1.2",
@@ -269,6 +269,7 @@ interface Field {
269
269
  minWidth?: number;
270
270
  maxWidth?: number;
271
271
  symbol?: string;
272
+ symbol_field?: string;
272
273
  options?: any[];
273
274
  option_type?: 'STATIC' | 'API' | 'ENTITY_DATA';
274
275
  entity_name?: string;
@@ -342,6 +343,12 @@ interface Field {
342
343
  rich_text?: boolean;
343
344
  is_hyp?: boolean;
344
345
  hypl_nm?: string;
346
+ composite_fields?: string[];
347
+ composite_direction?: 'stack' | 'inline';
348
+ composite_separator?: string;
349
+ cell_page_id?: string;
350
+ cell_style?: CellTextStyle;
351
+ cell_style_secondary?: CellTextStyle;
345
352
  is_pii?: boolean;
346
353
  is_ephi?: boolean;
347
354
  to_encrypt?: boolean;
@@ -378,9 +385,53 @@ interface Field {
378
385
  * searchable whether a picker needs a filter box depends on how
379
386
  * many options this grid shows, not on the field
380
387
  * dateTimeFormat legacy alias; the model writes `date_format`
388
+ *
389
+ * See SEEDED_FIELD_KEYS for the middle ground: keys the data model supplies a
390
+ * starting value for, which this grid may then override.
381
391
  */
382
392
  declare const INHERITED_FIELD_KEYS: readonly string[];
383
- type DataTypes = 'number' | 'textbox' | 'textarea' | 'currency' | 'date' | 'datetime' | 'duration' | 'time' | 'dropdown_single_select' | 'dropdown_multi_select' | 'location' | 'email' | 'people' | 'checkbox' | 'phone' | 'priority' | 'status' | 'progress' | 'attachment' | 'tag' | 'rating' | 'website';
393
+ /**
394
+ * The overridable subset of INHERITED_FIELD_KEYS: the data model still supplies
395
+ * the starting value, but only while the column has none of its own, and the
396
+ * design panel leaves the control editable instead of locking it. An override is
397
+ * a normal column edit — emitted as a columnMetaPatch and persisted with the
398
+ * page, unlike the keys that are purely inherited.
399
+ *
400
+ * These are presentation choices that legitimately differ per grid over the very
401
+ * same field: whether a figure reads 1,25,00,000 or 1.25 Cr, which scale it
402
+ * abbreviates on, which sibling field carries each row's currency symbol in a
403
+ * multi-currency dataset, and how wide a date may be spelled — a dense report
404
+ * wants 'dd-MM-yy' where a detail grid over the same field wants the model's.
405
+ *
406
+ * Kept INSIDE the inherited list rather than removed from it, because that list
407
+ * is also what eru-studio's properties panel reads to show a bound field's real
408
+ * value; dropping a key there would make the panel and the page disagree.
409
+ */
410
+ /**
411
+ * Datatypes that describe how a column is DRAWN rather than what it holds.
412
+ *
413
+ * A composite shows other columns; a page renders a layout. The data model has
414
+ * no such field type, so a mapped column keeps these instead of inheriting the
415
+ * model's datatype over them (see buildMappedColumnPatch).
416
+ */
417
+ declare const PRESENTATION_DATATYPES: ReadonlySet<string>;
418
+ /**
419
+ * Datatypes that colour their own value from the data — a status pill, a
420
+ * priority chip, a progress band.
421
+ *
422
+ * A column-level text colour has nothing to say about these: the colour IS the
423
+ * value's meaning, authored on the field's options. They still take the
424
+ * column's typography, and a `cell` background still tints the cell around
425
+ * them, which is the one colour choice that remains meaningful.
426
+ */
427
+ declare const SELF_COLOURED_DATATYPES: ReadonlySet<string>;
428
+ /**
429
+ * Narrowest the action column may be: what the word "Action" needs in the
430
+ * header, which is wider than a single action icon.
431
+ */
432
+ declare const ACTION_COLUMN_MIN_WIDTH = 56;
433
+ declare const SEEDED_FIELD_KEYS: readonly string[];
434
+ type DataTypes = 'number' | 'textbox' | 'textarea' | 'currency' | 'date' | 'datetime' | 'duration' | 'time' | 'dropdown_single_select' | 'dropdown_multi_select' | 'location' | 'email' | 'people' | 'checkbox' | 'phone' | 'priority' | 'status' | 'progress' | 'attachment' | 'tag' | 'rating' | 'website' | 'composite' | 'page';
384
435
  /** Resolve a data-model datatype to the canonical DataTypes value. */
385
436
  declare function normalizeDatatype(datatype: any): DataTypes;
386
437
  /** The three colours a status pill is painted with. */
@@ -487,24 +538,149 @@ declare function formatDateWithPattern(date: Date | null, pattern: string): stri
487
538
  * splitting cannot recover the field order on its own.
488
539
  */
489
540
  declare function parseDateWithPattern(text: string, pattern: string): Date | null;
490
- /** One value band and the colours it paints. Either bound may be open-ended. */
491
- interface ColorRangeBand {
492
- from?: number | null;
493
- to?: number | null;
541
+ /**
542
+ * Resolve a value against a column's `color_ranges`, returning the first
543
+ * matching band or null.
544
+ *
545
+ * Kept as the name the progress, number and currency cells already call, now a
546
+ * thin alias over matchCellRule so bands and conditional-format rules can never
547
+ * disagree about what matches.
548
+ */
549
+ declare function matchColorRange(value: any, ranges: any): ColorRangeBand | null;
550
+ /**
551
+ * Operators a conditional-format rule can test with.
552
+ *
553
+ * `between` is the historical behaviour of a `color_ranges` band and stays the
554
+ * default when a rule names no operator, so bands authored before this — in the
555
+ * data model or the design pane — keep matching exactly as they did.
556
+ */
557
+ type CellRuleOperator = 'between' | 'gt' | 'gte' | 'lt' | 'lte' | 'eq' | 'neq' | 'contains' | 'not_contains' | 'starts_with' | 'ends_with' | 'is_empty' | 'is_not_empty' | 'before' | 'after';
558
+ declare const CELL_RULE_OPERATORS: {
559
+ value: CellRuleOperator;
560
+ label: string;
561
+ operands: 0 | 1 | 2;
562
+ }[];
563
+ /**
564
+ * One conditional-format rule on a column.
565
+ *
566
+ * A superset of ColorRangeBand: the same `from`/`to`/`color`/`background` keys
567
+ * mean the same thing, so every existing `color_ranges` value is already a
568
+ * valid rule list and no migration is needed. What is new is `op` (so a rule
569
+ * can test text and dates, not only numeric ranges), the text/cell `fill`
570
+ * choice, `bold`, and `bar` for a data bar.
571
+ *
572
+ * Rules are checked in order and the first match wins — the author controls
573
+ * precedence by ordering, as `color_ranges` already did.
574
+ */
575
+ interface CellFormatRule {
576
+ op?: CellRuleOperator;
577
+ from?: number | string | null;
578
+ to?: number | string | null;
494
579
  color?: string | null;
495
580
  background?: string | null;
581
+ fill?: 'text' | 'cell';
582
+ bold?: boolean;
583
+ /**
584
+ * Draw the value's magnitude as a bar behind it. `bar_min`/`bar_max` scale
585
+ * it; without them the bar cannot be drawn, because a bar is relative to the
586
+ * column and a cell cannot see the column. Column-relative scaling (and
587
+ * top/bottom-N) needs per-column stats from the server — see the grid docs.
588
+ */
589
+ bar?: boolean;
590
+ bar_min?: number | null;
591
+ bar_max?: number | null;
592
+ /** Scale the bar from the column's own min/max instead of fixed bounds. */
593
+ bar_auto?: boolean;
594
+ /**
595
+ * Operands taken from a column statistic rather than typed in. This is how
596
+ * "top 10 items" or "above average" are expressed: the server returns one
597
+ * scalar per statistic and it is substituted for `from`/`to` before matching,
598
+ * so the rule stays an ordinary comparison and nothing downstream changes.
599
+ */
600
+ from_stat?: CellStatRef | null;
601
+ to_stat?: CellStatRef | null;
602
+ }
603
+ /** Statistics a rule operand may be drawn from. Mirrors the aggregate verbs
604
+ * the server exposes; `min`, `max` and `avg` are the ones it already has. */
605
+ type CellStatVerb = 'min' | 'max' | 'avg' | 'stddev' | 'percentile' | 'nth';
606
+ interface CellStatRef {
607
+ stat: CellStatVerb;
608
+ /** percentile: 0-100. */
609
+ p?: number;
610
+ /** nth: 1-based rank. */
611
+ n?: number;
612
+ /** nth: which end to count from. */
613
+ dir?: 'asc' | 'desc';
614
+ /**
615
+ * Multiples of the column's standard deviation added to the base statistic,
616
+ * which is how "one std dev above average" is written: `{ stat: 'avg',
617
+ * offset_stddev: 1 }`. Requests the stddev alongside the base.
618
+ */
619
+ offset_stddev?: number;
620
+ }
621
+ /** One aggregate the grid needs for a column, in the shape the totals call
622
+ * already uses. `args` carries the operands the verb takes, if any. */
623
+ interface ColumnStatRequest {
624
+ func: CellStatVerb;
625
+ field: string;
626
+ alias: string;
627
+ args?: Record<string, any>;
496
628
  }
497
629
  /**
498
- * Resolve a numeric value against a column's `color_ranges`, returning the
499
- * first matching band or null.
630
+ * Deterministic alias for a statistic.
500
631
  *
501
- * Shared by the progress, number and currency cells so a value falling in the
502
- * same band paints the same way whichever datatype renders it. A blank or
503
- * absent bound is open-ended — data-model bands are authored that way ("80 and
504
- * above"), and coercing a missing bound to 0 would stop such a band matching.
505
- * Bands are checked in order, so the author controls precedence.
632
+ * Both sides key off this: the grid asks for it and looks the answer up by the
633
+ * same string, so nothing has to correlate requests with responses positionally.
506
634
  */
507
- declare function matchColorRange(value: any, ranges: any): ColorRangeBand | null;
635
+ declare function cellStatAlias(field: string, stat: CellStatVerb, args?: {
636
+ p?: number;
637
+ n?: number;
638
+ dir?: string;
639
+ }): string;
640
+ /**
641
+ * Every statistic the current columns' rules need, deduplicated by alias.
642
+ *
643
+ * Deliberately derived from the rules rather than configured separately: a
644
+ * column asks for exactly the aggregates its formatting uses, so removing a
645
+ * rule stops the request without anyone remembering to.
646
+ */
647
+ declare function collectColumnStatRequests(columns: Field[] | null | undefined): ColumnStatRequest[];
648
+ /** A statistic's value, or null when it has not come back (or cannot apply). */
649
+ declare function resolveStatValue(field: string, ref: CellStatRef | null | undefined, stats: Record<string, number> | null | undefined): number | null;
650
+ /**
651
+ * A column's rules with every statistic-backed operand replaced by its value.
652
+ *
653
+ * A rule whose statistic has not arrived is dropped rather than evaluated: with
654
+ * the operand missing it would either match everything or nothing, and both are
655
+ * worse than leaving the cell unformatted until the numbers land.
656
+ */
657
+ declare function resolveColumnRules(column: Field | null | undefined, stats: Record<string, number> | null | undefined): CellFormatRule[];
658
+ /** Legacy alias: a colour band is a rule with no operator. */
659
+ interface ColorRangeBand extends CellFormatRule {
660
+ }
661
+ /**
662
+ * Does one rule match this value?
663
+ *
664
+ * Numeric operators fall back to a string comparison when either side is not a
665
+ * number, so `eq` works on a status name as readily as on an amount and an
666
+ * author does not have to know which operator family their datatype belongs to.
667
+ */
668
+ declare function cellRuleMatches(value: any, rule: CellFormatRule, field?: Field | null): boolean;
669
+ /**
670
+ * First rule in the list that matches, or null.
671
+ *
672
+ * Every datatype resolves its rules through this, which is the point: colour
673
+ * bands used to be wired into the number, currency and progress cells only, so
674
+ * a status or a date column could not be conditionally formatted at all.
675
+ */
676
+ declare function matchCellRule(value: any, rules: any, field?: Field | null): CellFormatRule | null;
677
+ /**
678
+ * Percentage of the way `value` sits between a rule's bar bounds, or null when
679
+ * the bar cannot be scaled.
680
+ */
681
+ declare function cellRuleBarPercent(value: any, rule: CellFormatRule | null): number | null;
682
+ /** A matched rule as an ngStyle map, merged over the column's own cell style. */
683
+ declare function cellRuleToCss(value: any, rule: CellFormatRule | null): Record<string, string>;
508
684
  declare const DATA_TYPES: DataTypes[];
509
685
  type AggregationFunction = 'sum' | 'count' | 'avg' | 'min' | 'max';
510
686
  interface PivotColumnGroupState {
@@ -684,6 +860,107 @@ interface CellValueChange {
684
860
  * <ng-template #personCard let-userId let-column="column">…</ng-template>
685
861
  * <eru-grid [personCardTemplate]="personCard" [gridConfig]="cfg"></eru-grid>
686
862
  */
863
+ /**
864
+ * Basic text styling a column may set on its own cells.
865
+ *
866
+ * Kept to four properties on purpose. Cell appearance is otherwise owned by the
867
+ * grid preset and its tokens, and a column that can set arbitrary CSS stops
868
+ * inheriting the theme — the reason this is not a `style` string. These four
869
+ * are what a designer actually reaches for: making a secondary value smaller
870
+ * and quieter, or an identifier bolder.
871
+ */
872
+ interface CellTextStyle {
873
+ font_size?: number;
874
+ font_weight?: number;
875
+ italic?: boolean;
876
+ color?: string;
877
+ background?: string;
878
+ /**
879
+ * Where `background` is painted. `text` wraps the value in a pill that hugs
880
+ * it (the shape status and tag cells already use); `cell` tints the whole
881
+ * cell, which is how a column-wide band reads. Ignored without a background.
882
+ */
883
+ fill?: 'text' | 'cell';
884
+ }
885
+ /**
886
+ * Colour tokens a grid column may pick, mirroring eru-studio's picker but over
887
+ * the grid's own `--grid-*` set — a column styled with a token keeps tracking
888
+ * the preset/theme instead of freezing one hex.
889
+ */
890
+ declare const GRID_COLOR_TOKENS: {
891
+ label: string;
892
+ value: string;
893
+ }[];
894
+ interface ParsedColorValue {
895
+ /** `var(--grid-x)` when the value names a token, else null. */
896
+ token: string | null;
897
+ /** Hex for the custom-colour input; '#000000' when the value is a token. */
898
+ hex: string;
899
+ /** 0-100. */
900
+ alpha: number;
901
+ }
902
+ /**
903
+ * Read one of the three shapes a colour value takes: a bare token, a token
904
+ * wrapped in `color-mix(... N%, transparent)` for partial opacity, or a plain
905
+ * `rgba()`/hex. Same contract as eru-studio's property editor, so a colour
906
+ * authored on a page and one authored on a column mean the same thing.
907
+ *
908
+ * Opacity rides in `color-mix` rather than being baked into a hex precisely so
909
+ * a token stays a token: bake it and the colour stops following the theme.
910
+ */
911
+ declare function parseColorValue(value: any): ParsedColorValue;
912
+ /** Inverse of parseColorValue. Returns null for "nothing set", so a cleared
913
+ * colour falls back to the preset rather than being pinned to black. */
914
+ declare function composeColorValue(token: string | null, hex: string | null, alpha: number): string | null;
915
+ /**
916
+ * CellTextStyle as an ngStyle map. Empty when nothing is set, so the cell keeps
917
+ * the preset's own values rather than being pinned to defaults.
918
+ *
919
+ * A `text` fill turns the container inline-block so it hugs the value and reads
920
+ * as a pill; a `cell` fill leaves the box alone and just tints it.
921
+ */
922
+ declare function cellTextStyleToCss(style: CellTextStyle | null | undefined): Record<string, string>;
923
+ /**
924
+ * Abbreviate a number to k / L / Cr (lacs) or k / mn / bn / tn (millions).
925
+ *
926
+ * Shared: the number cell, the currency cell and a composite part must all
927
+ * abbreviate identically. It lived as a private copy in both number.component
928
+ * and currency.component — byte-identical, and two places to fix.
929
+ */
930
+ declare function abbreviateNumber(num: number, system: 'lacs' | 'mn', decimals: number): string;
931
+ /**
932
+ * Render a number or currency value the way its column configures it —
933
+ * decimals, separator locale, abbreviation, optional symbol prefix.
934
+ *
935
+ * The single implementation behind the number cell, the currency cell and a
936
+ * composite part, so the same value never reads two ways in one grid.
937
+ * A non-numeric string is returned untouched: the grid shows what the row
938
+ * holds rather than 'NaN'.
939
+ */
940
+ declare function formatNumberValue(value: any, cfg: Partial<Field> | null | undefined, options?: {
941
+ prefix?: string;
942
+ replaceZero?: string;
943
+ }): string;
944
+ /**
945
+ * Best-effort parse of a stored date value, trying the column's own pattern
946
+ * before falling back to ISO and then the platform parser. Returns null rather
947
+ * than an Invalid Date so callers can render an empty cell.
948
+ */
949
+ declare function parseCellDate(value: any, pattern?: string): Date | null;
950
+ /**
951
+ * Display text for a value under a field's own formatting rules.
952
+ *
953
+ * Used where a value must be shown but not edited — today a composite cell's
954
+ * parts. It deliberately renders text only: a status pill or an avatar stack is
955
+ * the interactive cell's job, and a composite that tried to host those would be
956
+ * a layout engine. A column needing that is a `page` cell.
957
+ */
958
+ declare function formatCellValue(value: any, field: Field | null | undefined): string;
959
+ /**
960
+ * Read a field's value off a row, tolerating both shapes the grid is handed:
961
+ * a flat row and one wrapping its values in `entity_data`.
962
+ */
963
+ declare function readRowValue(row: any, fieldName: string): any;
687
964
  interface PersonCardContext {
688
965
  /** The selected person's id ($implicit — bind with let-userId) */
689
966
  $implicit: string;
@@ -692,6 +969,16 @@ interface PersonCardContext {
692
969
  /** Page the field names as the card, from the data model's people_card */
693
970
  cardPage?: string;
694
971
  }
972
+ /** Context a `page` cell hands its renderer — one row, one column. Mirrors
973
+ * BoardCardContext so a consumer can reuse the same card host for both. */
974
+ interface CellTemplateContext {
975
+ /** Row data for this cell ($implicit — bind with let-row) */
976
+ $implicit: Row;
977
+ /** The column being rendered, carrying `cell_page_id` */
978
+ column: Field;
979
+ /** All visible columns, for a card that shows more than its own field */
980
+ columns: Field[];
981
+ }
695
982
  interface BoardCardContext {
696
983
  /** Row data for this card ($implicit — bind with let-row) */
697
984
  $implicit: Row;
@@ -1065,6 +1352,23 @@ declare class EruGridStore {
1065
1352
  name: string;
1066
1353
  patch: Partial<Field>;
1067
1354
  } | null>;
1355
+ /**
1356
+ * Column-wide statistics behind stat-backed conditional-format rules, keyed
1357
+ * by the alias `cellStatAlias` builds. Supplied by the consuming app, which
1358
+ * owns the round trip; the grid only says which aggregates it needs.
1359
+ */
1360
+ private readonly _columnStats;
1361
+ readonly columnStats: _angular_core.Signal<Record<string, number>>;
1362
+ /** Aggregates the current rules need, or null when none do. */
1363
+ private readonly _columnStatsRequest;
1364
+ readonly columnStatsRequest: _angular_core.Signal<ColumnStatRequest[] | null>;
1365
+ setColumnStats(stats: Record<string, number> | null | undefined): void;
1366
+ /**
1367
+ * Publish the aggregate list. Compared before writing so a re-resolve that
1368
+ * produces the same set does not re-trigger the consumer's fetch — the
1369
+ * columns signal changes on every design edit and resize.
1370
+ */
1371
+ setColumnStatsRequest(requests: ColumnStatRequest[] | null): void;
1068
1372
  readonly columns: _angular_core.Signal<Field[]>;
1069
1373
  readonly groups: _angular_core.Signal<RowGroup[]>;
1070
1374
  readonly rows: _angular_core.Signal<Row[]>;
@@ -1573,6 +1877,20 @@ declare class EruGridComponent implements OnInit, AfterViewInit, OnDestroy {
1573
1877
  * card trigger stays inert.
1574
1878
  */
1575
1879
  personCardTemplate?: TemplateRef<PersonCardContext>;
1880
+ /**
1881
+ * Renderer for a `page` column's cells — the same contract as
1882
+ * boardCardTemplate, one level down. The grid invokes it once per row for
1883
+ * every column whose datatype is `page`, handing it the row, that column
1884
+ * (which carries `cell_page_id`) and the visible columns. Omit it and such a
1885
+ * column falls back to showing its raw value.
1886
+ *
1887
+ * Example:
1888
+ * <ng-template #myCell let-row let-column="column">
1889
+ * <my-page-host [row]="row" [pageId]="column.cell_page_id"></my-page-host>
1890
+ * </ng-template>
1891
+ * <eru-grid [cellTemplate]="myCell" [gridConfig]="cfg"></eru-grid>
1892
+ */
1893
+ cellTemplate?: TemplateRef<CellTemplateContext>;
1576
1894
  /**
1577
1895
  * Height in pixels of each board card slot.
1578
1896
  * Must match the fixed height of the card rendered by boardCardTemplate (or the default card).
@@ -1906,6 +2224,10 @@ declare class EruGridComponent implements OnInit, AfterViewInit, OnDestroy {
1906
2224
  * Width of the action column. Icons sit side by side, so the column has to
1907
2225
  * grow with the number configured or they wrap; a kebab is always one icon.
1908
2226
  * Capped so a long action list scrolls the icons rather than eating the grid.
2227
+ *
2228
+ * The floor is the header's own width, not the icons': one action needed only
2229
+ * 48px of icon but the word "Action" is wider than that, so the header was
2230
+ * clipped on every single-action grid.
1909
2231
  */
1910
2232
  readonly actionColumnWidth: _angular_core.Signal<number>;
1911
2233
  onSortColumn(event: Event, column: Field, direction: 'asc' | 'desc'): void;
@@ -1926,6 +2248,12 @@ declare class EruGridComponent implements OnInit, AfterViewInit, OnDestroy {
1926
2248
  * Attributes a mapped column inherits from its data-model field. Only keys
1927
2249
  * the field actually defines are returned, so a sparse field never blanks
1928
2250
  * out what the column already has.
2251
+ *
2252
+ * SEEDED_FIELD_KEYS are merged only while the column carries no value of its
2253
+ * own: the model supplies the starting point, and this grid's own choice —
2254
+ * including an explicit `false` on a checkbox — wins from then on. Without the
2255
+ * column in hand there is no way to tell "not set" from "set to the opposite",
2256
+ * so an override was overwritten on every resolve.
1929
2257
  */
1930
2258
  private buildMappedColumnPatch;
1931
2259
  /** Get the field name used for grouping */
@@ -2100,7 +2428,7 @@ declare class EruGridComponent implements OnInit, AfterViewInit, OnDestroy {
2100
2428
  requestBoardRowsForGroup(group: RowGroup): void;
2101
2429
  loadBoardAll(): void;
2102
2430
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<EruGridComponent, never>;
2103
- 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>;
2431
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<EruGridComponent, "eru-grid", never, { "gridConfig": { "alias": "gridConfig"; "required": false; }; "boardCardTemplate": { "alias": "boardCardTemplate"; "required": false; }; "personCardTemplate": { "alias": "personCardTemplate"; "required": false; }; "cellTemplate": { "alias": "cellTemplate"; "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>;
2104
2432
  }
2105
2433
  interface GroupItem {
2106
2434
  type: 'header' | 'row' | 'table-header' | 'row-place-holder' | 'ghost-loading';
@@ -2244,6 +2572,42 @@ declare class CheckboxComponent {
2244
2572
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<CheckboxComponent, "eru-checkbox", never, { "value": { "alias": "value"; "required": false; "isSignal": true; }; "config": { "alias": "config"; "required": false; "isSignal": true; }; "isEditable": { "alias": "isEditable"; "required": false; "isSignal": true; }; "isActive": { "alias": "isActive"; "required": false; "isSignal": true; }; "isDrillable": { "alias": "isDrillable"; "required": false; "isSignal": true; }; "label": { "alias": "label"; "required": false; "isSignal": true; }; }, { "valueChange": "valueChange"; "change": "change"; "blur": "blur"; "focus": "focus"; "drilldownClick": "drilldownClick"; "editModeChange": "editModeChange"; }, never, never, true, never>;
2245
2573
  }
2246
2574
 
2575
+ interface CompositePart {
2576
+ name: string;
2577
+ label: string;
2578
+ text: string;
2579
+ }
2580
+ /**
2581
+ * Several of the row's own columns rendered as one cell — a name over an email,
2582
+ * an amount over a date.
2583
+ *
2584
+ * View-only, and text-only, by design. Each part is formatted by its OWN
2585
+ * field's rules (`formatCellValue`), so a currency part keeps its symbol and
2586
+ * decimals and a date part keeps its pattern; the composite itself decides only
2587
+ * arrangement and emphasis. Editing stays on the underlying columns, which are
2588
+ * usually hidden once composed.
2589
+ */
2590
+ declare class CompositeComponent {
2591
+ row: _angular_core.InputSignal<any>;
2592
+ column: _angular_core.InputSignal<Field | null>;
2593
+ columns: _angular_core.InputSignal<Field[]>;
2594
+ isDrillable: _angular_core.InputSignal<boolean>;
2595
+ drilldownClick: _angular_core.OutputEmitterRef<string>;
2596
+ readonly inline: _angular_core.Signal<boolean>;
2597
+ readonly separator: _angular_core.Signal<string>;
2598
+ readonly primaryCss: _angular_core.Signal<Record<string, string>>;
2599
+ readonly secondaryCss: _angular_core.Signal<Record<string, string>>;
2600
+ /**
2601
+ * Falls back to the composite column itself when `composite_fields` is unset
2602
+ * or names nothing that exists, so a column switched to `composite` before it
2603
+ * is configured still shows its own value instead of going blank.
2604
+ */
2605
+ readonly parts: _angular_core.Signal<CompositePart[]>;
2606
+ onDrilldown(event: Event, part: CompositePart): void;
2607
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<CompositeComponent, never>;
2608
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<CompositeComponent, "eru-composite", never, { "row": { "alias": "row"; "required": false; "isSignal": true; }; "column": { "alias": "column"; "required": false; "isSignal": true; }; "columns": { "alias": "columns"; "required": false; "isSignal": true; }; "isDrillable": { "alias": "isDrillable"; "required": false; "isSignal": true; }; }, { "drilldownClick": "drilldownClick"; }, never, never, true, never>;
2609
+ }
2610
+
2247
2611
  interface CurrencyValidationResult {
2248
2612
  isValid: boolean;
2249
2613
  error?: string;
@@ -2286,7 +2650,7 @@ declare class CurrencyComponent {
2286
2650
  rangeColor: _angular_core.Signal<string | null>;
2287
2651
  rangeBackground: _angular_core.Signal<string | null>;
2288
2652
  constructor();
2289
- formatNumberSignal: _angular_core.Signal<string | undefined>;
2653
+ formatNumberSignal: _angular_core.Signal<string>;
2290
2654
  onActivate(): void;
2291
2655
  onBlur(): void;
2292
2656
  onValueChange(event: any): void;
@@ -2559,7 +2923,7 @@ declare class NumberComponent {
2559
2923
  rangeColor: _angular_core.Signal<string | null>;
2560
2924
  rangeBackground: _angular_core.Signal<string | null>;
2561
2925
  constructor();
2562
- formatNumberSignal: _angular_core.Signal<string | undefined>;
2926
+ formatNumberSignal: _angular_core.Signal<string>;
2563
2927
  onActivate(): void;
2564
2928
  onBlur(): void;
2565
2929
  onValueChange(event: any): void;
@@ -3221,5 +3585,5 @@ declare class ThemeToggleComponent {
3221
3585
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<ThemeToggleComponent, "eru-theme-toggle", never, {}, {}, never, never, true, never>;
3222
3586
  }
3223
3587
 
3224
- 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, statusPillColors, tagPillColors };
3225
- export type { ActionClick, AggregationFunction, AttachmentConfig, BoardCardContext, CellValueChange, ColorRangeBand, ColumnReorder, ColumnResize, ColumnWidthConstraints, CurrencyValidationResult, DataTypes, Drilldown, DurationValue, DynamicDataRequest, EmailValidationResult, ExcelDownloadPayload, ExcelDownloadRequest, ExcelPivotConfig, 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, StatusPillColors, TagPillColors, TextareaValidationResult, TextboxValidationResult, Theme, WebsiteValidationResult };
3588
+ export { ACTION_COLUMN_MIN_WIDTH, AttachmentComponent, CELL_RULE_OPERATORS, CheckboxComponent, ColumnConstraintsService, CompositeComponent, CurrencyComponent, CustomVirtualScrollStrategy, DATA_TYPES, DATETIME_FORMATS, DATE_FORMATS, DateComponent, DatetimeComponent, DurationComponent, EmailComponent, EruGridComponent, EruGridService, EruGridStore, GRID_COLOR_TOKENS, INHERITED_FIELD_KEYS, LocationComponent, MATERIAL_MODULES, MATERIAL_PROVIDERS, MONTH_SHORT_NAMES, NumberComponent, PRESENTATION_DATATYPES, PRESET_CONFIG_DEFAULTS, PRESET_MANAGED_FIELDS, PeopleComponent, PhoneComponent, PriorityComponent, ProgressComponent, RatingComponent, SEEDED_FIELD_KEYS, SELF_COLOURED_DATATYPES, SelectComponent, StatusComponent, TagComponent, TextareaComponent, TextboxComponent, ThemeService, ThemeToggleComponent, WebsiteComponent, abbreviateNumber, cellRuleBarPercent, cellRuleMatches, cellRuleToCss, cellStatAlias, cellTextStyleToCss, collectColumnStatRequests, composeColorValue, evaluateRowCondition, formatCellValue, formatDateWithPattern, formatNumberValue, matchCellRule, matchColorRange, normalizeDatatype, normalizeDateFormat, normalizeDateTimeFormat, parseCellDate, parseColorValue, parseDateWithPattern, readRowValue, resolveColumnRules, resolveRowValue, resolveStatValue, statusPillColors, tagPillColors };
3589
+ export type { ActionClick, AggregationFunction, AttachmentConfig, BoardCardContext, CellFormatRule, CellRuleOperator, CellStatRef, CellStatVerb, CellTemplateContext, CellTextStyle, CellValueChange, ColorRangeBand, ColumnReorder, ColumnResize, ColumnStatRequest, ColumnWidthConstraints, CompositePart, CurrencyValidationResult, DataTypes, Drilldown, DurationValue, DynamicDataRequest, EmailValidationResult, ExcelDownloadPayload, ExcelDownloadRequest, ExcelPivotConfig, Field, GridAction, GridConfiguration, GridFeatures, GridMode, GridPreset, GridStyles, GridTokens, GroupItem$1 as GroupItem, LocationConfig, LocationValidationResult, NumberValidationResult, ParsedColorValue, PeopleOption, PersonCardContext, PivotColumnGroupState, PivotColumnHeader, PivotColumnKind, PivotConfiguration, PivotHeaderStructure, PivotMetadata, PivotResult, PivotRow, PivotRowKind, RatingConfig, Row, RowDataRequest, RowDataResponse, RowGrandTotal, RowGroup, ServerValidationNotice, StatusPillColors, TagPillColors, TextareaValidationResult, TextboxValidationResult, Theme, WebsiteValidationResult };