eru-grid 0.0.52 → 0.0.53

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.52",
3
+ "version": "0.0.53",
4
4
  "peerDependencies": {
5
5
  "@angular/common": "^21.1.2",
6
6
  "@angular/core": "^21.1.2",
@@ -15,13 +15,6 @@
15
15
  },
16
16
  "sideEffects": false,
17
17
  "exports": {
18
- "./package.json": {
19
- "default": "./package.json"
20
- },
21
- ".": {
22
- "types": "./types/eru-grid.d.ts",
23
- "default": "./fesm2022/eru-grid.mjs"
24
- },
25
18
  "./theme": {
26
19
  "sass": "./src/lib/styles/theme.scss",
27
20
  "default": "./src/lib/styles/theme.scss"
@@ -33,6 +26,13 @@
33
26
  "./styles": {
34
27
  "sass": "./src/lib/styles/index.scss",
35
28
  "default": "./src/lib/styles/index.scss"
29
+ },
30
+ "./package.json": {
31
+ "default": "./package.json"
32
+ },
33
+ ".": {
34
+ "types": "./types/eru-grid.d.ts",
35
+ "default": "./fesm2022/eru-grid.mjs"
36
36
  }
37
37
  },
38
38
  "module": "fesm2022/eru-grid.mjs",
@@ -68,10 +68,11 @@ interface GridFeatures {
68
68
  actionColumn?: boolean;
69
69
  actionColumnPosition?: 'before' | 'after';
70
70
  actions?: GridAction[];
71
- action_display_type?: 'icons' | 'kebab';
71
+ action_display_type?: 'icons' | 'icons_outlined' | 'kebab';
72
72
  designMode?: boolean;
73
73
  groupBar?: boolean;
74
74
  excel_download?: boolean;
75
+ excel_download_icon?: boolean;
75
76
  response_key?: string;
76
77
  header_fill_color?: string[];
77
78
  header_fill_type?: string;
@@ -312,6 +313,9 @@ interface Field {
312
313
  max_files?: number;
313
314
  allowed_file_types?: any[];
314
315
  max_file_size?: number;
316
+ storage_name?: string;
317
+ folder_name?: string;
318
+ default_upload?: boolean;
315
319
  default_country?: string;
316
320
  date_format?: string;
317
321
  dateTimeFormat?: string;
@@ -346,9 +350,23 @@ interface Field {
346
350
  rich_text?: boolean;
347
351
  is_hyp?: boolean;
348
352
  hypl_nm?: string;
353
+ /**
354
+ * How the cell is DRAWN, independently of what the column holds.
355
+ *
356
+ * Was encoded as a datatype ('composite' / 'page'), which meant switching a
357
+ * column to one overwrote the datatype it actually had: its own formatting
358
+ * controls became unreachable, and turning the composite off could not bring
359
+ * them back because the value was gone, not hidden. As a separate axis the
360
+ * column keeps its type and its format either way, so the toggle is no longer
361
+ * destructive and edits made while it is on survive turning it off.
362
+ */
363
+ cell_render?: CellRender;
349
364
  composite_fields?: string[];
350
365
  composite_direction?: 'stack' | 'inline';
351
366
  composite_separator?: string;
367
+ composite_label_position?: 'none' | 'left' | 'right';
368
+ composite_labels?: string[];
369
+ presentation_base_datatype?: DataTypes | null;
352
370
  cell_page_id?: string;
353
371
  cell_style?: CellTextStyle;
354
372
  cell_style_secondary?: CellTextStyle;
@@ -408,18 +426,45 @@ declare const INHERITED_FIELD_KEYS: readonly string[];
408
426
  * multi-currency dataset, and how wide a date may be spelled — a dense report
409
427
  * wants 'dd-MM-yy' where a detail grid over the same field wants the model's.
410
428
  *
429
+ * `label` is here for the same reason: the model's name is the right default
430
+ * and the right thing to fall back to, but a narrow column, or one whose
431
+ * meaning is already obvious from its neighbours, often wants a shorter heading
432
+ * in this grid without renaming the field for every grid that maps it.
433
+ *
411
434
  * Kept INSIDE the inherited list rather than removed from it, because that list
412
435
  * is also what eru-studio's properties panel reads to show a bound field's real
413
436
  * value; dropping a key there would make the panel and the page disagree.
414
437
  */
415
438
  /**
416
- * Datatypes that describe how a column is DRAWN rather than what it holds.
417
- *
418
- * A composite shows other columns; a page renders a layout. The data model has
419
- * no such field type, so a mapped column keeps these instead of inheriting the
420
- * model's datatype over them (see buildMappedColumnPatch).
439
+ * The datatypes that used to encode a renderer, kept only to recognise columns
440
+ * saved that way. Nothing is offered these any more — see `cell_render`, which
441
+ * replaced them, and `normalizeCellRender`, which migrates them.
421
442
  */
422
443
  declare const PRESENTATION_DATATYPES: ReadonlySet<string>;
444
+ /** How a cell is drawn: its datatype's control, or one of the two renderers. */
445
+ type CellRender = 'default' | 'composite' | 'page';
446
+ /**
447
+ * A column's renderer, migrating the legacy encoding where it was a datatype.
448
+ *
449
+ * A column saved that way has already lost the datatype it held — there is
450
+ * nothing to recover here. A mapped one picks its real type back up from the
451
+ * data model on the next resolve; an unmapped one falls back to text, which is
452
+ * what its underlying value was being rendered as anyway.
453
+ */
454
+ declare function normalizeCellRender(field: {
455
+ cell_render?: string;
456
+ datatype?: string;
457
+ } | null | undefined): CellRender;
458
+ /**
459
+ * The datatype that governs how a column's VALUE is formatted.
460
+ *
461
+ * Normally that is `datatype`, but a presentation type says how the column is
462
+ * drawn and not what it holds, so for those the real type comes from
463
+ * `presentation_base_datatype`. A composite's primary part is the composite
464
+ * column itself — without this it formatted as an untyped value and a date came
465
+ * out as its raw stored string.
466
+ */
467
+ declare function effectiveValueDatatype(field: Field | null | undefined): string | undefined;
423
468
  /**
424
469
  * Datatypes that colour their own value from the data — a status pill, a
425
470
  * priority chip, a progress band.
@@ -989,12 +1034,50 @@ declare function formatNumberValue(value: any, cfg: Partial<Field> | null | unde
989
1034
  prefix?: string;
990
1035
  replaceZero?: string;
991
1036
  }): string;
1037
+ /**
1038
+ * The canonical stored form of a date: `yyyy-MM-dd`, in LOCAL time.
1039
+ *
1040
+ * Built from the local getters rather than `toISOString()`, which converts to
1041
+ * UTC and would move a date picked late in the day to the next (or previous)
1042
+ * one. This is the shape a value is stored in, whatever pattern the column
1043
+ * chooses to display it under, and it matches eru-studio's date component.
1044
+ */
1045
+ declare function toDateOnlyString(date: Date | null | undefined): string;
1046
+ /**
1047
+ * The canonical stored form of a datetime: `yyyy-MM-dd HH:mm:ss`, in LOCAL
1048
+ * time — the date-only form plus a 24-hour clock, with seconds always present
1049
+ * so the stored shape does not depend on the display pattern.
1050
+ */
1051
+ declare function toDateTimeString(date: Date | null | undefined): string;
1052
+ /**
1053
+ * Render a datetime with a token pattern (`dd-MMM-yyyy hh:mm:ss`).
1054
+ *
1055
+ * The date half goes through formatDateWithPattern, so `MMM` yields a month
1056
+ * name — the datetime cell used to build its own numeric date string and had no
1057
+ * `MMM` branch at all, which is why picking DD-MMM-YYYY HH:MM:SS still rendered
1058
+ * digits. The time half is 24-hour, with seconds only when the pattern asks.
1059
+ */
1060
+ declare function formatDateTimeWithPattern(date: Date | null, pattern: string): string;
1061
+ /**
1062
+ * Best-effort parse of a stored datetime value, keeping the time.
1063
+ *
1064
+ * Distinct from parseCellDate, which deliberately pins a bare ISO date to local
1065
+ * midnight so a date column never shifts a day across timezones — correct
1066
+ * there, but it threw the clock away, so a datetime column could never show
1067
+ * anything but 00:00.
1068
+ *
1069
+ * An ISO timestamp is tried first and handed to the platform parser: it is
1070
+ * unambiguous, it carries an offset, and letting a `dd-MM-yyyy` column pattern
1071
+ * see it first would read `2026-09-05` as day 2026. A timestamp with an offset
1072
+ * (`...Z`) therefore reads back as the local wall-clock time of that instant.
1073
+ */
1074
+ declare function parseCellDateTime(value: any, pattern?: string): Date | null;
992
1075
  /**
993
1076
  * Best-effort parse of a stored date value, trying the column's own pattern
994
1077
  * before falling back to ISO and then the platform parser. Returns null rather
995
1078
  * than an Invalid Date so callers can render an empty cell.
996
1079
  */
997
- declare function parseCellDate(value: any, pattern?: string): Date | null;
1080
+ declare function parseCellDate(value: any, pattern?: string, keepTime?: boolean): Date | null;
998
1081
  /**
999
1082
  * Display text for a value under a field's own formatting rules.
1000
1083
  *
@@ -1359,6 +1442,14 @@ declare class PivotTransformService {
1359
1442
  static ɵprov: _angular_core.ɵɵInjectableDeclaration<PivotTransformService>;
1360
1443
  }
1361
1444
 
1445
+ /**
1446
+ * The id a row is selected by. Entity rows carry `entity_id`; array/query rows
1447
+ * that were given a synthetic key carry `id`. Every read and write of the
1448
+ * selection set must go through this — the checkbox used to store `row.id`
1449
+ * while the checked-state read `row.entity_id`, so ticking an entity row put
1450
+ * `undefined` in the set and the box never rendered checked.
1451
+ */
1452
+ declare function rowSelectionKey(row: any): string;
1362
1453
  declare class EruGridStore {
1363
1454
  private readonly gridConfigService;
1364
1455
  private readonly pivotTransformService;
@@ -1368,6 +1459,7 @@ declare class EruGridStore {
1368
1459
  private readonly _rows;
1369
1460
  private _groupRows;
1370
1461
  private readonly _selectedRowIds;
1462
+ private readonly _selectAllMatching;
1371
1463
  private readonly _activeBoardRow;
1372
1464
  private readonly _rowGrandTotal;
1373
1465
  private readonly _dynamicDataRequest;
@@ -1427,6 +1519,7 @@ declare class EruGridStore {
1427
1519
  count: number;
1428
1520
  }[]>;
1429
1521
  readonly selectedRowIds: _angular_core.Signal<Set<string>>;
1522
+ readonly selectAllMatching: _angular_core.Signal<boolean>;
1430
1523
  readonly activeBoardRow: _angular_core.Signal<any>;
1431
1524
  readonly configuration: _angular_core.Signal<GridConfiguration>;
1432
1525
  readonly isLoading: _angular_core.Signal<boolean>;
@@ -1446,7 +1539,22 @@ declare class EruGridStore {
1446
1539
  readonly dynamicDataRequest: _angular_core.Signal<DynamicDataRequest[] | null>;
1447
1540
  readonly dynamicData: _angular_core.Signal<Map<string, any> | null>;
1448
1541
  readonly excelDownloadRequest: _angular_core.Signal<ExcelDownloadRequest[]>;
1542
+ /**
1543
+ * Every row currently in memory that can be selected, deduped by selection key.
1544
+ *
1545
+ * Selection has to read both row stores: `_rows` is only populated when the
1546
+ * consumer mirrors data in via setRows()/addRows(), while the grouped,
1547
+ * server-paginated renderer fills `_groupRows` through addRowsForGroup(). The
1548
+ * select-all handler read `rows()` alone, which is empty in the normal paged
1549
+ * path — so select-all was a no-op there.
1550
+ */
1551
+ readonly selectableRows: _angular_core.Signal<Row[]>;
1449
1552
  readonly selectedRows: _angular_core.Signal<Row[]>;
1553
+ /**
1554
+ * How many records the current groups say exist server-side, loaded or not.
1555
+ * This is the "all N matching" number the select-all banner offers.
1556
+ */
1557
+ readonly totalMatchingCount: _angular_core.Signal<number>;
1450
1558
  readonly totalSelectedCount: _angular_core.Signal<number>;
1451
1559
  readonly hasSelection: _angular_core.Signal<boolean>;
1452
1560
  readonly expandedGroups: _angular_core.Signal<RowGroup[]>;
@@ -1474,6 +1582,17 @@ declare class EruGridStore {
1474
1582
  */
1475
1583
  private compareValues;
1476
1584
  getConfiguration(): GridConfiguration;
1585
+ /**
1586
+ * Reorder by column name rather than by rendered position.
1587
+ *
1588
+ * The header renders `displayColumns` — `columns()` minus the hidden columns
1589
+ * and minus the group-by field — so the `$index` of a header cell is not the
1590
+ * index of that column in `_columns`. Passing the rendered index straight to
1591
+ * `reorderColumns` moved whichever column occupied that slot in the full
1592
+ * list, which is why dragging a column near the end appeared to move its
1593
+ * neighbour instead. Names survive every filter, so resolve them here.
1594
+ */
1595
+ reorderColumnsByName(fromName: string, toName: string): void;
1477
1596
  reorderColumns(fromIndex: number, toIndex: number): void;
1478
1597
  updateColumnRequired(columnName: string, required: boolean): void;
1479
1598
  /**
@@ -1557,6 +1676,14 @@ declare class EruGridStore {
1557
1676
  toggleRowSelection(rowId: string): void;
1558
1677
  selectAllRowsInGroup(groupId: string): void;
1559
1678
  deselectAllRowsInGroup(groupId: string): void;
1679
+ /** Select every row loaded so far, across all groups. Stage one of select-all. */
1680
+ selectAllLoadedRows(): void;
1681
+ /**
1682
+ * Stage two of select-all: the user accepted "select all N matching". The set
1683
+ * of ids is left as-is (it still only holds what is loaded) — the flag is what
1684
+ * tells the consumer to act on the filter rather than on the ids.
1685
+ */
1686
+ setSelectAllMatching(value: boolean): void;
1560
1687
  clearSelection(): void;
1561
1688
  setConfiguration(configuration: GridConfiguration): void;
1562
1689
  /**
@@ -1815,6 +1942,12 @@ declare class EruGridService {
1815
1942
  get rows(): _angular_core.Signal<eru_grid.Row[]>;
1816
1943
  get selectedRowIds(): _angular_core.Signal<Set<string>>;
1817
1944
  get hasSelection(): _angular_core.Signal<boolean>;
1945
+ get selectedRows(): _angular_core.Signal<eru_grid.Row[]>;
1946
+ get totalSelectedCount(): _angular_core.Signal<number>;
1947
+ /** True once the user accepted "select all N matching" — act on the filter, not the ids. */
1948
+ get selectAllMatching(): _angular_core.Signal<boolean>;
1949
+ get totalMatchingCount(): _angular_core.Signal<number>;
1950
+ clearSelection(): void;
1818
1951
  get theme(): ThemeService;
1819
1952
  constrainColumnWidth(width: number, column: Field | undefined): number;
1820
1953
  /**
@@ -1887,6 +2020,11 @@ declare class EruGridComponent implements OnInit, AfterViewInit, OnDestroy {
1887
2020
  private elementRef;
1888
2021
  private breakpointObserver;
1889
2022
  readonly isSmViewport: _angular_core.WritableSignal<boolean>;
2023
+ /** Set once the host ResizeObserver has reported a usable width, after which
2024
+ * the window media query stops feeding isSmViewport. */
2025
+ private hasMeasuredOwnWidth;
2026
+ /** Below `md`, matching the media query this replaced. */
2027
+ private static readonly SM_VIEWPORT_MAX_WIDTH;
1890
2028
  private containerHeight;
1891
2029
  private resizeObserver;
1892
2030
  private boardViewportObserver;
@@ -2001,6 +2139,13 @@ declare class EruGridComponent implements OnInit, AfterViewInit, OnDestroy {
2001
2139
  * request via gridStore.removeExcelDownloadRequest(id) once done.
2002
2140
  */
2003
2141
  onExcelDownloadClick(event: Event): void;
2142
+ /**
2143
+ * Enqueue an excel-download request without a click. This is the same path
2144
+ * the icon takes, exposed so a host can trigger the export from its own
2145
+ * button — useful when `config.excel_download_icon` is off because the
2146
+ * built-in icon sits in the wrong place for the page.
2147
+ */
2148
+ requestExcelDownload(): void;
2004
2149
  private buildExcelDownloadPayload;
2005
2150
  /**
2006
2151
  * The columns the `columns` block of the excel-download payload describes.
@@ -2035,6 +2180,15 @@ declare class EruGridComponent implements OnInit, AfterViewInit, OnDestroy {
2035
2180
  groupedRows: _angular_core.Signal<GroupItem[]>;
2036
2181
  columns: _angular_core.Signal<Field[]>;
2037
2182
  selectedRowIds: _angular_core.Signal<Set<string>>;
2183
+ selectAllMatching: _angular_core.Signal<boolean>;
2184
+ totalMatchingCount: _angular_core.Signal<number>;
2185
+ /**
2186
+ * Show the select-all banner only where it has something to say: either the
2187
+ * user already accepted "all N matching" and needs it reported back, or they
2188
+ * selected everything loaded and there is more behind it to offer. Ticking a
2189
+ * few rows deliberately is not an occasion to offer the whole result set.
2190
+ */
2191
+ showSelectAllBanner: _angular_core.Signal<boolean>;
2038
2192
  totalRowCount: _angular_core.Signal<number>;
2039
2193
  averageGroupHeight: _angular_core.Signal<number>;
2040
2194
  currentPivotScrollIndex: _angular_core.WritableSignal<number>;
@@ -2262,7 +2416,17 @@ declare class EruGridComponent implements OnInit, AfterViewInit, OnDestroy {
2262
2416
  */
2263
2417
  readonly gridActions: _angular_core.Signal<GridAction[]>;
2264
2418
  readonly hasConfiguredActions: _angular_core.Signal<boolean>;
2265
- readonly actionDisplayType: _angular_core.Signal<"icons" | "kebab">;
2419
+ readonly actionDisplayType: _angular_core.Signal<"icons" | "icons_outlined" | "kebab">;
2420
+ /**
2421
+ * Icon font for the row-action icons.
2422
+ *
2423
+ * Filled and outlined are two different Material fonts over the same ligature
2424
+ * names, not two ligatures — so the choice is a `fontSet` swap and every
2425
+ * configured action keeps the icon name it was given. Consumers must have the
2426
+ * outlined font loaded; without it mat-icon falls back to the filled face, so
2427
+ * the worst case is the previous look rather than empty boxes.
2428
+ */
2429
+ readonly actionIconFontSet: _angular_core.Signal<string>;
2266
2430
  /**
2267
2431
  * The actions that apply to one row, after each action's
2268
2432
  * `action_visible_condition` is evaluated against that row's values.
@@ -2340,11 +2504,20 @@ declare class EruGridComponent implements OnInit, AfterViewInit, OnDestroy {
2340
2504
  * @returns true if action column is enabled and matches the position
2341
2505
  */
2342
2506
  shouldShowActionColumn(position: 'before' | 'after'): boolean;
2507
+ /**
2508
+ * The header checkbox. Stage one only: it selects the rows loaded so far, and
2509
+ * the banner then offers "select all N matching" for the rest. It cannot
2510
+ * select unloaded pages itself — the grid never holds them.
2511
+ */
2343
2512
  toggleAllGroups(event: Event): void;
2513
+ /** The banner's "select all N matching" — stage two. */
2514
+ selectAllMatchingRows(): void;
2515
+ clearRowSelection(): void;
2344
2516
  isRowSelected(rowId?: string): boolean;
2345
2517
  isGroupSelected(groupId: string): boolean;
2346
2518
  isAllGroupsSelected(): boolean;
2347
- getSelectedRows(): any[];
2519
+ getSelectedRows(): Row[];
2520
+ getSelectedRowIds(): string[];
2348
2521
  toggleGroupExpansion(groupId: string): void;
2349
2522
  /**
2350
2523
  * Toggle collapse/expand state of a column group
@@ -2568,6 +2741,9 @@ interface AttachmentConfig {
2568
2741
  allowedFileTypes?: string[];
2569
2742
  maxFileSize?: number;
2570
2743
  columnWidth?: number;
2744
+ storageName?: string;
2745
+ folderName?: string;
2746
+ defaultUpload?: boolean;
2571
2747
  }
2572
2748
  declare class AttachmentComponent implements OnInit {
2573
2749
  private el;
@@ -2586,6 +2762,14 @@ declare class AttachmentComponent implements OnInit {
2586
2762
  drilldownClick: EventEmitter<string[] | null>;
2587
2763
  editModeChange: EventEmitter<boolean>;
2588
2764
  fileAdded: EventEmitter<string>;
2765
+ /** The file's contents and where it is meant to go, for a host that uploads. */
2766
+ fileUpload: EventEmitter<{
2767
+ fileName: string;
2768
+ file: string;
2769
+ storage_name: string;
2770
+ folder_name: string;
2771
+ default_upload: boolean;
2772
+ }>;
2589
2773
  fileDeleted: EventEmitter<string>;
2590
2774
  fileViewed: EventEmitter<string>;
2591
2775
  currentValue: _angular_core.WritableSignal<string[]>;
@@ -2626,7 +2810,7 @@ declare class AttachmentComponent implements OnInit {
2626
2810
  trackByFile(index: number, file: string): string;
2627
2811
  getFileName(file: string): string;
2628
2812
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<AttachmentComponent, never>;
2629
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<AttachmentComponent, "eru-attachment", 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; }; "columnWidth": { "alias": "columnWidth"; "required": false; "isSignal": true; }; "eruGridStore": { "alias": "eruGridStore"; "required": false; "isSignal": true; }; }, { "valueChange": "valueChange"; "blur": "blur"; "focus": "focus"; "drilldownClick": "drilldownClick"; "editModeChange": "editModeChange"; "fileAdded": "fileAdded"; "fileDeleted": "fileDeleted"; "fileViewed": "fileViewed"; }, never, never, true, never>;
2813
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<AttachmentComponent, "eru-attachment", 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; }; "columnWidth": { "alias": "columnWidth"; "required": false; "isSignal": true; }; "eruGridStore": { "alias": "eruGridStore"; "required": false; "isSignal": true; }; }, { "valueChange": "valueChange"; "blur": "blur"; "focus": "focus"; "drilldownClick": "drilldownClick"; "editModeChange": "editModeChange"; "fileAdded": "fileAdded"; "fileUpload": "fileUpload"; "fileDeleted": "fileDeleted"; "fileViewed": "fileViewed"; }, never, never, true, never>;
2630
2814
  }
2631
2815
 
2632
2816
  declare class CheckboxComponent {
@@ -2761,6 +2945,8 @@ declare class CompositeComponent {
2761
2945
  drilldownClick: _angular_core.OutputEmitterRef<string>;
2762
2946
  readonly inline: _angular_core.Signal<boolean>;
2763
2947
  readonly separator: _angular_core.Signal<string>;
2948
+ /** Which side each part's label sits on, or 'none' for bare values. */
2949
+ readonly labelPosition: _angular_core.Signal<"none" | "left" | "right">;
2764
2950
  readonly primaryCss: _angular_core.Signal<Record<string, string>>;
2765
2951
  readonly secondaryCss: _angular_core.Signal<Record<string, string>>;
2766
2952
  /**
@@ -2892,12 +3078,22 @@ declare class DatetimeComponent {
2892
3078
  updateValue(): void;
2893
3079
  onDrillableClick(event: Event): void;
2894
3080
  readonly dtFormat: _angular_core.Signal<string>;
3081
+ /**
3082
+ * The canonical stored form of an edit: `yyyy-MM-dd HH:mm:ss`.
3083
+ *
3084
+ * It used to be built from the DISPLAY pattern, which made the stored shape
3085
+ * depend on how the column happened to be formatted and dropped the seconds
3086
+ * whenever the pattern had no `ss` — so editing a server timestamp under a
3087
+ * `hh:mm` pattern silently truncated it. Display goes through
3088
+ * formatDateTimeWithPattern; storage is always this one shape.
3089
+ */
2895
3090
  formatDateTime(date: Date): string;
2896
3091
  formatTime(date: Date): string;
2897
- parseDateTimeString(dateTimeString: string): {
2898
- date: Date;
2899
- time: string;
2900
- } | null;
3092
+ /**
3093
+ * Seconds are carried through when the time string has them. The picker only
3094
+ * offers HH:mm, so an untouched value keeps the seconds it arrived with
3095
+ * rather than being silently zeroed on a date-only change.
3096
+ */
2901
3097
  combineDateAndTime(date: Date, time: string): Date;
2902
3098
  isValidTimeFormat(time: string): boolean;
2903
3099
  getDisplayValue(): string;
@@ -2934,6 +3130,17 @@ declare class DurationComponent {
2934
3130
  onOverlayBackdropClick(): void;
2935
3131
  onOverlayClick(event: Event): void;
2936
3132
  onBlur(): void;
3133
+ /**
3134
+ * Close the editor, emitting only when the duration actually changed.
3135
+ *
3136
+ * It used to emit unconditionally, and since the editor works in minutes that
3137
+ * rewrote the stored representation on a no-op: a cell holding '02:30' became
3138
+ * 150 merely by opening the overlay and dismissing it. Opening a cell is not
3139
+ * an edit.
3140
+ */
3141
+ private commitAndClose;
3142
+ /** The incoming value in minutes, for comparison against an edit. */
3143
+ private storedMinutes;
2937
3144
  onDrillableClick(event: Event): void;
2938
3145
  onManualMinutesChange(value: string): void;
2939
3146
  onStartTimeChange(time: string): void;
@@ -3328,7 +3535,25 @@ declare class ProgressComponent implements OnInit {
3328
3535
  drilldownClick: EventEmitter<number | null>;
3329
3536
  editModeChange: EventEmitter<boolean>;
3330
3537
  currentValue: _angular_core.WritableSignal<number>;
3538
+ /** Configured scale, defaulting to the 0-100 percentage scale. */
3539
+ readonly scaleMin: _angular_core.Signal<number>;
3540
+ readonly scaleMax: _angular_core.Signal<number>;
3541
+ /**
3542
+ * The value the slider edits — the raw stored number, only coerced when it is
3543
+ * not a number at all.
3544
+ *
3545
+ * Deliberately NOT displayValue(): that clamps to the scale for the bar, and
3546
+ * seeding the control with it meant a stored 150 opened the slider at 100 and
3547
+ * the first drag wrote the clamp back as the real value.
3548
+ */
3549
+ readonly editValue: _angular_core.Signal<number>;
3331
3550
  displayValue: _angular_core.Signal<number>;
3551
+ /**
3552
+ * Bar fill as a percentage of the configured scale. The bar's width is always
3553
+ * 0-100% of its track, whatever units the column counts in — a 3 on a 0-5
3554
+ * scale fills 60%, not 3%.
3555
+ */
3556
+ readonly fillPercent: _angular_core.Signal<number>;
3332
3557
  barColor: _angular_core.Signal<string | null>;
3333
3558
  /**
3334
3559
  * Whether to show the value as a percentage. `is_perc` is the data model's
@@ -3787,5 +4012,5 @@ declare class ThemeToggleComponent {
3787
4012
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<ThemeToggleComponent, "eru-theme-toggle", never, {}, {}, never, never, true, never>;
3788
4013
  }
3789
4014
 
3790
- export { ACTION_COLUMN_MIN_WIDTH, AttachmentComponent, CELL_RULE_OPERATORS, CheckboxComponent, ChipListComponent, 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, NumericInputDirective, 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, abbreviationScaleFor, cellRuleBarPercent, cellRuleMatches, cellRuleToCss, cellStatAlias, cellTextStyleToCss, collectColumnStatRequests, columnCellRules, composeColorValue, evaluateRowCondition, formatCellValue, formatDateWithPattern, formatNumberValue, hasOwnCellRules, matchCellRule, matchColorRange, normalizeDatatype, normalizeDateFormat, normalizeDateTimeFormat, parseCellDate, parseColorValue, parseDateWithPattern, readRowValue, resolveColumnRules, resolveRowValue, resolveStatValue, statusPillColors, tagPillColors };
3791
- export type { ActionClick, AggregationFunction, AttachmentConfig, BoardCardContext, CellFormatRule, CellRuleOperator, CellStatRef, CellStatVerb, CellTemplateContext, CellTextStyle, CellValueChange, ChipListItem, 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 };
4015
+ export { ACTION_COLUMN_MIN_WIDTH, AttachmentComponent, CELL_RULE_OPERATORS, CheckboxComponent, ChipListComponent, 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, NumericInputDirective, 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, abbreviationScaleFor, cellRuleBarPercent, cellRuleMatches, cellRuleToCss, cellStatAlias, cellTextStyleToCss, collectColumnStatRequests, columnCellRules, composeColorValue, effectiveValueDatatype, evaluateRowCondition, formatCellValue, formatDateTimeWithPattern, formatDateWithPattern, formatNumberValue, hasOwnCellRules, matchCellRule, matchColorRange, normalizeCellRender, normalizeDatatype, normalizeDateFormat, normalizeDateTimeFormat, parseCellDate, parseCellDateTime, parseColorValue, parseDateWithPattern, readRowValue, resolveColumnRules, resolveRowValue, resolveStatValue, rowSelectionKey, statusPillColors, tagPillColors, toDateOnlyString, toDateTimeString };
4016
+ export type { ActionClick, AggregationFunction, AttachmentConfig, BoardCardContext, CellFormatRule, CellRender, CellRuleOperator, CellStatRef, CellStatVerb, CellTemplateContext, CellTextStyle, CellValueChange, ChipListItem, 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 };