@forgeroute/ui 0.3.0 → 0.3.2

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.
@@ -45,7 +45,8 @@ export interface ToolbarAction {
45
45
  badge?: number;
46
46
  /** Hide this action entirely */
47
47
  hidden?: boolean;
48
- /** Only shown when the table's `permission` is 'full' (e.g. "Add …", bulk mutations). */
48
+ /** Documentation of intent: marks a mutating action ("Add …", bulk mutations). It does not change behavior - the table hides
49
+ * EVERY page-defined toolbar action for any `permission` other than 'full', with or without this flag. */
49
50
  requiresFull?: boolean;
50
51
  /**
51
52
  * Keep this action when the table is empty and unfiltered. By default only `variant: 'primary'` buttons survive that
@@ -87,9 +88,13 @@ export interface RowAction {
87
88
  opens?: 'modal' | 'panel';
88
89
  /** Required when opens === 'modal'. Drives the confirm dialog shown by the table. */
89
90
  modal?: ConfirmConfig;
90
- /** Only shown when the table's `permission` is 'full' (edit, delete, any mutation).
91
- * The built-in `type: 'delete'` action is always treated as requiring full permission. */
91
+ /** Documentation of intent: marks a mutating action (edit, delete, ...). It does not change behavior - for any `permission`
92
+ * other than 'full' the table offers only View and actions marked `allowReadOnly`, with or without this flag.
93
+ * The built-in `type: 'delete'` action is never offered to read-only users. */
92
94
  requiresFull?: boolean;
95
+ /** Keep this action for read-only users too (download, preview: reads that change nothing). Without it a read-only table offers only
96
+ * View. Never applies to the built-in delete, and the table still drops the Actions column when no row has any visible action. */
97
+ allowReadOnly?: boolean;
93
98
  }
94
99
  /** Page-level permission passed to `<ui-data-table [permission]>`. Anything other than 'full' is read-only
95
100
  * (apps use values like 'read-only' / 'hidden'). */
@@ -105,6 +110,9 @@ export interface ColumnDef {
105
110
  /** Values a bulk "Change <label>" may set. When omitted the options come from /filter-counts.
106
111
  * Use it when only some values are user-settable or when a valid value may currently have no rows. */
107
112
  bulkOptions?: string[];
113
+ /** Fixed column width (any CSS length, e.g. '140px'). Applied as width, min-width and max-width; cell text longer than
114
+ * it is cut with an ellipsis. Omit for an automatic width. Not applied to the Actions column's cell clipping. */
115
+ width?: string;
108
116
  align?: 'left' | 'right' | 'center';
109
117
  headerAlign?: 'left' | 'right' | 'center';
110
118
  /** How to render cell content. Defaults to 'text'. */
@@ -127,7 +135,7 @@ export interface ColumnDef {
127
135
  overdueThreshold?: number;
128
136
  /**
129
137
  * Maps a row to a progress bar. Return null to render a plain '—' (e.g. nothing to track).
130
- * `label` is the text beside the bar (e.g. "3/5"); `tooltip` is the hover text.
138
+ * `label` is the text beside the bar (e.g. "3/5"); `tooltip` is the hover text. Leave `variant` out and the bar colors itself by completion (red / amber / blue / green).
131
139
  */
132
140
  progressFn?: (item: any) => {
133
141
  value: number;
@@ -141,6 +149,11 @@ export interface ColumnDef {
141
149
  tagsKey?: string;
142
150
  /** Returns the image URL for the row. A falsy value (null / undefined / '') shows the placeholder icon. */
143
151
  imageFn?: (item: any) => string | null | undefined;
152
+ /** Focal point (percent, 50/50 = centered) of the cropped image, applied as CSS object-position. */
153
+ imagePositionFn?: (item: any) => {
154
+ x: number | null | undefined;
155
+ y: number | null | undefined;
156
+ } | null | undefined;
144
157
  /** Alt text for the row's image. When omitted the image is decorative (`alt=""`). */
145
158
  imageAlt?: (item: any) => string;
146
159
  /** 'circle' (default) or 'rounded' (3:2 rounded rectangle). */
@@ -231,6 +244,17 @@ export type BulkUpdateOption<T = any> = string | {
231
244
  * { field: 'delete', deletable: (row: Invoice) => row.status === 'DRAFT' }
232
245
  */
233
246
  deletable?: (row: T) => boolean;
247
+ /**
248
+ * Field changes (`{ field, canChange }`): true when the server will accept moving THIS row to `target` (a value the select offers).
249
+ * For rules the field values alone can't express, e.g. a draft can only be sent when it has a document and a recipient. Keep it
250
+ * identical to the backend rule. Rows it refuses are skipped like rows `allowedFrom` refuses ("N selected rows can't be changed to X
251
+ * and will be skipped." / `ctx.skippedBlocked` + `ctx.skippedRows` for host `confirm` copy), are never sent, and a target is offered
252
+ * only while some selected row can move to it. It runs after `allowedFrom` and only sees rows on the loaded page. Omit it and
253
+ * nothing changes.
254
+ *
255
+ * { field: 'status', allowedFrom: { SENT: ['DRAFT'] }, canChange: (row, target) => target !== 'SENT' || canSend(row) }
256
+ */
257
+ canChange?: (row: T, target: string) => boolean;
234
258
  };
235
259
  /** What a bulk confirm function receives. For bulk Delete: `targetValue`/`targetLabel` are '', `columnLabel` is 'Delete', skipped counts are 0. */
236
260
  export interface BulkConfirmContext<T = any> {
@@ -250,14 +274,17 @@ export interface BulkConfirmContext<T = any> {
250
274
  /** Raw target value ("APPROVED") and its display label ("Approved"). */
251
275
  targetValue: string;
252
276
  targetLabel: string;
253
- /** The eligible row objects (name records, show before -> after). Only rows on the loaded page are available. */
277
+ /**
278
+ * The eligible row objects (name records, show before -> after). A selection never spans pages (any reload clears it and
279
+ * select-all takes the loaded page), so these are every row that will be sent.
280
+ */
254
281
  rows: T[];
255
282
  /** The selected rows that will be skipped. */
256
283
  skippedRows: T[];
257
284
  }
258
285
  /** Host copy for one bulk confirm. Plain text only (never HTML); `\n` in `message` shows as a line break. */
259
286
  export interface BulkConfirmCopy {
260
- /** Default: the action label ("Change Status") / "Delete Selected". */
287
+ /** Default: the action label ("Change Status") / "Delete <Items>" built from the table's item label ("template" → "Delete Templates"). */
261
288
  title?: string;
262
289
  message: string;
263
290
  /** Rendered as a bullet list under the message (consequences, what is NOT affected, undoable or not). */
@@ -285,6 +312,8 @@ export interface BulkActionDef {
285
312
  confirm?: BulkConfirmFn | Record<string, BulkConfirmFn>;
286
313
  /** Bulk Delete only: which rows the server will delete (from `{ field: 'delete', deletable }`). */
287
314
  deletable?: (row: any) => boolean;
315
+ /** Field changes: per-row check that the server will accept the move to a target (from `{ field, canChange }`). */
316
+ canChange?: (row: any, target: string) => boolean;
288
317
  /**
289
318
  * The item field this action targets (e.g. 'status', 'type').
290
319
  * When set the table shows an inline select populated from the column's option sources.
@@ -767,7 +796,7 @@ export declare function createFieldReveal(showErrors: Signal<boolean>): {
767
796
  revealed: Signal<boolean>;
768
797
  };
769
798
  /** Splits `YYYY-MM-DD` (optionally followed by `Thh:mm[:ss]`) and rejects impossible dates (2026-02-31) and times (25:00). */
770
- export declare function parseIso(value: string, withTime: boolean): {
799
+ export declare function parseIso(value: string | null | undefined, withTime: boolean): {
771
800
  y: number;
772
801
  mo: number;
773
802
  d: number;
@@ -775,9 +804,9 @@ export declare function parseIso(value: string, withTime: boolean): {
775
804
  mi: number;
776
805
  } | null;
777
806
  /** "Oct 20, 2026" from an ISO date (never shifted by the time zone). */
778
- export declare function formatIsoDate(value: string): string;
807
+ export declare function formatIsoDate(value: string | null | undefined): string;
779
808
  /** "Oct 20, 2026, 3:30 PM" from an ISO local date-time. */
780
- export declare function formatIsoDateTime(value: string): string;
809
+ export declare function formatIsoDateTime(value: string | null | undefined): string;
781
810
  /** Sortable key `YYYYMMDDHHmm` of a parsed ISO value. */
782
811
  export declare function isoKey(p: {
783
812
  y: number;
@@ -786,6 +815,10 @@ export declare function isoKey(p: {
786
815
  h: number;
787
816
  mi: number;
788
817
  }): number;
818
+ /** Parses `HH:mm` (optionally `HH:mm:ss`) into minutes since midnight; null for anything else (25:00, 9:5, 09:30:99, text, null/undefined). */
819
+ export declare function parseTime(value: string | null | undefined): number | null;
820
+ /** "9:00 AM" / "12:30 PM" from an `HH:mm` value (returned unchanged when it cannot be parsed; '' for null/undefined/non-strings). */
821
+ export declare function formatTime(value: string | null | undefined): string;
789
822
  export interface SelectOption {
790
823
  value: string;
791
824
  label: string;
@@ -1051,6 +1084,8 @@ export declare class DataTableComponent<T extends Record<string, any>> implement
1051
1084
  /** Plural label; defaults to English pluralisation of `itemLabel` ("property" → "properties"). */
1052
1085
  readonly itemLabelPlural: import("@angular/core").InputSignal<string>;
1053
1086
  protected _countLabel(count: number): string;
1087
+ /** Default bulk-Delete confirm title: "Delete " + the title-cased plural item label ("template" → "Delete Templates", "lien waiver" → "Delete Lien Waivers"). */
1088
+ protected _deleteTitle(): string;
1054
1089
  /**
1055
1090
  * Column keys to enable bulk updates for, plus the special keyword `'delete'`.
1056
1091
  * e.g. `['status', 'type', 'delete']`
@@ -1135,6 +1170,8 @@ export declare class DataTableComponent<T extends Record<string, any>> implement
1135
1170
  private _columnBadgeLabel;
1136
1171
  protected readonly _error: import("@angular/core").WritableSignal<string | null>;
1137
1172
  protected readonly _search: import("@angular/core").WritableSignal<string>;
1173
+ /** The search text as sent to the API: lower-cased, so every search is case-insensitive whatever the backend does. The input still shows what the user typed. */
1174
+ protected readonly _searchParam: Signal<string>;
1138
1175
  protected readonly _page: import("@angular/core").WritableSignal<number>;
1139
1176
  protected readonly _sortField: import("@angular/core").WritableSignal<string | null>;
1140
1177
  protected readonly _sortDir: import("@angular/core").WritableSignal<SortDir>;
@@ -1147,6 +1184,8 @@ export declare class DataTableComponent<T extends Record<string, any>> implement
1147
1184
  protected readonly _effectiveSavedViews: Signal<SavedView[]>;
1148
1185
  /** Empty = show all defaultVisible; non-empty = show exactly these keys */
1149
1186
  protected readonly _visibleColumns: import("@angular/core").WritableSignal<string[]>;
1187
+ /** Drops the key of every `cellType: 'actions'` column — Actions is never part of a configured/saved column list. */
1188
+ protected _configurableKeys(keys: string[] | null | undefined): string[];
1150
1189
  protected readonly _ieRef: Signal<ImportExportComponent | undefined>;
1151
1190
  /** Tag overflow tooltip — fixed position to escape table's overflow:auto */
1152
1191
  protected readonly _tagTooltip: import("@angular/core").WritableSignal<{
@@ -1233,12 +1272,19 @@ export declare class DataTableComponent<T extends Record<string, any>> implement
1233
1272
  * through the column's own `nameFn` / `render` so it reads exactly like the cell. '' when there is none.
1234
1273
  */
1235
1274
  protected rowName(item: T): string;
1236
- /** "Select Acme Electric" — a row's selection checkbox name. */
1275
+ /**
1276
+ * Rows of the loaded page whose name repeats get a position suffix (" (1 of 2)", " (2 of 2)"), so a screen-reader user never hears two rows
1277
+ * announced identically ("Select Jane Cooper" twice). Names that are unique on the page — and rows with no name — are left exactly as they are.
1278
+ */
1279
+ private readonly _rowNameSuffix;
1280
+ /** A row's accessible name: its name, plus the position among rows of the same name when that name repeats on the page. */
1281
+ private rowAccessibleName;
1282
+ /** "Select Acme Electric" — a row's selection checkbox name ("Select Acme Electric (2 of 3)" when the name repeats on the page). */
1237
1283
  protected selectRowLabel(item: T): string;
1238
1284
  /**
1239
1285
  * "Row actions for Acme Electric" — a row's actions-menu trigger name. It still contains the generic "Row actions"
1240
1286
  * text, so lookups by that accessible name (substring) keep finding the button, while a screen-reader user now
1241
- * hears which row it belongs to.
1287
+ * hears which row it belongs to ("Row actions for Acme Electric (2 of 3)" when the name repeats on the page).
1242
1288
  */
1243
1289
  protected rowActionsLabel(item: T): string;
1244
1290
  protected toggleSelectAll(): void;
@@ -1355,7 +1401,8 @@ export declare class DataTableComponent<T extends Record<string, any>> implement
1355
1401
  protected onRowKeydown(e: KeyboardEvent, item: T): void;
1356
1402
  protected onInternalButtonClick(type: string): void;
1357
1403
  protected onImported(): void;
1358
- /** Row actions visible for the current permission: everything for 'full', only View (`type: 'view'`) otherwise. */
1404
+ /** Row actions visible for the current permission: everything for 'full'; otherwise only View (`type: 'view'`) and actions marked
1405
+ * `allowReadOnly` (never the built-in delete). The Actions column itself is shown only while some row has a visible action. */
1359
1406
  protected _rowActions(col: ColumnDef, item: T): RowAction[];
1360
1407
  protected onTableRowAction(type: string, col: ColumnDef, item: T): Promise<void>;
1361
1408
  private isNumericCol;
@@ -1367,6 +1414,8 @@ export declare class DataTableComponent<T extends Record<string, any>> implement
1367
1414
  protected imageUrl(col: ColumnDef, item: T): string | null;
1368
1415
  /** Always a string so the <img> keeps an `alt` attribute ('' = decorative). */
1369
1416
  protected imageAlt(col: ColumnDef, item: T): string;
1417
+ /** CSS object-position from `imagePositionFn` (percent); centered when there is none or it throws. */
1418
+ protected imagePosition(col: ColumnDef, item: T): string;
1370
1419
  protected imageClass(col: ColumnDef, small: boolean): string;
1371
1420
  protected onImageError(url: string): void;
1372
1421
  protected phoneCell(value: any): string;
@@ -1525,6 +1574,27 @@ export declare class DataTableComponent<T extends Record<string, any>> implement
1525
1574
  "rowDeleted": "rowDeleted";
1526
1575
  }, never, never, true, never>;
1527
1576
  }
1577
+ /**
1578
+ * Column-filter values travel as ONE comma-joined request parameter (`?section=Roofing,Siding`). A value that itself contains a comma
1579
+ * ("Roofing, Inc.") would be read as two. These helpers keep the wire format backward compatible and make such values unambiguous:
1580
+ *
1581
+ * - a value is sent AS IS unless joining it would be ambiguous: it contains a comma, a doubled backslash, or ends with a backslash;
1582
+ * - such a value is escaped: `\` becomes `\\` and `,` becomes `\,`;
1583
+ * - the reader splits on commas that are not escaped and unescapes `\,` and `\\`; any other backslash is an ordinary character.
1584
+ *
1585
+ * So every value that worked before (no comma, no doubled / trailing backslash) is byte-for-byte unchanged, and a backend that does not know the
1586
+ * escaping keeps working for them. Backends that parse filter values should split with the same rules (`splitFilterList` in the contractor
1587
+ * backend, `decodeFilterValues` here).
1588
+ */
1589
+ /** One value as it is written into the comma-joined parameter. */
1590
+ export declare function encodeFilterValue(value: string): string;
1591
+ /** The comma-joined parameter for a list of filter values (`['Roofing, Inc.', 'Siding']` -> `Roofing\, Inc.,Siding`). */
1592
+ export declare function encodeFilterValues(values: readonly string[]): string;
1593
+ /**
1594
+ * The values of a comma-joined parameter, the inverse of {@link encodeFilterValues}: split on unescaped commas, unescape `\,` and `\\`,
1595
+ * trim each value and drop the empty ones (the same as the plain split it replaces).
1596
+ */
1597
+ export declare function decodeFilterValues(raw: string): string[];
1528
1598
  export declare class SidePanelComponent implements OnDestroy {
1529
1599
  readonly open: import("@angular/core").InputSignal<boolean>;
1530
1600
  readonly title: import("@angular/core").InputSignal<string>;
@@ -1698,6 +1768,10 @@ export type ProgressBarVariant = 'blue' | 'green' | 'amber' | 'red' | 'slate';
1698
1768
  /**
1699
1769
  * Horizontal progress bar with an optional trailing label (e.g. "3/5").
1700
1770
  * Pass `value` and `max`; the fill width is clamped to 0–100%.
1771
+ *
1772
+ * The fill color is built in and follows completion, in four bands: red up to 25%, amber up to 50%, blue up to 75%,
1773
+ * green above 75% (full = green). Nothing needs to be passed. `variant` is an optional override for a bar whose
1774
+ * color means something else (for example an overdue status) — when it is set the color stays fixed.
1701
1775
  */
1702
1776
  export declare class ProgressBarComponent {
1703
1777
  /** Completed amount. */
@@ -1706,12 +1780,15 @@ export declare class ProgressBarComponent {
1706
1780
  readonly max: import("@angular/core").InputSignal<number>;
1707
1781
  /** Text shown to the right of the bar, e.g. "3/5". */
1708
1782
  readonly label: import("@angular/core").InputSignal<string>;
1709
- readonly variant: import("@angular/core").InputSignal<ProgressBarVariant>;
1710
- /** Native hover tooltip. */
1783
+ /** Optional fixed color override. Leave it out and the color follows completion (red / amber / blue / green). */
1784
+ readonly variant: import("@angular/core").InputSignal<ProgressBarVariant | null | undefined>;
1785
+ /** Hover / focus tooltip (library `uiTooltip`); `\n` starts a new line. */
1711
1786
  readonly tooltip: import("@angular/core").InputSignal<string>;
1712
1787
  readonly ariaLabel: import("@angular/core").InputSignal<string>;
1713
1788
  protected readonly clampedValue: import("@angular/core").Signal<number>;
1714
1789
  protected readonly percent: import("@angular/core").Signal<number>;
1790
+ /** The override when given, else the completion band: up to 25% red, up to 50% amber, up to 75% blue, above 75% green. */
1791
+ protected readonly effectiveVariant: import("@angular/core").Signal<ProgressBarVariant>;
1715
1792
  static ɵfac: i0.ɵɵFactoryDeclaration<ProgressBarComponent, never>;
1716
1793
  static ɵcmp: i0.ɵɵComponentDeclaration<ProgressBarComponent, "ui-progress-bar", never, {
1717
1794
  "value": {
@@ -1775,12 +1852,141 @@ export declare class SkeletonComponent {
1775
1852
  };
1776
1853
  }, {}, never, never, true, never>;
1777
1854
  }
1778
- export declare class CheckboxComponent implements ControlValueAccessor {
1855
+ /**
1856
+ * Hover / focus tooltip for any element: `<span uiTooltip="Saved">`.
1857
+ * Empty text shows nothing. Line breaks (`\n`) are kept. Escape or leaving the element closes it.
1858
+ * The bubble is rendered on `document.body` (position: fixed) so table/panel overflow never clips it.
1859
+ */
1860
+ export declare class TooltipDirective {
1861
+ /** Tooltip text; empty or null disables the tooltip. */
1862
+ readonly uiTooltip: import("@angular/core").InputSignal<string | null | undefined>;
1863
+ /** Preferred side; flips to the other side when there is no room. */
1864
+ readonly tooltipPosition: import("@angular/core").InputSignal<"top" | "bottom">;
1865
+ private readonly host;
1866
+ private readonly doc;
1867
+ private bubble;
1868
+ private readonly id;
1869
+ constructor();
1870
+ protected show(): void;
1871
+ protected hide(): void;
1872
+ static ɵfac: i0.ɵɵFactoryDeclaration<TooltipDirective, never>;
1873
+ static ɵdir: i0.ɵɵDirectiveDeclaration<TooltipDirective, "[uiTooltip]", never, {
1874
+ "uiTooltip": {
1875
+ "alias": "uiTooltip";
1876
+ "required": false;
1877
+ "isSignal": true;
1878
+ };
1879
+ "tooltipPosition": {
1880
+ "alias": "tooltipPosition";
1881
+ "required": false;
1882
+ "isSignal": true;
1883
+ };
1884
+ }, {}, never, never, true, never>;
1885
+ }
1886
+ export type ImageRepositionShape = 'circle' | 'rounded';
1887
+ /**
1888
+ * Drag-to-center photo frame. The image fills the frame (`object-fit: cover`) and the user drags it, or uses the arrow
1889
+ * keys, to choose which part stays visible. The result is a focal point in percent (`x`, `y`, 0-100, 50/50 = centered)
1890
+ * to apply as CSS `object-position` wherever the image is shown (`ui-image-preview` / the data table image cell take it).
1891
+ *
1892
+ * <ui-image-reposition [src]="url" [(x)]="posX" [(y)]="posY" label="Photo position" />
1893
+ *
1894
+ * Only the axis that overflows the frame can move (a landscape photo moves sideways, a portrait one up and down).
1895
+ * Arrow keys nudge by 2% (Shift: 10%). The frame is a labelled group with a hint for assistive tech.
1896
+ */
1897
+ export declare class ImageRepositionComponent {
1898
+ private static nextId;
1899
+ protected readonly hintId: string;
1900
+ private readonly host;
1901
+ /** Image URL (or data URL). Without one the frame is empty and cannot be moved. */
1902
+ readonly src: import("@angular/core").InputSignal<string | null | undefined>;
1903
+ readonly alt: import("@angular/core").InputSignal<string>;
1904
+ readonly shape: import("@angular/core").InputSignal<ImageRepositionShape>;
1905
+ /** Accessible name of the frame. */
1906
+ readonly label: import("@angular/core").InputSignal<string>;
1907
+ /** Focal point, percent from the left (0-100). Two-way: `[(x)]`. */
1908
+ readonly x: import("@angular/core").ModelSignal<number>;
1909
+ /** Focal point, percent from the top (0-100). Two-way: `[(y)]`. */
1910
+ readonly y: import("@angular/core").ModelSignal<number>;
1911
+ protected readonly dragging: import("@angular/core").WritableSignal<boolean>;
1912
+ private natural;
1913
+ private start;
1914
+ protected onLoad(e: Event): void;
1915
+ /** How many px the cover-scaled image overflows the frame on each axis (0 = that axis cannot move). */
1916
+ private overflow;
1917
+ protected onPointerDown(e: PointerEvent): void;
1918
+ protected onPointerMove(e: PointerEvent): void;
1919
+ protected endDrag(e: PointerEvent): void;
1920
+ protected onKeydown(e: KeyboardEvent): void;
1921
+ static ɵfac: i0.ɵɵFactoryDeclaration<ImageRepositionComponent, never>;
1922
+ static ɵcmp: i0.ɵɵComponentDeclaration<ImageRepositionComponent, "ui-image-reposition", never, {
1923
+ "src": {
1924
+ "alias": "src";
1925
+ "required": false;
1926
+ "isSignal": true;
1927
+ };
1928
+ "alt": {
1929
+ "alias": "alt";
1930
+ "required": false;
1931
+ "isSignal": true;
1932
+ };
1933
+ "shape": {
1934
+ "alias": "shape";
1935
+ "required": false;
1936
+ "isSignal": true;
1937
+ };
1938
+ "label": {
1939
+ "alias": "label";
1940
+ "required": false;
1941
+ "isSignal": true;
1942
+ };
1943
+ "x": {
1944
+ "alias": "x";
1945
+ "required": false;
1946
+ "isSignal": true;
1947
+ };
1948
+ "y": {
1949
+ "alias": "y";
1950
+ "required": false;
1951
+ "isSignal": true;
1952
+ };
1953
+ }, {
1954
+ "x": "xChange";
1955
+ "y": "yChange";
1956
+ }, never, never, true, never>;
1957
+ }
1958
+ export declare class CheckboxComponent implements ControlValueAccessor, Validator, UiFieldValidity {
1779
1959
  readonly label: import("@angular/core").InputSignal<string>;
1780
1960
  /** Accessible name for the native checkbox when there is no visible `label` (e.g. a table row's selector). */
1781
1961
  readonly ariaLabel: import("@angular/core").InputSignal<string>;
1782
1962
  readonly indeterminate: import("@angular/core").InputSignal<boolean>;
1783
1963
  readonly checked: import("@angular/core").ModelSignal<boolean>;
1964
+ /** The box must be ticked. */
1965
+ readonly required: import("@angular/core").InputSignal<boolean>;
1966
+ /** Replaces the built-in "<label> is required." message. */
1967
+ readonly requiredMessage: import("@angular/core").InputSignal<string>;
1968
+ readonly hint: import("@angular/core").InputSignal<string>;
1969
+ /** Host-provided error message (wins over the built-in one). */
1970
+ readonly error: import("@angular/core").InputSignal<string>;
1971
+ /** Reveal the built-in error message now (e.g. after a failed Save click), without waiting for a toggle. */
1972
+ readonly showErrors: import("@angular/core").InputSignal<boolean>;
1973
+ protected readonly _descId: string;
1974
+ private readonly _reveal;
1975
+ private readonly _issue;
1976
+ /** True while a required box is unticked or the host passed an `[error]`. */
1977
+ readonly invalid: import("@angular/core").Signal<boolean>;
1978
+ /** Message of the broken built-in rule ('' when valid), shown or not. */
1979
+ readonly errorMessage: import("@angular/core").Signal<string>;
1980
+ /** Emits whenever the field becomes invalid / valid. */
1981
+ readonly invalidChange: import("@angular/core").OutputEmitterRef<boolean>;
1982
+ protected readonly _activeError: import("@angular/core").Signal<string>;
1983
+ private _onValidatorChange;
1984
+ constructor();
1985
+ /** Re-run the form control's validation when a rule input (`required`, `requiredMessage`, `label`) changes. */
1986
+ ngOnChanges(): void;
1987
+ validate(control: AbstractControl): ValidationErrors | null;
1988
+ registerOnValidatorChange(fn: () => void): void;
1989
+ private _check;
1784
1990
  /** Public so a host template can bind `[disabled]` (a protected input fails strict template type-checking, TS2445). */
1785
1991
  readonly _disabledInput: import("@angular/core").InputSignal<boolean>;
1786
1992
  private readonly _cvaDisabled;
@@ -1814,6 +2020,31 @@ export declare class CheckboxComponent implements ControlValueAccessor {
1814
2020
  "required": false;
1815
2021
  "isSignal": true;
1816
2022
  };
2023
+ "required": {
2024
+ "alias": "required";
2025
+ "required": false;
2026
+ "isSignal": true;
2027
+ };
2028
+ "requiredMessage": {
2029
+ "alias": "requiredMessage";
2030
+ "required": false;
2031
+ "isSignal": true;
2032
+ };
2033
+ "hint": {
2034
+ "alias": "hint";
2035
+ "required": false;
2036
+ "isSignal": true;
2037
+ };
2038
+ "error": {
2039
+ "alias": "error";
2040
+ "required": false;
2041
+ "isSignal": true;
2042
+ };
2043
+ "showErrors": {
2044
+ "alias": "showErrors";
2045
+ "required": false;
2046
+ "isSignal": true;
2047
+ };
1817
2048
  "_disabledInput": {
1818
2049
  "alias": "disabled";
1819
2050
  "required": false;
@@ -1821,6 +2052,7 @@ export declare class CheckboxComponent implements ControlValueAccessor {
1821
2052
  };
1822
2053
  }, {
1823
2054
  "checked": "checkedChange";
2055
+ "invalidChange": "invalidChange";
1824
2056
  }, never, ["*"], true, never>;
1825
2057
  }
1826
2058
  export declare class ButtonComponent {
@@ -1835,6 +2067,8 @@ export declare class ButtonComponent {
1835
2067
  readonly ariaLabel: import("@angular/core").InputSignal<string | undefined>;
1836
2068
  readonly ariaExpanded: import("@angular/core").InputSignal<boolean | undefined>;
1837
2069
  readonly ariaPressed: import("@angular/core").InputSignal<boolean | undefined>;
2070
+ /** Id of the element that describes this button (an error or hint rendered next to it), e.g. `<ui-error errorId="x">`. Absent when empty. */
2071
+ readonly ariaDescribedBy: import("@angular/core").InputSignal<string | undefined>;
1838
2072
  _footerLeft?: string;
1839
2073
  _footerRight?: string;
1840
2074
  static ɵfac: i0.ɵɵFactoryDeclaration<ButtonComponent, never>;
@@ -1894,6 +2128,11 @@ export declare class ButtonComponent {
1894
2128
  "required": false;
1895
2129
  "isSignal": true;
1896
2130
  };
2131
+ "ariaDescribedBy": {
2132
+ "alias": "ariaDescribedBy";
2133
+ "required": false;
2134
+ "isSignal": true;
2135
+ };
1897
2136
  "_footerLeft": {
1898
2137
  "alias": "modal-footer-left";
1899
2138
  "required": false;
@@ -2919,6 +3158,15 @@ declare class SendEmailComponent implements OnInit {
2919
3158
  docsRemovedNote: string;
2920
3159
  onDocumentsChange(v: DocumentSendValue): void;
2921
3160
  onDocumentsInvalid(bad: boolean): void;
3161
+ /** Server limits (400 "Subject must be 255 characters or fewer." / "Body must be 10000 characters or fewer."). */
3162
+ readonly MAX_SUBJECT = 255;
3163
+ readonly MAX_BODY = 10000;
3164
+ /** Inline error when the message, as it will be sent, is over the server limit ('' when fine). */
3165
+ get bodyLengthError(): string;
3166
+ /** Inline error when the subject, as it will be sent, is over the server limit ('' when fine). */
3167
+ get subjectLengthError(): string;
3168
+ /** The length problem shown under the form in every mode; compose mode shows the message one on the editor instead. */
3169
+ get sendLengthError(): string;
2922
3170
  get canSend(): boolean;
2923
3171
  get minScheduleTime(): string;
2924
3172
  /**
@@ -3826,6 +4074,8 @@ export declare class TextareaInputComponent implements ControlValueAccessor, Val
3826
4074
  private readonly _cvaDisabled;
3827
4075
  protected readonly disabled: import("@angular/core").Signal<boolean>;
3828
4076
  protected readonly _value: import("@angular/core").WritableSignal<string>;
4077
+ /** The hint is shown inline after the label; with no label there is nothing to hang it on, so it renders under the field. */
4078
+ protected readonly _unlabelledHint: import("@angular/core").Signal<boolean>;
3829
4079
  private readonly _reveal;
3830
4080
  private readonly _issue;
3831
4081
  /** True while the value breaks a built-in rule or the host passed an `[error]`. */
@@ -4182,18 +4432,37 @@ export declare class DatetimeInputComponent implements ControlValueAccessor, Val
4182
4432
  "invalidChange": "invalidChange";
4183
4433
  }, never, never, true, never>;
4184
4434
  }
4185
- export declare class TimeInputComponent implements ControlValueAccessor {
4435
+ export declare class TimeInputComponent implements ControlValueAccessor, Validator, UiFieldValidity {
4186
4436
  readonly label: import("@angular/core").InputSignal<string>;
4437
+ /** Accessible name when there is no visible `label` (falls back to `label`). */
4438
+ readonly ariaLabel: import("@angular/core").InputSignal<string>;
4187
4439
  readonly required: import("@angular/core").InputSignal<boolean>;
4188
4440
  readonly min: import("@angular/core").InputSignal<string>;
4189
4441
  readonly max: import("@angular/core").InputSignal<string>;
4190
4442
  readonly hint: import("@angular/core").InputSignal<string>;
4191
4443
  readonly error: import("@angular/core").InputSignal<string>;
4444
+ /** Reveal the built-in error messages now (e.g. after a failed Save click), without waiting for blur. */
4445
+ readonly showErrors: import("@angular/core").InputSignal<boolean>;
4192
4446
  protected readonly _disabledInput: import("@angular/core").InputSignal<boolean>;
4193
4447
  private readonly _cvaDisabled;
4194
4448
  protected readonly disabled: import("@angular/core").Signal<boolean>;
4195
4449
  protected readonly _value: import("@angular/core").WritableSignal<string>;
4196
4450
  protected readonly _inputId: string;
4451
+ private readonly _reveal;
4452
+ private readonly _issue;
4453
+ /** True while the value breaks a built-in rule or the host passed an `[error]`. */
4454
+ readonly invalid: import("@angular/core").Signal<boolean>;
4455
+ /** Message of the first broken built-in rule ('' when valid), shown or not. */
4456
+ readonly errorMessage: import("@angular/core").Signal<string>;
4457
+ /** Emits whenever the field becomes invalid / valid. */
4458
+ readonly invalidChange: import("@angular/core").OutputEmitterRef<boolean>;
4459
+ protected readonly _activeError: import("@angular/core").Signal<string>;
4460
+ private _onValidatorChange;
4461
+ constructor();
4462
+ /** Re-run the form control's validation when a rule input (required, min, max) changes. */
4463
+ ngOnChanges(): void;
4464
+ validate(control: AbstractControl): ValidationErrors | null;
4465
+ registerOnValidatorChange(fn: () => void): void;
4197
4466
  private _onChange;
4198
4467
  private _onTouched;
4199
4468
  writeValue(val: string): void;
@@ -4202,6 +4471,7 @@ export declare class TimeInputComponent implements ControlValueAccessor {
4202
4471
  setDisabledState(d: boolean): void;
4203
4472
  protected onChange(event: Event): void;
4204
4473
  protected onBlur(): void;
4474
+ private _check;
4205
4475
  static ɵfac: i0.ɵɵFactoryDeclaration<TimeInputComponent, never>;
4206
4476
  static ɵcmp: i0.ɵɵComponentDeclaration<TimeInputComponent, "ui-time-input", never, {
4207
4477
  "label": {
@@ -4209,6 +4479,11 @@ export declare class TimeInputComponent implements ControlValueAccessor {
4209
4479
  "required": false;
4210
4480
  "isSignal": true;
4211
4481
  };
4482
+ "ariaLabel": {
4483
+ "alias": "ariaLabel";
4484
+ "required": false;
4485
+ "isSignal": true;
4486
+ };
4212
4487
  "required": {
4213
4488
  "alias": "required";
4214
4489
  "required": false;
@@ -4234,12 +4509,19 @@ export declare class TimeInputComponent implements ControlValueAccessor {
4234
4509
  "required": false;
4235
4510
  "isSignal": true;
4236
4511
  };
4512
+ "showErrors": {
4513
+ "alias": "showErrors";
4514
+ "required": false;
4515
+ "isSignal": true;
4516
+ };
4237
4517
  "_disabledInput": {
4238
4518
  "alias": "disabled";
4239
4519
  "required": false;
4240
4520
  "isSignal": true;
4241
4521
  };
4242
- }, {}, never, never, true, never>;
4522
+ }, {
4523
+ "invalidChange": "invalidChange";
4524
+ }, never, never, true, never>;
4243
4525
  }
4244
4526
  /**
4245
4527
  * Searchable multi-value dropdown. Selected values render as dismissible chips above the trigger.
@@ -5070,6 +5352,9 @@ export declare class ImagePreviewComponent {
5070
5352
  readonly size: import("@angular/core").InputSignal<ImagePreviewSize>;
5071
5353
  readonly placeholder: import("@angular/core").InputSignal<ImagePreviewPlaceholder>;
5072
5354
  readonly loading: import("@angular/core").InputSignal<"lazy" | "eager">;
5355
+ /** Focal point in percent (0-100, default centered) — which part of a cropped image stays visible (CSS object-position). */
5356
+ readonly positionX: import("@angular/core").InputSignal<number | null | undefined>;
5357
+ readonly positionY: import("@angular/core").InputSignal<number | null | undefined>;
5073
5358
  /**
5074
5359
  * Optional retry trigger: whenever its value changes, a failed image is attempted again (signal inputs cannot see
5075
5360
  * the same `src` being set twice, so a host bumps this, e.g. a counter, to retry the same URL).
@@ -5078,6 +5363,7 @@ export declare class ImagePreviewComponent {
5078
5363
  protected readonly _failed: import("@angular/core").WritableSignal<boolean>;
5079
5364
  /** Trimmed src; blank / whitespace-only is treated as no image. */
5080
5365
  protected readonly _url: import("@angular/core").Signal<string | null>;
5366
+ protected readonly _objectPosition: import("@angular/core").Signal<string>;
5081
5367
  protected readonly _cls: import("@angular/core").Signal<string>;
5082
5368
  constructor();
5083
5369
  /** Clears the failed state so the current `src` is attempted again (call via viewChild). */
@@ -5115,6 +5401,16 @@ export declare class ImagePreviewComponent {
5115
5401
  "required": false;
5116
5402
  "isSignal": true;
5117
5403
  };
5404
+ "positionX": {
5405
+ "alias": "positionX";
5406
+ "required": false;
5407
+ "isSignal": true;
5408
+ };
5409
+ "positionY": {
5410
+ "alias": "positionY";
5411
+ "required": false;
5412
+ "isSignal": true;
5413
+ };
5118
5414
  "retryKey": {
5119
5415
  "alias": "retryKey";
5120
5416
  "required": false;
@@ -5439,4 +5735,458 @@ export declare class RichTextEditorComponent implements ControlValueAccessor {
5439
5735
  * raw status text, "null"). Callers fall back to their own generated wording on `null`.
5440
5736
  */
5441
5737
  export declare function humanReadableMessage(value: unknown): string | null;
5738
+ /**
5739
+ * Single native radio button (visual tokens of `ui-checkbox`). Normally rendered by `ui-radio-group`; usable standalone
5740
+ * when the host manages the shared `name` and the `checked` state itself.
5741
+ */
5742
+ export declare class RadioComponent {
5743
+ readonly label: import("@angular/core").InputSignal<string>;
5744
+ readonly description: import("@angular/core").InputSignal<string>;
5745
+ /** Accessible name when there is no visible `label`. */
5746
+ readonly ariaLabel: import("@angular/core").InputSignal<string>;
5747
+ readonly value: import("@angular/core").InputSignal<string>;
5748
+ /** Radios with the same `name` form one keyboard (arrow key) group. */
5749
+ readonly name: import("@angular/core").InputSignal<string>;
5750
+ readonly checked: import("@angular/core").InputSignal<boolean>;
5751
+ readonly invalid: import("@angular/core").InputSignal<boolean>;
5752
+ /** Id(s) of the element(s) describing the group (hint / error). */
5753
+ readonly describedBy: import("@angular/core").InputSignal<string>;
5754
+ /** Public so a host template can bind `[disabled]` (a protected input fails strict template type-checking). */
5755
+ readonly _disabledInput: import("@angular/core").InputSignal<boolean>;
5756
+ protected readonly disabled: import("@angular/core").InputSignal<boolean>;
5757
+ protected readonly _labelId: string;
5758
+ /** With a description inside the <label>, the accessible name would read "Email We send a message": name the input by the label text only. */
5759
+ protected readonly _labelledBy: import("@angular/core").Signal<string | null>;
5760
+ protected readonly _descriptionId: string;
5761
+ /** Group hint/error id plus the option's own description (kept out of the label so the accessible name is label-only). */
5762
+ protected readonly _describedByIds: import("@angular/core").Signal<string | null>;
5763
+ /** Emits the radio's `value` when the user selects it. */
5764
+ readonly selected: import("@angular/core").OutputEmitterRef<string>;
5765
+ protected onChange(event: Event): void;
5766
+ static ɵfac: i0.ɵɵFactoryDeclaration<RadioComponent, never>;
5767
+ static ɵcmp: i0.ɵɵComponentDeclaration<RadioComponent, "ui-radio", never, {
5768
+ "label": {
5769
+ "alias": "label";
5770
+ "required": false;
5771
+ "isSignal": true;
5772
+ };
5773
+ "description": {
5774
+ "alias": "description";
5775
+ "required": false;
5776
+ "isSignal": true;
5777
+ };
5778
+ "ariaLabel": {
5779
+ "alias": "ariaLabel";
5780
+ "required": false;
5781
+ "isSignal": true;
5782
+ };
5783
+ "value": {
5784
+ "alias": "value";
5785
+ "required": false;
5786
+ "isSignal": true;
5787
+ };
5788
+ "name": {
5789
+ "alias": "name";
5790
+ "required": false;
5791
+ "isSignal": true;
5792
+ };
5793
+ "checked": {
5794
+ "alias": "checked";
5795
+ "required": false;
5796
+ "isSignal": true;
5797
+ };
5798
+ "invalid": {
5799
+ "alias": "invalid";
5800
+ "required": false;
5801
+ "isSignal": true;
5802
+ };
5803
+ "describedBy": {
5804
+ "alias": "describedBy";
5805
+ "required": false;
5806
+ "isSignal": true;
5807
+ };
5808
+ "_disabledInput": {
5809
+ "alias": "disabled";
5810
+ "required": false;
5811
+ "isSignal": true;
5812
+ };
5813
+ }, {
5814
+ "selected": "selected";
5815
+ }, never, ["*"], true, never>;
5816
+ }
5817
+ export interface RadioOption {
5818
+ value: string;
5819
+ label: string;
5820
+ description?: string;
5821
+ disabled?: boolean;
5822
+ }
5823
+ /**
5824
+ * Group of native radio buttons inside a `<fieldset>` (+ `<legend>` = `label`), a ControlValueAccessor (string value, `''`
5825
+ * = nothing selected). Arrow keys move and select natively because all radios share one `name`.
5826
+ * Built-in validation: `required` -> "<label> is required."; a non-empty value that is not one of the `options` ->
5827
+ * "Select a valid option." (not checked while `options` is empty). Disabled groups are never invalid.
5828
+ *
5829
+ * Validity API (same on every ui input): Angular `Validator`, signals `invalid` + `errorMessage`, `invalidChange` output,
5830
+ * provides `UiFieldValidity`. Messages show after the group lost focus or while `[showErrors]="true"`; a host `[error]` wins.
5831
+ */
5832
+ export declare class RadioGroupComponent implements ControlValueAccessor, Validator, UiFieldValidity {
5833
+ readonly label: import("@angular/core").InputSignal<string>;
5834
+ readonly options: import("@angular/core").InputSignal<RadioOption[]>;
5835
+ readonly required: import("@angular/core").InputSignal<boolean>;
5836
+ readonly hint: import("@angular/core").InputSignal<string>;
5837
+ readonly error: import("@angular/core").InputSignal<string>;
5838
+ /** Reveal the built-in error messages now (e.g. after a failed Save click), without waiting for blur. */
5839
+ readonly showErrors: import("@angular/core").InputSignal<boolean>;
5840
+ readonly orientation: import("@angular/core").InputSignal<"vertical" | "horizontal">;
5841
+ /** Native `name` shared by the radios; a unique one is generated when omitted. */
5842
+ readonly name: import("@angular/core").InputSignal<string>;
5843
+ protected readonly _disabledInput: import("@angular/core").InputSignal<boolean>;
5844
+ private readonly _cvaDisabled;
5845
+ protected readonly disabled: import("@angular/core").Signal<boolean>;
5846
+ private readonly _generatedName;
5847
+ protected get _name(): string;
5848
+ protected readonly _descId: string;
5849
+ protected readonly _value: import("@angular/core").WritableSignal<string>;
5850
+ private readonly _reveal;
5851
+ private readonly _issue;
5852
+ /** True while the value breaks a built-in rule or the host passed an `[error]`. */
5853
+ readonly invalid: import("@angular/core").Signal<boolean>;
5854
+ /** Message of the first broken built-in rule ('' when valid), shown or not. */
5855
+ readonly errorMessage: import("@angular/core").Signal<string>;
5856
+ /** Emits whenever the field becomes invalid / valid. */
5857
+ readonly invalidChange: import("@angular/core").OutputEmitterRef<boolean>;
5858
+ protected readonly _activeError: import("@angular/core").Signal<string>;
5859
+ private _onValidatorChange;
5860
+ constructor();
5861
+ /** Re-run the form control's validation when a rule input (required, options) changes. */
5862
+ ngOnChanges(): void;
5863
+ validate(control: AbstractControl): ValidationErrors | null;
5864
+ registerOnValidatorChange(fn: () => void): void;
5865
+ private _onChange;
5866
+ private _onTouched;
5867
+ writeValue(val: string): void;
5868
+ registerOnChange(fn: (v: string) => void): void;
5869
+ registerOnTouched(fn: () => void): void;
5870
+ setDisabledState(d: boolean): void;
5871
+ protected onSelect(value: string): void;
5872
+ /** Touched once focus leaves the whole group (moving between its radios does not count). */
5873
+ protected onFocusOut(event: FocusEvent): void;
5874
+ private _check;
5875
+ static ɵfac: i0.ɵɵFactoryDeclaration<RadioGroupComponent, never>;
5876
+ static ɵcmp: i0.ɵɵComponentDeclaration<RadioGroupComponent, "ui-radio-group", never, {
5877
+ "label": {
5878
+ "alias": "label";
5879
+ "required": false;
5880
+ "isSignal": true;
5881
+ };
5882
+ "options": {
5883
+ "alias": "options";
5884
+ "required": false;
5885
+ "isSignal": true;
5886
+ };
5887
+ "required": {
5888
+ "alias": "required";
5889
+ "required": false;
5890
+ "isSignal": true;
5891
+ };
5892
+ "hint": {
5893
+ "alias": "hint";
5894
+ "required": false;
5895
+ "isSignal": true;
5896
+ };
5897
+ "error": {
5898
+ "alias": "error";
5899
+ "required": false;
5900
+ "isSignal": true;
5901
+ };
5902
+ "showErrors": {
5903
+ "alias": "showErrors";
5904
+ "required": false;
5905
+ "isSignal": true;
5906
+ };
5907
+ "orientation": {
5908
+ "alias": "orientation";
5909
+ "required": false;
5910
+ "isSignal": true;
5911
+ };
5912
+ "name": {
5913
+ "alias": "name";
5914
+ "required": false;
5915
+ "isSignal": true;
5916
+ };
5917
+ "_disabledInput": {
5918
+ "alias": "disabled";
5919
+ "required": false;
5920
+ "isSignal": true;
5921
+ };
5922
+ }, {
5923
+ "invalidChange": "invalidChange";
5924
+ }, never, never, true, never>;
5925
+ }
5926
+ /** One row of a `ui-radio-matrix`: `value` is the key in the model, `label` the row header. */
5927
+ export interface RadioMatrixRow {
5928
+ value: string;
5929
+ label: string;
5930
+ disabled?: boolean;
5931
+ }
5932
+ /**
5933
+ * Matrix of native radio buttons: one row per item, one column per choice, exactly one choice per row (e.g. a page-permission
5934
+ * grid: rows = pages, columns = Full Access / Read Only / Hidden). A ControlValueAccessor whose value is a record
5935
+ * `{ [row.value]: column.value }` (`''` / missing = nothing chosen for that row). Arrow keys move inside a row natively because the
5936
+ * radios of a row share one `name`. Every radio is named "<row>: <column>" for screen readers; rows are `<th scope="row">`, columns
5937
+ * `<th scope="col">`.
5938
+ *
5939
+ * Built-in validation: `required` -> every row needs a choice ("Choose an option in every row." / "<label>: choose an option in
5940
+ * every row."); a value that is not one of the `columns` -> "Select a valid option."; a key that is not one of the `rows` is
5941
+ * ignored (and kept untouched in the model). Disabled matrices are never invalid.
5942
+ *
5943
+ * Validity API (same on every ui input): Angular `Validator`, signals `invalid` + `errorMessage`, `invalidChange` output,
5944
+ * provides `UiFieldValidity`. Messages show after the matrix lost focus or while `[showErrors]="true"`; a host `[error]` wins.
5945
+ *
5946
+ * <ui-radio-matrix label="Page permissions" rowHeader="Page" [rows]="pages" [columns]="levels" [(ngModel)]="permissions" />
5947
+ */
5948
+ export declare class RadioMatrixComponent implements ControlValueAccessor, Validator, UiFieldValidity {
5949
+ readonly label: import("@angular/core").InputSignal<string>;
5950
+ /** Text of the top-left header cell (what the rows are, e.g. "Page"). */
5951
+ readonly rowHeader: import("@angular/core").InputSignal<string>;
5952
+ readonly rows: import("@angular/core").InputSignal<RadioMatrixRow[]>;
5953
+ /** The choices, one column each (same shape as `ui-radio-group` options; `description` is not shown). */
5954
+ readonly columns: import("@angular/core").InputSignal<RadioOption[]>;
5955
+ readonly required: import("@angular/core").InputSignal<boolean>;
5956
+ readonly hint: import("@angular/core").InputSignal<string>;
5957
+ readonly error: import("@angular/core").InputSignal<string>;
5958
+ /** Reveal the built-in error messages now (e.g. after a failed Save click), without waiting for blur. */
5959
+ readonly showErrors: import("@angular/core").InputSignal<boolean>;
5960
+ /** Prefix of the native radio `name`s (one name per row); a unique one is generated when omitted. */
5961
+ readonly name: import("@angular/core").InputSignal<string>;
5962
+ protected readonly _disabledInput: import("@angular/core").InputSignal<boolean>;
5963
+ private readonly _cvaDisabled;
5964
+ protected readonly disabled: import("@angular/core").Signal<boolean>;
5965
+ private readonly _generatedName;
5966
+ protected get _name(): string;
5967
+ protected readonly _descId: string;
5968
+ protected readonly _value: import("@angular/core").WritableSignal<Record<string, string>>;
5969
+ private readonly _reveal;
5970
+ private readonly _issue;
5971
+ /** True while the value breaks a built-in rule or the host passed an `[error]`. */
5972
+ readonly invalid: import("@angular/core").Signal<boolean>;
5973
+ /** Message of the first broken built-in rule ('' when valid), shown or not. */
5974
+ readonly errorMessage: import("@angular/core").Signal<string>;
5975
+ /** Emits whenever the field becomes invalid / valid. */
5976
+ readonly invalidChange: import("@angular/core").OutputEmitterRef<boolean>;
5977
+ protected readonly _activeError: import("@angular/core").Signal<string>;
5978
+ private _onValidatorChange;
5979
+ constructor();
5980
+ /** Re-run the form control's validation when a rule input (required, rows, columns) changes. */
5981
+ ngOnChanges(): void;
5982
+ validate(control: AbstractControl): ValidationErrors | null;
5983
+ registerOnValidatorChange(fn: () => void): void;
5984
+ private _onChange;
5985
+ private _onTouched;
5986
+ writeValue(val: Record<string, string> | null): void;
5987
+ registerOnChange(fn: (v: Record<string, string>) => void): void;
5988
+ registerOnTouched(fn: () => void): void;
5989
+ setDisabledState(d: boolean): void;
5990
+ protected onSelect(row: string, column: string): void;
5991
+ /** True when a required matrix has no valid choice in this row (shown on the row header and the dots). */
5992
+ protected _rowInvalid(row: RadioMatrixRow): boolean;
5993
+ /** Touched once focus leaves the whole matrix (moving between its radios does not count). */
5994
+ protected onFocusOut(event: FocusEvent): void;
5995
+ private _toRecord;
5996
+ private _check;
5997
+ static ɵfac: i0.ɵɵFactoryDeclaration<RadioMatrixComponent, never>;
5998
+ static ɵcmp: i0.ɵɵComponentDeclaration<RadioMatrixComponent, "ui-radio-matrix", never, {
5999
+ "label": {
6000
+ "alias": "label";
6001
+ "required": false;
6002
+ "isSignal": true;
6003
+ };
6004
+ "rowHeader": {
6005
+ "alias": "rowHeader";
6006
+ "required": false;
6007
+ "isSignal": true;
6008
+ };
6009
+ "rows": {
6010
+ "alias": "rows";
6011
+ "required": false;
6012
+ "isSignal": true;
6013
+ };
6014
+ "columns": {
6015
+ "alias": "columns";
6016
+ "required": false;
6017
+ "isSignal": true;
6018
+ };
6019
+ "required": {
6020
+ "alias": "required";
6021
+ "required": false;
6022
+ "isSignal": true;
6023
+ };
6024
+ "hint": {
6025
+ "alias": "hint";
6026
+ "required": false;
6027
+ "isSignal": true;
6028
+ };
6029
+ "error": {
6030
+ "alias": "error";
6031
+ "required": false;
6032
+ "isSignal": true;
6033
+ };
6034
+ "showErrors": {
6035
+ "alias": "showErrors";
6036
+ "required": false;
6037
+ "isSignal": true;
6038
+ };
6039
+ "name": {
6040
+ "alias": "name";
6041
+ "required": false;
6042
+ "isSignal": true;
6043
+ };
6044
+ "_disabledInput": {
6045
+ "alias": "disabled";
6046
+ "required": false;
6047
+ "isSignal": true;
6048
+ };
6049
+ }, {
6050
+ "invalidChange": "invalidChange";
6051
+ }, never, never, true, never>;
6052
+ }
6053
+ /**
6054
+ * Card for detail pages: an optional header and a body, both filled by the page that uses it.
6055
+ *
6056
+ * Header (all optional - set `[showHeader]="false"` and the card is just the body):
6057
+ * - `title` / `subtitle`: the bold uppercase title and the grey line under it.
6058
+ * - `titleId`: an id for the title text, which also names the card for assistive tech (aria-labelledby).
6059
+ * - `<div card-header-leading>`: something before the title block, such as a logo or an icon.
6060
+ * - `<ng-container card-header>`: your own header content, shown under the title (or instead of it when no title is set).
6061
+ * - `<ng-container card-header-action>`: buttons or links on the right side of the header.
6062
+ * - `showEdit` + `editLabel` + `(editClick)`: the built-in Edit button.
6063
+ * - `collapsible` (default true): a chevron toggle and a clickable header; `[(expanded)]` is two-way.
6064
+ * Without a header, or with `collapsible` false, the body is always open.
6065
+ *
6066
+ * The title is always shown in capitals; the subtitle keeps the case you give it. The body is the default content slot. A collapsed body is removed from the tab order and from assistive tech.
6067
+ *
6068
+ * <ui-detail-card title="COMMUNICATIONS" subtitle="All calls, texts, and emails"> ...body... </ui-detail-card>
6069
+ * <ui-detail-card title="CONTACT INFO" [showEdit]="true" (editClick)="openEdit()"> ... </ui-detail-card>
6070
+ * <ui-detail-card [showHeader]="false"> ...body only... </ui-detail-card>
6071
+ * <ui-detail-card [collapsible]="false">
6072
+ * <div card-header>Any markup</div>
6073
+ * <ui-button card-header-action size="xs" variant="secondary">Add</ui-button>
6074
+ * ...body...
6075
+ * </ui-detail-card>
6076
+ */
6077
+ export declare class DetailCardComponent {
6078
+ /** Bold uppercase title. Empty = no title text. */
6079
+ readonly title: import("@angular/core").InputSignal<string>;
6080
+ /** 1-6 makes the title a real heading for screen readers (role=heading, aria-level); null keeps it plain text. */
6081
+ readonly headingLevel: import("@angular/core").InputSignal<1 | 2 | 3 | 4 | 5 | 6 | null>;
6082
+ /** Optional id for the title text; the card is then labelled by it. Without it the title is the card's aria-label. */
6083
+ readonly titleId: import("@angular/core").InputSignal<string>;
6084
+ /** Grey line under the title. */
6085
+ readonly subtitle: import("@angular/core").InputSignal<string>;
6086
+ /** false = no header at all (no title, edit button, toggle or divider): the card is only the body, always open. */
6087
+ readonly showHeader: import("@angular/core").InputSignal<boolean>;
6088
+ /** Chevron toggle + clickable header. false = the body is always open. */
6089
+ readonly collapsible: import("@angular/core").InputSignal<boolean>;
6090
+ /** Two-way: whether the body is open. */
6091
+ readonly expanded: import("@angular/core").ModelSignal<boolean>;
6092
+ /** Show the built-in Edit button in the header. */
6093
+ readonly showEdit: import("@angular/core").InputSignal<boolean>;
6094
+ readonly editLabel: import("@angular/core").InputSignal<string>;
6095
+ readonly editClick: import("@angular/core").OutputEmitterRef<void>;
6096
+ /** The body is open unless the card has a header that is collapsible and was collapsed. */
6097
+ isOpen(): boolean;
6098
+ toggle(): void;
6099
+ /** A click on the header toggles, except on a control inside it (Edit, your own header actions, links, inputs). */
6100
+ onHeaderClick(event: Event): void;
6101
+ static ɵfac: i0.ɵɵFactoryDeclaration<DetailCardComponent, never>;
6102
+ static ɵcmp: i0.ɵɵComponentDeclaration<DetailCardComponent, "ui-detail-card", never, {
6103
+ "title": {
6104
+ "alias": "title";
6105
+ "required": false;
6106
+ "isSignal": true;
6107
+ };
6108
+ "headingLevel": {
6109
+ "alias": "headingLevel";
6110
+ "required": false;
6111
+ "isSignal": true;
6112
+ };
6113
+ "titleId": {
6114
+ "alias": "titleId";
6115
+ "required": false;
6116
+ "isSignal": true;
6117
+ };
6118
+ "subtitle": {
6119
+ "alias": "subtitle";
6120
+ "required": false;
6121
+ "isSignal": true;
6122
+ };
6123
+ "showHeader": {
6124
+ "alias": "showHeader";
6125
+ "required": false;
6126
+ "isSignal": true;
6127
+ };
6128
+ "collapsible": {
6129
+ "alias": "collapsible";
6130
+ "required": false;
6131
+ "isSignal": true;
6132
+ };
6133
+ "expanded": {
6134
+ "alias": "expanded";
6135
+ "required": false;
6136
+ "isSignal": true;
6137
+ };
6138
+ "showEdit": {
6139
+ "alias": "showEdit";
6140
+ "required": false;
6141
+ "isSignal": true;
6142
+ };
6143
+ "editLabel": {
6144
+ "alias": "editLabel";
6145
+ "required": false;
6146
+ "isSignal": true;
6147
+ };
6148
+ }, {
6149
+ "expanded": "expandedChange";
6150
+ "editClick": "editClick";
6151
+ }, never, ["[card-header-leading]", "[card-header]", "[card-header-action]", "*"], true, never>;
6152
+ }
6153
+ export type DividerSpace = 'none' | 'sm' | 'md' | 'lg';
6154
+ /**
6155
+ * Horizontal divider line (an `<hr>`) with the app's standard colour and optional space above / below.
6156
+ * It is a real separator for assistive tech by default; set `decorative` when it only adds visual rhythm and the
6157
+ * content around it already reads as separate (the line is then hidden from screen readers).
6158
+ *
6159
+ * <section class="kpi-grid"> ... </section>
6160
+ * <ui-divider /> // line with 16px below
6161
+ * <ui-divider spaceAbove="md" spaceBelow="lg" />
6162
+ * <ui-divider [decorative]="true" />
6163
+ */
6164
+ export declare class DividerComponent {
6165
+ /** Space above the line: none (0), sm (8px), md (16px), lg (24px). */
6166
+ readonly spaceAbove: import("@angular/core").InputSignal<DividerSpace>;
6167
+ /** Space below the line: none (0), sm (8px), md (16px), lg (24px). */
6168
+ readonly spaceBelow: import("@angular/core").InputSignal<DividerSpace>;
6169
+ /** true = purely visual: hidden from assistive tech. */
6170
+ readonly decorative: import("@angular/core").InputSignal<boolean>;
6171
+ protected readonly above: import("@angular/core").Signal<number>;
6172
+ protected readonly below: import("@angular/core").Signal<number>;
6173
+ static ɵfac: i0.ɵɵFactoryDeclaration<DividerComponent, never>;
6174
+ static ɵcmp: i0.ɵɵComponentDeclaration<DividerComponent, "ui-divider", never, {
6175
+ "spaceAbove": {
6176
+ "alias": "spaceAbove";
6177
+ "required": false;
6178
+ "isSignal": true;
6179
+ };
6180
+ "spaceBelow": {
6181
+ "alias": "spaceBelow";
6182
+ "required": false;
6183
+ "isSignal": true;
6184
+ };
6185
+ "decorative": {
6186
+ "alias": "decorative";
6187
+ "required": false;
6188
+ "isSignal": true;
6189
+ };
6190
+ }, {}, never, never, true, never>;
6191
+ }
5442
6192
  export type { SendDocumentsPayload, SendEmailPayload, SendTextPayload };