@forgeroute/ui 0.3.13 → 0.4.1

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.
@@ -887,6 +887,11 @@ export declare function formatTime(value: string | null | undefined): string;
887
887
  export interface SelectOption<V extends string | number = string> {
888
888
  value: V;
889
889
  label: string;
890
+ /**
891
+ * Optional longer explanation of this choice. The select shows the SELECTED option's description under the field (linked with
892
+ * `aria-describedby`) and sets it as the option's `title` tooltip where the browser shows one. Options without it are unchanged.
893
+ */
894
+ description?: string;
890
895
  }
891
896
  export declare class SelectComponent implements ControlValueAccessor, Validator, UiFieldValidity {
892
897
  readonly label: import("@angular/core").InputSignal<string>;
@@ -901,13 +906,17 @@ export declare class SelectComponent implements ControlValueAccessor, Validator,
901
906
  readonly error: import("@angular/core").InputSignal<string>;
902
907
  /** Reveal the built-in error messages now (e.g. after a failed Save click), without waiting for blur. */
903
908
  readonly showErrors: import("@angular/core").InputSignal<boolean>;
904
- readonly size: import("@angular/core").InputSignal<"default" | "sm">;
909
+ readonly size: import("@angular/core").InputSignal<"sm" | "default">;
905
910
  readonly _disabledInput: import("@angular/core").InputSignal<boolean>;
906
911
  private readonly _cvaDisabled;
907
912
  protected readonly disabled: import("@angular/core").Signal<boolean>;
908
913
  protected readonly _value: import("@angular/core").WritableSignal<string>;
909
914
  /** Index of the first option matching the written / chosen value, or -1 (so only ONE option is selected even with duplicate keys). */
910
915
  protected readonly _selectedIndex: import("@angular/core").Signal<number>;
916
+ /** The selected option's `description` ('' when none is selected or it has none); hidden while an error shows. */
917
+ protected readonly _selectedDescription: import("@angular/core").Signal<string>;
918
+ /** ids of the texts that describe the select: the error / hint, then the selected option's description. */
919
+ protected readonly _describedBy: import("@angular/core").Signal<string>;
911
920
  private readonly _reveal;
912
921
  private readonly _issue;
913
922
  /** True while the value breaks a built-in rule or the host passed an `[error]`. */
@@ -1121,6 +1130,12 @@ export declare class DataTableComponent<T extends Record<string, any>> implement
1121
1130
  readonly pageSize: import("@angular/core").InputSignal<number>;
1122
1131
  readonly tableLabel: import("@angular/core").InputSignal<string>;
1123
1132
  readonly emptyMessage: import("@angular/core").InputSignal<string>;
1133
+ /**
1134
+ * Text of the retry button in the failed-load state (desktop table and phone cards). Plain text.
1135
+ * Empty / blank keeps the error state's own default ("Try again").
1136
+ */
1137
+ readonly retryLabel: import("@angular/core").InputSignal<string>;
1138
+ protected readonly _retryLabel: Signal<string>;
1124
1139
  readonly lockedColumn: import("@angular/core").InputSignal<string>;
1125
1140
  readonly savedViews: import("@angular/core").InputSignal<SavedView[]>;
1126
1141
  /**
@@ -1131,6 +1146,14 @@ export declare class DataTableComponent<T extends Record<string, any>> implement
1131
1146
  readonly page: import("@angular/core").InputSignal<string>;
1132
1147
  /** Show column config + saved views toolbar. Defaults true. Set false to hide both. */
1133
1148
  readonly showToolbar: import("@angular/core").InputSignal<boolean>;
1149
+ /**
1150
+ * Show the search box above the table. Defaults true. Set false for small fixed tables where searching is meaningless
1151
+ * (a handful of summary rows). Quick-filter tabs and the toolbar are unaffected; when the search box, the tabs and the
1152
+ * toolbar are all off, the header row above the table is not rendered at all.
1153
+ */
1154
+ readonly showSearch: import("@angular/core").InputSignal<boolean>;
1155
+ /** False when the header row would be empty (no search box, no toolbar, no quick-filter tabs). */
1156
+ protected readonly _showHeader: Signal<boolean>;
1134
1157
  /** Optional endpoint that returns Record<string,number> counts per quick-filter value. */
1135
1158
  readonly countsEndpoint: import("@angular/core").InputSignal<string>;
1136
1159
  /**
@@ -1447,6 +1470,13 @@ export declare class DataTableComponent<T extends Record<string, any>> implement
1447
1470
  activeValues: string[];
1448
1471
  };
1449
1472
  }[]>;
1473
+ /**
1474
+ * The sort buttons / icons and the column-filter icons only show while there is something to sort or filter: not after a failed
1475
+ * load, and not when the table is empty because nothing exists or only a search / quick tab matched nothing (clear the search to
1476
+ * get back). Once the user has used a column header control (a column filter or a sort is active) the controls stay, even with
1477
+ * zero rows, so they can change or clear it. Headers are plain labels otherwise.
1478
+ */
1479
+ protected readonly _showColumnControls: Signal<boolean>;
1450
1480
  protected readonly _hasPhoneControls: Signal<boolean>;
1451
1481
  /** Phone sort select → sets the sort directly (same state, page reset and load as the header's onSort). */
1452
1482
  protected onPhoneSort(value: string): void;
@@ -1561,6 +1591,11 @@ export declare class DataTableComponent<T extends Record<string, any>> implement
1561
1591
  "required": false;
1562
1592
  "isSignal": true;
1563
1593
  };
1594
+ "retryLabel": {
1595
+ "alias": "retryLabel";
1596
+ "required": false;
1597
+ "isSignal": true;
1598
+ };
1564
1599
  "lockedColumn": {
1565
1600
  "alias": "lockedColumn";
1566
1601
  "required": false;
@@ -1581,6 +1616,11 @@ export declare class DataTableComponent<T extends Record<string, any>> implement
1581
1616
  "required": false;
1582
1617
  "isSignal": true;
1583
1618
  };
1619
+ "showSearch": {
1620
+ "alias": "showSearch";
1621
+ "required": false;
1622
+ "isSignal": true;
1623
+ };
1584
1624
  "countsEndpoint": {
1585
1625
  "alias": "countsEndpoint";
1586
1626
  "required": false;
@@ -2090,7 +2130,7 @@ export declare class AudioPlayerComponent {
2090
2130
  /** Accessible name of the player. */
2091
2131
  readonly ariaLabel: import("@angular/core").InputSignal<string>;
2092
2132
  /** How much to load before play: 'metadata' (default), 'auto' or 'none'. */
2093
- readonly preload: import("@angular/core").InputSignal<"none" | "auto" | "metadata">;
2133
+ readonly preload: import("@angular/core").InputSignal<"none" | "metadata" | "auto">;
2094
2134
  /** Fires when the browser can't load or decode the source. */
2095
2135
  readonly playbackError: import("@angular/core").OutputEmitterRef<void>;
2096
2136
  protected readonly failed: import("@angular/core").WritableSignal<boolean>;
@@ -2117,11 +2157,27 @@ export declare class AudioPlayerComponent {
2117
2157
  "playbackError": "playbackError";
2118
2158
  }, never, never, true, never>;
2119
2159
  }
2160
+ /**
2161
+ * Shimmering placeholder for content that is loading.
2162
+ *
2163
+ * By default it is purely decorative (hidden from assistive tech), like before. Give ONE skeleton - or the wrapper of a group of them - an
2164
+ * `ariaLabel` to announce the loading state: the host then becomes a polite live region (`role="status"`, `aria-live="polite"`,
2165
+ * `aria-busy="true"`, named by the label) and is no longer hidden. Remove the skeleton (or the label) when the content has loaded.
2166
+ *
2167
+ * <ui-skeleton [height]="44" ariaLabel="Loading submissions" />
2168
+ * <div role="status" aria-label="Loading report"> <ui-skeleton /> <ui-skeleton /> </div> <!-- decorative skeletons inside a labelled wrapper -->
2169
+ *
2170
+ * Do not label every skeleton of a group: each labelled skeleton is its own live region and would be announced separately.
2171
+ */
2120
2172
  export declare class SkeletonComponent {
2121
2173
  readonly height: import("@angular/core").InputSignal<number>;
2122
2174
  readonly width: import("@angular/core").InputSignal<string>;
2123
2175
  readonly radius: import("@angular/core").InputSignal<number>;
2124
2176
  readonly mb: import("@angular/core").InputSignal<number>;
2177
+ /** Accessible name that turns the skeleton into a polite status region ("Loading ..."). Empty (default) = decorative, hidden from assistive tech. */
2178
+ readonly ariaLabel: import("@angular/core").InputSignal<string>;
2179
+ /** The trimmed label ('' = none). */
2180
+ label(): string;
2125
2181
  static ɵfac: i0.ɵɵFactoryDeclaration<SkeletonComponent, never>;
2126
2182
  static ɵcmp: i0.ɵɵComponentDeclaration<SkeletonComponent, "ui-skeleton", never, {
2127
2183
  "height": {
@@ -2144,6 +2200,11 @@ export declare class SkeletonComponent {
2144
2200
  "required": false;
2145
2201
  "isSignal": true;
2146
2202
  };
2203
+ "ariaLabel": {
2204
+ "alias": "ariaLabel";
2205
+ "required": false;
2206
+ "isSignal": true;
2207
+ };
2147
2208
  }, {}, never, never, true, never>;
2148
2209
  }
2149
2210
  /**
@@ -2950,7 +3011,7 @@ export declare class PhoneNumberPickerComponent {
2950
3011
  protected readonly modeCtl: FormControl<string>;
2951
3012
  protected readonly zipCtl: FormControl<string>;
2952
3013
  protected readonly areaCtl: FormControl<string>;
2953
- protected readonly step: import("@angular/core").WritableSignal<1 | 2 | 3>;
3014
+ protected readonly step: import("@angular/core").WritableSignal<2 | 1 | 3>;
2954
3015
  protected readonly mode: import("@angular/core").WritableSignal<PhoneNumberSearchMode>;
2955
3016
  private readonly _zip;
2956
3017
  private readonly _area;
@@ -3081,8 +3142,8 @@ export declare class ButtonComponent {
3081
3142
  protected readonly _rel: import("@angular/core").Signal<string | null>;
3082
3143
  readonly color: import("@angular/core").InputSignal<string | undefined>;
3083
3144
  readonly active: import("@angular/core").InputSignal<boolean>;
3084
- readonly size: import("@angular/core").InputSignal<"sm" | "md" | "xs" | "lg">;
3085
- readonly type: import("@angular/core").InputSignal<"reset" | "submit" | "button">;
3145
+ readonly size: import("@angular/core").InputSignal<"sm" | "md" | "lg" | "xs">;
3146
+ readonly type: import("@angular/core").InputSignal<"button" | "submit" | "reset">;
3086
3147
  readonly disabled: import("@angular/core").InputSignal<boolean>;
3087
3148
  readonly loading: import("@angular/core").InputSignal<boolean>;
3088
3149
  readonly fullWidth: import("@angular/core").InputSignal<boolean>;
@@ -6013,7 +6074,7 @@ export declare class TextInputComponent implements ControlValueAccessor, Validat
6013
6074
  * `search`, `text`, `none`). Empty (default) = the browser's default for the field, except `type="tel"`, which keeps `tel`.
6014
6075
  * It only picks the keyboard; it does not restrict what can be typed or pasted.
6015
6076
  */
6016
- readonly inputmode: import("@angular/core").InputSignal<"" | "none" | "text" | "search" | "email" | "tel" | "url" | "decimal" | "numeric">;
6077
+ readonly inputmode: import("@angular/core").InputSignal<"" | "none" | "text" | "email" | "tel" | "search" | "url" | "decimal" | "numeric">;
6017
6078
  readonly readonly: import("@angular/core").InputSignal<boolean>;
6018
6079
  readonly hint: import("@angular/core").InputSignal<string>;
6019
6080
  readonly error: import("@angular/core").InputSignal<string>;
@@ -6294,6 +6355,46 @@ export declare class TextareaInputComponent implements ControlValueAccessor, Val
6294
6355
  "invalidChange": "invalidChange";
6295
6356
  }, never, never, true, never>;
6296
6357
  }
6358
+ export type TextSize = 'sm' | 'md' | 'lg';
6359
+ export type TextTone = 'default' | 'muted';
6360
+ /**
6361
+ * Plain text that keeps its line breaks: a note, a message, an address, a pasted block. It is page content, not a form control —
6362
+ * no tab stop, no resize handle, selectable and copyable, and read normally by screen readers (including browse mode).
6363
+ *
6364
+ * <ui-text [text]="note.content" />
6365
+ * <ui-text [text]="request.message" size="sm" tone="muted" />
6366
+ *
6367
+ * Every line break and run of spaces in `text` is shown as written; long unbroken words and links wrap instead of
6368
+ * stretching the layout. The text is never interpreted as HTML. Pass the text through `[text]` (not as projected content),
6369
+ * so the template's own indentation can never leak into it. An empty or missing text renders nothing.
6370
+ *
6371
+ * Inputs: `text`, `size` (sm 0.8125rem | md 0.875rem | lg 1rem, default md), `tone` (default slate | muted grey).
6372
+ */
6373
+ export declare class TextComponent {
6374
+ /** The text to show. Line breaks are kept; it is never parsed as HTML. */
6375
+ readonly text: import("@angular/core").InputSignal<string | null | undefined>;
6376
+ readonly size: import("@angular/core").InputSignal<TextSize>;
6377
+ readonly tone: import("@angular/core").InputSignal<TextTone>;
6378
+ protected readonly fontSize: import("@angular/core").Signal<string>;
6379
+ static ɵfac: i0.ɵɵFactoryDeclaration<TextComponent, never>;
6380
+ static ɵcmp: i0.ɵɵComponentDeclaration<TextComponent, "ui-text", never, {
6381
+ "text": {
6382
+ "alias": "text";
6383
+ "required": false;
6384
+ "isSignal": true;
6385
+ };
6386
+ "size": {
6387
+ "alias": "size";
6388
+ "required": false;
6389
+ "isSignal": true;
6390
+ };
6391
+ "tone": {
6392
+ "alias": "tone";
6393
+ "required": false;
6394
+ "isSignal": true;
6395
+ };
6396
+ }, {}, never, never, true, never>;
6397
+ }
6297
6398
  /** Why a chosen file was refused. */
6298
6399
  /** 'type' = not an accepted type, 'size' = over `maxSize`, 'empty' = a 0-byte file (`rejectEmpty`), 'small' = under `minSize`. */
6299
6400
  export type FileRejectReason = 'type' | 'size' | 'empty' | 'small';
@@ -6986,6 +7087,8 @@ export interface DropdownItem {
6986
7087
  label: string;
6987
7088
  value: string;
6988
7089
  count?: number;
7090
+ /** Greyed-out, not selectable and skipped by keyboard navigation. */
7091
+ disabled?: boolean;
6989
7092
  }
6990
7093
  export declare class DropdownComponent {
6991
7094
  readonly label: import("@angular/core").InputSignal<string>;
@@ -6996,16 +7099,54 @@ export declare class DropdownComponent {
6996
7099
  readonly activeValue: import("@angular/core").InputSignal<string>;
6997
7100
  readonly variant: import("@angular/core").InputSignal<"badge" | "button">;
6998
7101
  readonly menuWidth: import("@angular/core").InputSignal<string>;
7102
+ /**
7103
+ * Accessible name. Set it when the trigger has no meaningful visible text. Applied as `aria-label` on the
7104
+ * trigger and on the menu; when empty (default) no `aria-label` is rendered, the trigger is named by its
7105
+ * visible label and the menu by `aria-labelledby` pointing at the trigger. Surrounding whitespace is trimmed.
7106
+ */
7107
+ readonly ariaLabel: import("@angular/core").InputSignal<string>;
6999
7108
  readonly itemClick: import("@angular/core").OutputEmitterRef<DropdownItem>;
7000
7109
  protected readonly open: import("@angular/core").WritableSignal<boolean>;
7001
7110
  protected readonly loading: import("@angular/core").WritableSignal<boolean>;
7002
7111
  private readonly _loaded;
7003
7112
  private readonly _id;
7113
+ private readonly _host;
7114
+ private readonly _cdr;
7115
+ private _pendingFocus;
7116
+ private _typeahead;
7117
+ private _typeaheadTimer;
7118
+ private _destroyed;
7119
+ protected readonly triggerId: string;
7120
+ protected readonly menuId: string;
7121
+ protected readonly _ariaLabel: import("@angular/core").Signal<string | null>;
7004
7122
  protected readonly displayItems: import("@angular/core").Signal<DropdownItem[]>;
7005
7123
  constructor();
7006
7124
  toggle(event: Event): void;
7007
7125
  select(item: DropdownItem): void;
7008
7126
  close(): void;
7127
+ /**
7128
+ * Keyboard contract (WAI-ARIA menu button).
7129
+ * Trigger: Enter / Space toggle (opening focuses the first item), ArrowDown opens + first item,
7130
+ * ArrowUp opens + last item, ArrowDown/ArrowUp while open move into the menu, Tab closes (focus moves on naturally).
7131
+ */
7132
+ protected onTriggerKeydown(event: KeyboardEvent): void;
7133
+ /** Firefox fires the button click on Space keyup even when keydown was prevented. */
7134
+ protected onTriggerKeyup(event: KeyboardEvent): void;
7135
+ /**
7136
+ * Menu keys (focus on an item): ArrowDown / ArrowUp move with wrap, Home / End jump to first / last,
7137
+ * Enter / Space activate the focused item (native button click), Tab / Shift+Tab close and let focus move on from the trigger,
7138
+ * printable characters jump to the next item whose label starts with the typed text (typeahead, reset after 500 ms).
7139
+ * Disabled items are skipped. Other keys are ignored. Escape is handled on the host.
7140
+ */
7141
+ protected onMenuKeydown(event: KeyboardEvent): void;
7142
+ protected onEscape(event: Event): void;
7143
+ private _setOpen;
7144
+ private _openAndFocus;
7145
+ /** Renders the menu synchronously, then focuses the pending first / last enabled item. */
7146
+ private _focusPending;
7147
+ private _typeaheadFocus;
7148
+ private _enabledItems;
7149
+ private _focusTrigger;
7009
7150
  static ɵfac: i0.ɵɵFactoryDeclaration<DropdownComponent, never>;
7010
7151
  static ɵcmp: i0.ɵɵComponentDeclaration<DropdownComponent, "ui-dropdown", never, {
7011
7152
  "label": {
@@ -7043,6 +7184,11 @@ export declare class DropdownComponent {
7043
7184
  "required": false;
7044
7185
  "isSignal": true;
7045
7186
  };
7187
+ "ariaLabel": {
7188
+ "alias": "ariaLabel";
7189
+ "required": false;
7190
+ "isSignal": true;
7191
+ };
7046
7192
  }, {
7047
7193
  "itemClick": "itemClick";
7048
7194
  }, never, never, true, never>;
@@ -7065,7 +7211,7 @@ export declare class FormSectionComponent {
7065
7211
  }, {}, never, ["*"], true, never>;
7066
7212
  }
7067
7213
  export declare class FormRowComponent {
7068
- readonly cols: import("@angular/core").InputSignal<1 | 2 | 3>;
7214
+ readonly cols: import("@angular/core").InputSignal<2 | 1 | 3>;
7069
7215
  static ɵfac: i0.ɵɵFactoryDeclaration<FormRowComponent, never>;
7070
7216
  static ɵcmp: i0.ɵɵComponentDeclaration<FormRowComponent, "ui-form-row", never, {
7071
7217
  "cols": {
@@ -7230,20 +7376,31 @@ export declare class ListItemComponent {
7230
7376
  export declare function provideForgerouteToast(options?: {
7231
7377
  dismissible?: boolean;
7232
7378
  }): EnvironmentProviders;
7233
- /** Payload of `(reorder)`. `order[newIndex] = oldIndex`; apply it with `reorderItems(items, order)`. */
7234
- export interface ListReorderEvent {
7379
+ /** Payload of `(reorder)`. Apply it with `reorderItems(items, order)` or take the ready-made `items`. */
7380
+ export interface ListReorderEvent<T = unknown> {
7381
+ /** The row that was moved. */
7382
+ item: T;
7235
7383
  /** Index the moved row had before the move. */
7236
7384
  from: number;
7237
7385
  /** Index the moved row has after the move. */
7238
7386
  to: number;
7239
7387
  /** The new index order of the whole list: `order[newIndex] = oldIndex`. */
7240
7388
  order: number[];
7389
+ /** The new full order of the items (a new array; the input array is not changed). */
7390
+ items: T[];
7241
7391
  }
7242
- /** Context handed to the row template: `<ng-template let-item let-i="index" let-n="count">`. */
7392
+ /**
7393
+ * Context handed to the row template:
7394
+ * `<ng-template let-item let-i="index" let-n="count" let-first="first" let-last="last" let-dragging="dragging">`.
7395
+ */
7243
7396
  export interface ListRowContext<T = unknown> {
7244
7397
  $implicit: T;
7245
7398
  index: number;
7246
7399
  count: number;
7400
+ first: boolean;
7401
+ last: boolean;
7402
+ /** True while this row is being dragged. */
7403
+ dragging: boolean;
7247
7404
  }
7248
7405
  /** Returns a new array in the order given by a `ListReorderEvent.order` (the input array is not changed). */
7249
7406
  export declare function reorderItems<T>(items: readonly T[], order: readonly number[]): T[];
@@ -7252,22 +7409,26 @@ interface Row {
7252
7409
  key: unknown;
7253
7410
  index: number;
7254
7411
  label: string;
7255
- upLabel: string;
7256
- downLabel: string;
7412
+ earlierLabel: string;
7413
+ laterLabel: string;
7257
7414
  first: boolean;
7258
7415
  last: boolean;
7416
+ dragging: boolean;
7259
7417
  ctx: ListRowContext;
7260
7418
  }
7261
7419
  /**
7262
7420
  * Semantic list container. Renders a real `<ul>` (default) or `<ol>` (`[ordered]="true"`) whose children are real `<li>`
7263
- * elements, one per entry of `items`. The row template (the single `<ng-template>` child) renders what is inside each
7264
- * `<li>`, normally a `<ui-list-item>`. Screen readers announce "list, N items" and "item i of N" natively.
7421
+ * elements, one per entry of `items`. The single `<ng-template>` child renders what is inside each `<li>`, normally a
7422
+ * `<ui-list-item>`. Screen readers announce "list, N items" and "item i of N" natively. `layout="grid"` lays the same
7423
+ * `<ul>` out as a wrapping CSS grid (columns of at least `gridMin` px).
7265
7424
  *
7266
- * Optional reordering (`[reorderable]="true"`, off by default): Move up / Move down icon buttons at the row end,
7267
- * Alt+ArrowUp / Alt+ArrowDown from any focused element in the row, a polite live region and a `(reorder)` output.
7268
- * The host owns the data: the list never changes `items`; apply the event (`reorderItems`) and pass the new array.
7425
+ * Optional reordering (`[reorderable]="true"`, off by default): Move buttons, Alt+ArrowUp / Alt+ArrowDown from any
7426
+ * focused element in a row, drag and drop plus Shift+Arrow / Home / End on a focused row (default in the grid layout, see
7427
+ * `dragDrop`), a polite live region, and `(reorder)` / `(itemsChange)` outputs.
7428
+ * The host owns the data: the list never changes `items`. Either bind `[(items)]` (the list emits the new array) or
7429
+ * apply the event yourself (`reorderItems`) and pass the new array.
7269
7430
  *
7270
- * <ui-list ariaLabel="Documents" [items]="docs()" [reorderable]="true" (reorder)="docs.set(reorderItems(docs(), $event.order))">
7431
+ * <ui-list ariaLabel="Documents" [items]="docs()" [reorderable]="true" (reorder)="docs.set($event.items)">
7271
7432
  * <ng-template let-doc let-i="index">
7272
7433
  * <ui-list-item [interactive]="false" [bordered]="true" [title]="doc.title" [details]="[doc.fileName]" />
7273
7434
  * </ng-template>
@@ -7276,43 +7437,96 @@ interface Row {
7276
7437
  export declare class ListComponent<T = unknown> {
7277
7438
  private readonly host;
7278
7439
  private readonly injector;
7279
- /** The entries to render, one `<li>` each. The host owns this array; the list never changes it. */
7440
+ /**
7441
+ * The entries to render, one `<li>` each. The host owns this array; the list never changes it. Two-way binding
7442
+ * (`[(items)]`) works: the list emits `itemsChange` with the new array and the host stores it.
7443
+ */
7280
7444
  readonly items: import("@angular/core").InputSignal<readonly T[]>;
7281
- /** `false` (default) renders a `<ul>`; `true` renders an `<ol>` with native numbering. */
7445
+ /** `false` (default) renders a `<ul>`; `true` renders an `<ol>` with native numbering (no numbers in the grid layout). */
7282
7446
  readonly ordered: import("@angular/core").InputSignal<boolean>;
7283
- /** Shows Move up / Move down controls and enables Alt+ArrowUp / Alt+ArrowDown. Default `false`: no controls, no live region. */
7447
+ /** 'list' = one column; 'grid' = wrapping columns of at least `gridMin` px (still a real `<ul>`). */
7448
+ readonly layout: import("@angular/core").InputSignal<"list" | "grid">;
7449
+ /** Minimum column width in px of the grid layout. */
7450
+ readonly gridMin: import("@angular/core").InputSignal<number>;
7451
+ /**
7452
+ * Space between rows (list) or between rows and columns (grid): none | xs | sm | md | lg | xl (0/4/8/16/24/32px, the scale of
7453
+ * `ui-stack` / `ui-columns`) or any CSS length (`gap="20px"`). Not set, or not a token / length: 0 in a list, 12px in a grid.
7454
+ */
7455
+ readonly gap: import("@angular/core").InputSignal<string | undefined>;
7456
+ /** Turns reordering on. Default `false`: no controls, no live region, no drag, no keys. */
7284
7457
  readonly reorderable: import("@angular/core").InputSignal<boolean>;
7285
- /** Disables all move controls and the keyboard shortcut (the rows stay visible). */
7458
+ /** Disables all moves (buttons, keys, drag and drop); the rows stay visible. */
7286
7459
  readonly disabled: import("@angular/core").InputSignal<boolean>;
7460
+ /**
7461
+ * Move buttons on each row (needs `reorderable`). 'auto' (default) = shown in the list layout, hidden in the grid layout;
7462
+ * `true` / `false` force them.
7463
+ */
7464
+ readonly moveControls: import("@angular/core").InputSignal<boolean | "auto">;
7465
+ /**
7466
+ * Drag and drop plus focusable rows (Shift+Arrow / Home / End). 'auto' (default) = on in the grid layout, off in the list
7467
+ * layout (where the Move buttons are the way); `true` / `false` force it. Needs `reorderable`.
7468
+ */
7469
+ readonly dragDrop: import("@angular/core").InputSignal<boolean | "auto">;
7287
7470
  /** Accessible name of the list (`aria-label`). */
7288
7471
  readonly ariaLabel: import("@angular/core").InputSignal<string | undefined>;
7289
7472
  /** Id of the element naming the list (`aria-labelledby`). */
7290
7473
  readonly ariaLabelledby: import("@angular/core").InputSignal<string | undefined>;
7291
7474
  /**
7292
- * Row label used in "Move <label> up" and the live announcement. Default: the string itself, else the item's
7293
- * `title`, `label` or `name`, else "Item N".
7475
+ * Row label used in the button names, the row's accessible name and the live announcement. Default: the string itself,
7476
+ * else the item's `title`, `label` or `name`, else "Item N".
7294
7477
  */
7295
7478
  readonly itemLabelFn: import("@angular/core").InputSignal<(item: T, index: number) => string>;
7296
7479
  /** Stable identity per row (default: the item object itself) so reordering moves DOM instead of recreating it. */
7297
7480
  readonly trackBy: import("@angular/core").InputSignal<(item: T, index: number) => unknown>;
7298
- /** Fires when the user moves a row. The host applies it and passes the new `items`. */
7299
- readonly reorder: import("@angular/core").OutputEmitterRef<ListReorderEvent>;
7481
+ /**
7482
+ * Start of the up / earlier button name; the row label is appended ("Move earlier Image 3"). Default: "Move <label> up"
7483
+ * in the list layout, "Move earlier <label>" in the grid layout.
7484
+ */
7485
+ readonly moveEarlierLabel: import("@angular/core").InputSignal<string | undefined>;
7486
+ /** Start of the down / later button name ("Move later Image 3"). Default: "Move <label> down" (list), "Move later <label>" (grid). */
7487
+ readonly moveLaterLabel: import("@angular/core").InputSignal<string | undefined>;
7488
+ /** Screen-reader instruction for a focused draggable row (aria-describedby). */
7489
+ readonly helpText: import("@angular/core").InputSignal<string>;
7490
+ /** Announcement after a move; receives the row label, the new position (1-based) and the list size. */
7491
+ readonly moveAnnouncement: import("@angular/core").InputSignal<(label: string, position: number, total: number) => string>;
7492
+ /** Fires with the new array when the user moves a row (`[(items)]`). The list does not change `items` itself. */
7493
+ readonly itemsChange: import("@angular/core").OutputEmitterRef<T[]>;
7494
+ /** Fires when the user moves a row. The host applies it (or uses `[(items)]`) and passes the new `items`. */
7495
+ readonly reorder: import("@angular/core").OutputEmitterRef<ListReorderEvent<T>>;
7300
7496
  protected readonly rowTemplate: import("@angular/core").Signal<TemplateRef<any> | undefined>;
7497
+ protected readonly helpId: string;
7301
7498
  protected readonly announcement: import("@angular/core").WritableSignal<string>;
7302
7499
  protected readonly movedKey: import("@angular/core").WritableSignal<unknown>;
7500
+ protected readonly dragIndex: import("@angular/core").WritableSignal<number | null>;
7501
+ protected readonly overIndex: import("@angular/core").WritableSignal<number | null>;
7303
7502
  private pendingFocus;
7304
7503
  private announceSeq;
7305
7504
  /** Stable disambiguation tokens for repeated keys (duplicates in a primitive list), reused across recomputes. */
7306
7505
  private dupTokens;
7506
+ protected readonly isGrid: import("@angular/core").Signal<boolean>;
7507
+ private readonly canReorder;
7508
+ protected readonly showControls: import("@angular/core").Signal<boolean>;
7509
+ /** Rows are draggable, focusable and move with Shift+arrows. */
7510
+ protected readonly direct: import("@angular/core").Signal<boolean>;
7511
+ /** The `--ul-gap` custom property: the token / length, or the default of the layout when unset or invalid. */
7512
+ protected readonly gapCss: import("@angular/core").Signal<string>;
7307
7513
  protected readonly rows: import("@angular/core").Signal<Row[]>;
7308
- private canReorder;
7309
- /** The `<li>` (direct child of this list) that contains `el`, or null. */
7514
+ /** Index of the `<li>` (direct child of this list) that contains `el`, or -1. */
7310
7515
  private rowIndexOf;
7516
+ /**
7517
+ * Moves the row at `from` to position `to` (clamped) and emits `itemsChange` + `reorder`. No-op (returns false) when
7518
+ * reordering is off or disabled, `from` is out of range, or nothing would change. Does not touch focus.
7519
+ */
7520
+ move(from: number, to: number): boolean;
7311
7521
  protected onKeydown(e: KeyboardEvent): void;
7312
7522
  protected onClick(e: Event): void;
7313
7523
  protected onFocusOut(e: FocusEvent): void;
7314
- /** Emits the reorder, announces it and restores focus to the moved row's control once the host has re-rendered. */
7315
- private move;
7524
+ protected onDragStart(e: DragEvent): void;
7525
+ protected onDragOver(e: DragEvent): void;
7526
+ protected onDrop(e: DragEvent): void;
7527
+ protected onDragEnd(): void;
7528
+ /** Emits the move, announces it and (for key / button moves) restores focus once the host has re-rendered. */
7529
+ private apply;
7316
7530
  /** Identical text is not re-read by screen readers, so a repeat of the current message is cleared first and written after the next render. */
7317
7531
  private announce;
7318
7532
  private restoreFocus;
@@ -7328,6 +7542,21 @@ export declare class ListComponent<T = unknown> {
7328
7542
  "required": false;
7329
7543
  "isSignal": true;
7330
7544
  };
7545
+ "layout": {
7546
+ "alias": "layout";
7547
+ "required": false;
7548
+ "isSignal": true;
7549
+ };
7550
+ "gridMin": {
7551
+ "alias": "gridMin";
7552
+ "required": false;
7553
+ "isSignal": true;
7554
+ };
7555
+ "gap": {
7556
+ "alias": "gap";
7557
+ "required": false;
7558
+ "isSignal": true;
7559
+ };
7331
7560
  "reorderable": {
7332
7561
  "alias": "reorderable";
7333
7562
  "required": false;
@@ -7338,6 +7567,16 @@ export declare class ListComponent<T = unknown> {
7338
7567
  "required": false;
7339
7568
  "isSignal": true;
7340
7569
  };
7570
+ "moveControls": {
7571
+ "alias": "moveControls";
7572
+ "required": false;
7573
+ "isSignal": true;
7574
+ };
7575
+ "dragDrop": {
7576
+ "alias": "dragDrop";
7577
+ "required": false;
7578
+ "isSignal": true;
7579
+ };
7341
7580
  "ariaLabel": {
7342
7581
  "alias": "ariaLabel";
7343
7582
  "required": false;
@@ -7358,7 +7597,28 @@ export declare class ListComponent<T = unknown> {
7358
7597
  "required": false;
7359
7598
  "isSignal": true;
7360
7599
  };
7600
+ "moveEarlierLabel": {
7601
+ "alias": "moveEarlierLabel";
7602
+ "required": false;
7603
+ "isSignal": true;
7604
+ };
7605
+ "moveLaterLabel": {
7606
+ "alias": "moveLaterLabel";
7607
+ "required": false;
7608
+ "isSignal": true;
7609
+ };
7610
+ "helpText": {
7611
+ "alias": "helpText";
7612
+ "required": false;
7613
+ "isSignal": true;
7614
+ };
7615
+ "moveAnnouncement": {
7616
+ "alias": "moveAnnouncement";
7617
+ "required": false;
7618
+ "isSignal": true;
7619
+ };
7361
7620
  }, {
7621
+ "itemsChange": "itemsChange";
7362
7622
  "reorder": "reorder";
7363
7623
  }, ["rowTemplate"], ["[list-empty]"], true, never>;
7364
7624
  }
@@ -7370,6 +7630,12 @@ export declare class ListComponent<T = unknown> {
7370
7630
  * The row has no list role of its own: put `role="list"` on the host container and `role="listitem"` on each `ui-bar-row`
7371
7631
  * (or wrap them in `ui-list`). The label names the inner progressbar (`aria-labelledby`) and `valueText`
7372
7632
  * (default: the count plus the share) is its `aria-valuetext`.
7633
+ *
7634
+ * Out-of-range input: only the BAR is clamped, never the text the user reads. The fill is always 0-100% of the track:
7635
+ * `value` below 0, NaN, -Infinity or not a number (string, null, undefined) draws no fill; `value` above `max`
7636
+ * (including +Infinity) fills 100%; `max` of 0, negative, NaN, +/-Infinity or not a number draws an empty bar. The progressbar's
7637
+ * `aria-valuenow` is clamped to [0, max] and `aria-valuemax` is 0 for an invalid max. The count text keeps the real `value`
7638
+ * (formatted; a non-finite or non-number value reads "0"), and `count` / `share` / `valueText` are shown and announced as given.
7373
7639
  * Layout: `minmax(0, 12rem) 1fr auto`; at 480px and below the label sits above the bar with the count at the end of the label line.
7374
7640
  */
7375
7641
  export declare class BarRowComponent {
@@ -7377,7 +7643,7 @@ export declare class BarRowComponent {
7377
7643
  readonly label: import("@angular/core").InputSignal<string>;
7378
7644
  /** This row's amount. */
7379
7645
  readonly value: import("@angular/core").InputSignal<number>;
7380
- /** The amount that fills the bar (e.g. the largest category's count). 0 / NaN / negative draws an empty bar. */
7646
+ /** The amount that fills the bar (e.g. the largest category's count). 0 / NaN / negative / infinite / not a number draws an empty bar. */
7381
7647
  readonly max: import("@angular/core").InputSignal<number>;
7382
7648
  /** Fixed bar colour. Default blue; never follows completion. */
7383
7649
  readonly variant: import("@angular/core").InputSignal<ProgressBarVariant>;
@@ -7391,6 +7657,10 @@ export declare class BarRowComponent {
7391
7657
  readonly locale: import("@angular/core").InputSignal<string>;
7392
7658
  /** Unique id tying the label to the progressbar. */
7393
7659
  protected readonly labelId: string;
7660
+ /** `value` made safe for the bar: anything that is not a real number becomes 0 (the bar clamps the rest to 0..max). */
7661
+ protected readonly barValue: import("@angular/core").Signal<number>;
7662
+ /** `max` made safe for the bar: only a finite number above 0 counts, everything else is 0 (empty bar). */
7663
+ protected readonly barMax: import("@angular/core").Signal<number>;
7394
7664
  protected readonly countText: import("@angular/core").Signal<string>;
7395
7665
  protected readonly effectiveValueText: import("@angular/core").Signal<string>;
7396
7666
  static ɵfac: i0.ɵɵFactoryDeclaration<BarRowComponent, never>;
@@ -7643,7 +7913,7 @@ export declare class ChipGroupComponent {
7643
7913
  readonly spaceAbove: import("@angular/core").InputSignal<"none" | "sm" | "md">;
7644
7914
  /** Space below the chip group. */
7645
7915
  readonly spaceBelow: import("@angular/core").InputSignal<"none" | "sm" | "md">;
7646
- protected readonly _gap: import("@angular/core").Signal<"6px" | "8px" | "12px">;
7916
+ protected readonly _gap: import("@angular/core").Signal<"6px" | "12px" | "8px">;
7647
7917
  protected readonly _spaceAbove: import("@angular/core").Signal<"0" | "6px" | "12px">;
7648
7918
  protected readonly _spaceBelow: import("@angular/core").Signal<"0" | "6px" | "12px">;
7649
7919
  static ɵfac: i0.ɵɵFactoryDeclaration<ChipGroupComponent, never>;
@@ -7870,16 +8140,27 @@ export type AlertVariant = 'info' | 'success' | 'warning' | 'danger';
7870
8140
  /**
7871
8141
  * Inline status message (info / success / warning / danger) with an optional title,
7872
8142
  * optional dismiss button, and projected body content (text, links, a retry ui-button…).
8143
+ * `quiet` drops the live-region role (no announcement) and `compact` tightens it for list rows — both off by default.
7873
8144
  *
7874
8145
  * <ui-alert variant="warning">No recipients — this campaign will not be sent.</ui-alert>
7875
8146
  * <ui-alert variant="danger" title="Couldn't load recipients">
7876
8147
  * {{ error }} <ui-button variant="ghost" size="sm" (click)="retry()">Retry</ui-button>
7877
8148
  * </ui-alert>
8149
+ * <ui-alert variant="danger" [quiet]="true" [compact]="true">Row 4: Email is not valid.</ui-alert>
7878
8150
  */
7879
8151
  export declare class AlertComponent {
7880
8152
  readonly variant: import("@angular/core").InputSignal<AlertVariant>;
7881
8153
  readonly title: import("@angular/core").InputSignal<string>;
7882
8154
  readonly dismissible: import("@angular/core").InputSignal<boolean>;
8155
+ /**
8156
+ * Quiet: no live-region role, so a screen reader does NOT announce it when it appears. Use it for an alert that is already on
8157
+ * the page when the user gets there, or for each item of a long list of alerts (e.g. one per failed import row — 500 danger
8158
+ * alerts would be 500 announcements). The default (false) keeps `role="alert"` for danger and `role="status"` for the rest.
8159
+ * The text stays normal page content, so it is still read in browse mode.
8160
+ */
8161
+ readonly quiet: import("@angular/core").InputSignal<boolean>;
8162
+ /** Tighter padding and a slightly smaller font, for an alert that is one row of a list. */
8163
+ readonly compact: import("@angular/core").InputSignal<boolean>;
7883
8164
  readonly dismissed: import("@angular/core").OutputEmitterRef<void>;
7884
8165
  static ɵfac: i0.ɵɵFactoryDeclaration<AlertComponent, never>;
7885
8166
  static ɵcmp: i0.ɵɵComponentDeclaration<AlertComponent, "ui-alert", never, {
@@ -7898,6 +8179,16 @@ export declare class AlertComponent {
7898
8179
  "required": false;
7899
8180
  "isSignal": true;
7900
8181
  };
8182
+ "quiet": {
8183
+ "alias": "quiet";
8184
+ "required": false;
8185
+ "isSignal": true;
8186
+ };
8187
+ "compact": {
8188
+ "alias": "compact";
8189
+ "required": false;
8190
+ "isSignal": true;
8191
+ };
7901
8192
  }, {
7902
8193
  "dismissed": "dismissed";
7903
8194
  }, never, ["*"], true, never>;
@@ -7998,143 +8289,6 @@ export declare class IconComponent {
7998
8289
  "iconClick": "iconClick";
7999
8290
  }, never, never, true, never>;
8000
8291
  }
8001
- /** What an item template receives (`let-item let-i="index"`). */
8002
- export interface SortableItemContext<T> {
8003
- $implicit: T;
8004
- index: number;
8005
- first: boolean;
8006
- last: boolean;
8007
- /** True while this item is being dragged. */
8008
- dragging: boolean;
8009
- }
8010
- /** Marks the `<ng-template>` that renders one item: `<ng-template uiSortableItem let-item let-i="index"> … </ng-template>`. */
8011
- export declare class SortableItemDirective<T = unknown> {
8012
- readonly template: TemplateRef<SortableItemContext<T>>;
8013
- static ngTemplateContextGuard<T>(_dir: SortableItemDirective<T>, _ctx: unknown): _ctx is SortableItemContext<T>;
8014
- static ɵfac: i0.ɵɵFactoryDeclaration<SortableItemDirective<any>, never>;
8015
- static ɵdir: i0.ɵɵDirectiveDeclaration<SortableItemDirective<any>, "ng-template[uiSortableItem]", never, {}, {}, never, never, true, never>;
8016
- }
8017
- /** Emitted after the order changed (a drop, a keyboard move or a move button). */
8018
- export interface SortableOrderChange<T> {
8019
- item: T;
8020
- from: number;
8021
- to: number;
8022
- /** The new full order. */
8023
- items: T[];
8024
- }
8025
- /**
8026
- * A list (or wrapping grid) of items that can optionally be reordered. Reordering is OFF by default: with `sortable` false it only
8027
- * renders the items (nothing is draggable or focusable and no controls show), so it is safe to use as a plain list.
8028
- *
8029
- * <ui-sortable-list [(items)]="images" [sortable]="canReorder" layout="grid" ariaLabel="Product images"
8030
- * [itemLabel]="imageLabel" (orderChange)="saveOrder($event)">
8031
- * <ng-template uiSortableItem let-url let-i="index"> <ui-image-preview [src]="url" /> </ng-template>
8032
- * </ui-sortable-list>
8033
- *
8034
- * With `sortable` on, an item can be moved by
8035
- * - dragging it onto another item (mouse and any browser with native drag and drop; Firefox / Safari quirks are handled),
8036
- * - the keyboard: focus an item and press Shift + Arrow keys (Shift + Home / End = first / last),
8037
- * - the optional move buttons (`moveControls`), the touch- and pointer-friendly way (and the one that needs no gesture).
8038
- * Every change updates `items` (two-way `[(items)]`) and emits `orderChange`; the host saves it and can set `items` back if the
8039
- * save fails. A polite live region announces each move ("Image 3 moved to position 1 of 4").
8040
- */
8041
- export declare class SortableListComponent<T = unknown> {
8042
- /** The items in their current order (two-way: `[(items)]`). */
8043
- readonly items: import("@angular/core").ModelSignal<T[]>;
8044
- /** Reordering on/off. Default OFF: the list only renders its items. */
8045
- readonly sortable: import("@angular/core").InputSignal<boolean>;
8046
- /** 'list' = one column; 'grid' = wrapping columns of at least `gridMin` px. */
8047
- readonly layout: import("@angular/core").InputSignal<"list" | "grid">;
8048
- readonly gridMin: import("@angular/core").InputSignal<number>;
8049
- /** Accessible name of the list. */
8050
- readonly ariaLabel: import("@angular/core").InputSignal<string>;
8051
- /** Name of an item for assistive tech and tooltips ("Image 3"). */
8052
- readonly itemLabel: import("@angular/core").InputSignal<(item: T, index: number) => string>;
8053
- /** Show Move earlier / Move later buttons on each item (needs `sortable`) — the touch-friendly way to reorder. */
8054
- readonly moveControls: import("@angular/core").InputSignal<boolean>;
8055
- readonly moveEarlierLabel: import("@angular/core").InputSignal<string>;
8056
- readonly moveLaterLabel: import("@angular/core").InputSignal<string>;
8057
- /** Screen-reader instruction for a focused sortable item. */
8058
- readonly helpText: import("@angular/core").InputSignal<string>;
8059
- /** Announcement after a move; receives the item label, the new position (1-based) and the list size. */
8060
- readonly moveAnnouncement: import("@angular/core").InputSignal<(label: string, position: number, total: number) => string>;
8061
- /** The order changed. */
8062
- readonly orderChange: import("@angular/core").OutputEmitterRef<SortableOrderChange<T>>;
8063
- protected readonly itemTemplate: import("@angular/core").Signal<SortableItemDirective<any>>;
8064
- protected readonly _helpId: string;
8065
- protected readonly _dragIndex: import("@angular/core").WritableSignal<number | null>;
8066
- protected readonly _overIndex: import("@angular/core").WritableSignal<number | null>;
8067
- protected readonly _announcement: import("@angular/core").WritableSignal<string>;
8068
- protected readonly _count: import("@angular/core").Signal<number>;
8069
- /** Moves the item at `from` to position `to` (clamped). No-op when nothing changes or sorting is off. */
8070
- move(from: number, to: number): void;
8071
- protected onDragStart(event: DragEvent, index: number): void;
8072
- protected onDragOver(event: DragEvent, index: number): void;
8073
- protected onDrop(event: DragEvent, index: number): void;
8074
- protected onDragEnd(): void;
8075
- protected onKeydown(event: KeyboardEvent, index: number): void;
8076
- static ɵfac: i0.ɵɵFactoryDeclaration<SortableListComponent<any>, never>;
8077
- static ɵcmp: i0.ɵɵComponentDeclaration<SortableListComponent<any>, "ui-sortable-list", never, {
8078
- "items": {
8079
- "alias": "items";
8080
- "required": false;
8081
- "isSignal": true;
8082
- };
8083
- "sortable": {
8084
- "alias": "sortable";
8085
- "required": false;
8086
- "isSignal": true;
8087
- };
8088
- "layout": {
8089
- "alias": "layout";
8090
- "required": false;
8091
- "isSignal": true;
8092
- };
8093
- "gridMin": {
8094
- "alias": "gridMin";
8095
- "required": false;
8096
- "isSignal": true;
8097
- };
8098
- "ariaLabel": {
8099
- "alias": "ariaLabel";
8100
- "required": false;
8101
- "isSignal": true;
8102
- };
8103
- "itemLabel": {
8104
- "alias": "itemLabel";
8105
- "required": false;
8106
- "isSignal": true;
8107
- };
8108
- "moveControls": {
8109
- "alias": "moveControls";
8110
- "required": false;
8111
- "isSignal": true;
8112
- };
8113
- "moveEarlierLabel": {
8114
- "alias": "moveEarlierLabel";
8115
- "required": false;
8116
- "isSignal": true;
8117
- };
8118
- "moveLaterLabel": {
8119
- "alias": "moveLaterLabel";
8120
- "required": false;
8121
- "isSignal": true;
8122
- };
8123
- "helpText": {
8124
- "alias": "helpText";
8125
- "required": false;
8126
- "isSignal": true;
8127
- };
8128
- "moveAnnouncement": {
8129
- "alias": "moveAnnouncement";
8130
- "required": false;
8131
- "isSignal": true;
8132
- };
8133
- }, {
8134
- "items": "itemsChange";
8135
- "orderChange": "orderChange";
8136
- }, ["itemTemplate"], never, true, never>;
8137
- }
8138
8292
  export type ImagePreviewShape = 'circle' | 'rounded';
8139
8293
  export type ImagePreviewSize = 'sm' | 'md' | 'lg';
8140
8294
  export type ImagePreviewPlaceholder = 'person' | 'image';
@@ -8258,6 +8412,9 @@ export type KpiCardValueColor = 'default' | 'green' | 'blue';
8258
8412
  * role="button", focusable (tabindex 0, visible focus ring), and Enter / Space fire the host's (click). Give it an
8259
8413
  * accessible name with [attr.aria-label] when the label alone isn't enough (e.g. "Net Commission: $12.5K — show details").
8260
8414
  *
8415
+ * Optional background: `background="#fef2f2"` fills the card with any CSS colour (default white), e.g. a soft red for money going out; the
8416
+ * text keeps its own colours, so pick a light shade.
8417
+ *
8261
8418
  * Optional ring: `[progress]="67"` (+ `progressMax`, `progressVariant`, `progressSize`) draws a ui-progress-ring beside the label; extra lines
8262
8419
  * (a pace badge, a projection…) go in an element with the `kpi-footer` attribute.
8263
8420
  *
@@ -8277,6 +8434,8 @@ export declare class KpiCardComponent {
8277
8434
  readonly highlight: import("@angular/core").InputSignal<boolean>;
8278
8435
  readonly clickable: import("@angular/core").InputSignal<boolean>;
8279
8436
  readonly valueColor: import("@angular/core").InputSignal<KpiCardValueColor>;
8437
+ /** Card background as any CSS colour (`#fef2f2`, `var(--surface)` …). Empty (default) = white. The text colours do not change, so use a light shade. */
8438
+ readonly background: import("@angular/core").InputSignal<string>;
8280
8439
  /** Completed amount shown as a `ui-progress-ring` beside the label. `null` (default) = no ring. */
8281
8440
  readonly progress: import("@angular/core").InputSignal<number | null>;
8282
8441
  /** Total for `progress` (default 100, so `progress` is a percentage). */
@@ -8336,6 +8495,11 @@ export declare class KpiCardComponent {
8336
8495
  "required": false;
8337
8496
  "isSignal": true;
8338
8497
  };
8498
+ "background": {
8499
+ "alias": "background";
8500
+ "required": false;
8501
+ "isSignal": true;
8502
+ };
8339
8503
  "progress": {
8340
8504
  "alias": "progress";
8341
8505
  "required": false;
@@ -8373,6 +8537,167 @@ export declare class KpiCardComponent {
8373
8537
  };
8374
8538
  }, {}, never, ["[kpi-footer]"], true, never>;
8375
8539
  }
8540
+ interface StateView {
8541
+ id: string;
8542
+ name: string;
8543
+ path: string;
8544
+ value: number;
8545
+ /** "12 pickups" (or just "12"). */
8546
+ valueText: string;
8547
+ /** "Texas, 12 pickups": the accessible name, the tooltip text and the hidden-list entry. */
8548
+ label: string;
8549
+ fill: string;
8550
+ }
8551
+ /**
8552
+ * US choropleth map: the 50 states plus Washington, DC, each coloured from `colorLow` (value 0) to `colorHigh` (the largest
8553
+ * value) by its number in `data`.
8554
+ *
8555
+ * Interaction and accessibility
8556
+ * - Every state is a button (`role="button"`, name "Texas, 12 pickups", `aria-pressed` for the selected one). The group has a
8557
+ * single tab stop (roving tabindex: last focused state, else the selected one, else Alabama); arrow keys,
8558
+ * Home and End move between states in alphabetical order, Enter / Space emit `stateClick` with the abbreviation.
8559
+ * - The tooltip (state name + value) shows on hover AND on keyboard focus; it is real text, `aria-hidden` because the
8560
+ * state's accessible name already says the same. Colour is never the only signal: values are in names, tooltip and the
8561
+ * visually hidden list of all states.
8562
+ * - A selected state gets an orange outline and the others are dimmed; the focus ring is drawn as an overlay outline
8563
+ * (works the same in Chrome, Edge, Firefox and Safari) and only for keyboard focus.
8564
+ * - `prefers-reduced-motion` turns the transitions off. Strokes use `vector-effect: non-scaling-stroke`, so outlines keep
8565
+ * their pixel width when `focusState` zooms in.
8566
+ *
8567
+ * Known limitation: the very small states (CT, DC, DE, HI, MA, MD, NH, NJ, RI, VT) are tiny touch targets on a phone. They
8568
+ * are reachable by keyboard and screen reader like any other; set `showSmallStateButtons` for a row of 44px buttons for them.
8569
+ * Territories are not on the map.
8570
+ */
8571
+ export declare class UsStateMapComponent {
8572
+ /** State abbreviation -> value. Keys are case-insensitive; unknown keys are ignored; numbers and numeric strings (`'5'`) are read as numbers, anything else (negative, NaN, Infinity, text, booleans, null) counts as 0; repeated keys (`tx` and `TX`) are added up. */
8573
+ readonly data: import("@angular/core").InputSignal<Record<string, number>>;
8574
+ /** Abbreviation of the selected state (orange outline, the others are dimmed). Unknown / null = none. */
8575
+ readonly selectedState: import("@angular/core").InputSignal<string | null>;
8576
+ /** Abbreviation of a state to zoom the map to (bounding box plus 15% padding). Unknown / null = the whole map. */
8577
+ readonly focusState: import("@angular/core").InputSignal<string | null>;
8578
+ /** Unit for one, e.g. "pickup": "Texas, 1 pickup". Empty = just the number. */
8579
+ readonly unitSingular: import("@angular/core").InputSignal<string>;
8580
+ /** Unit for other counts, e.g. "pickups". Empty = the singular text is used for every count. */
8581
+ readonly unitPlural: import("@angular/core").InputSignal<string>;
8582
+ /** Colour of a value of 0 (CSS hex or rgb()). Invalid values fall back to #e5e7eb. */
8583
+ readonly colorLow: import("@angular/core").InputSignal<string>;
8584
+ /** Colour of the largest value (CSS hex or rgb()). Invalid values fall back to #1e40af. */
8585
+ readonly colorHigh: import("@angular/core").InputSignal<string>;
8586
+ /** Shows the colour scale (0 to the largest value). */
8587
+ readonly showLegend: import("@angular/core").InputSignal<boolean>;
8588
+ /** Shows a row of buttons for the very small states (touch friendly, 44px). Off by default. */
8589
+ readonly showSmallStateButtons: import("@angular/core").InputSignal<boolean>;
8590
+ /** Accessible name of the whole map. */
8591
+ readonly ariaLabel: import("@angular/core").InputSignal<string>;
8592
+ /** CSS maximum width of the map (it always shrinks to its container). */
8593
+ readonly maxWidth: import("@angular/core").InputSignal<string>;
8594
+ /** Optional CSS height of the map, e.g. "420px". Empty = follows the width (aspect ratio of the map). */
8595
+ readonly height: import("@angular/core").InputSignal<string>;
8596
+ /** Emits the state's abbreviation (upper case) on click, tap, Enter or Space. */
8597
+ readonly stateClick: import("@angular/core").OutputEmitterRef<string>;
8598
+ private readonly host;
8599
+ /** True between a pointer press and the click that follows: a mouse / touch focus must not draw the keyboard ring. */
8600
+ protected pointerDown: boolean;
8601
+ private readonly hoveredId;
8602
+ private readonly focusedId;
8603
+ private readonly lastFocusedId;
8604
+ private readonly ringVisible;
8605
+ protected readonly tipPos: import("@angular/core").WritableSignal<{
8606
+ x: number;
8607
+ y: number;
8608
+ } | null>;
8609
+ private readonly low;
8610
+ private readonly high;
8611
+ private readonly values;
8612
+ private readonly max;
8613
+ private unit;
8614
+ private valueText;
8615
+ protected readonly views: import("@angular/core").Signal<StateView[]>;
8616
+ protected readonly smallViews: import("@angular/core").Signal<StateView[]>;
8617
+ protected readonly selectedId: import("@angular/core").Signal<string | null>;
8618
+ protected readonly selectedView: import("@angular/core").Signal<StateView | null>;
8619
+ protected readonly focusRingView: import("@angular/core").Signal<StateView | null>;
8620
+ protected readonly viewBox: import("@angular/core").Signal<string>;
8621
+ /** The one state in the tab order: last focused, else selected, else the first. */
8622
+ protected readonly tabStop: import("@angular/core").Signal<string>;
8623
+ protected readonly tip: import("@angular/core").Signal<StateView | null>;
8624
+ protected readonly gradient: import("@angular/core").Signal<string>;
8625
+ protected readonly maxText: import("@angular/core").Signal<string>;
8626
+ protected readonly legendLabel: import("@angular/core").Signal<string>;
8627
+ protected opacityOf(id: string): string | null;
8628
+ protected onHover(ev: PointerEvent, id: string): void;
8629
+ protected onLeave(id: string): void;
8630
+ protected clearHover(): void;
8631
+ protected onClick(id: string): void;
8632
+ protected onFocus(id: string): void;
8633
+ protected onBlur(id: string): void;
8634
+ protected onKey(ev: KeyboardEvent, id: string): void;
8635
+ static ɵfac: i0.ɵɵFactoryDeclaration<UsStateMapComponent, never>;
8636
+ static ɵcmp: i0.ɵɵComponentDeclaration<UsStateMapComponent, "ui-us-state-map", never, {
8637
+ "data": {
8638
+ "alias": "data";
8639
+ "required": false;
8640
+ "isSignal": true;
8641
+ };
8642
+ "selectedState": {
8643
+ "alias": "selectedState";
8644
+ "required": false;
8645
+ "isSignal": true;
8646
+ };
8647
+ "focusState": {
8648
+ "alias": "focusState";
8649
+ "required": false;
8650
+ "isSignal": true;
8651
+ };
8652
+ "unitSingular": {
8653
+ "alias": "unitSingular";
8654
+ "required": false;
8655
+ "isSignal": true;
8656
+ };
8657
+ "unitPlural": {
8658
+ "alias": "unitPlural";
8659
+ "required": false;
8660
+ "isSignal": true;
8661
+ };
8662
+ "colorLow": {
8663
+ "alias": "colorLow";
8664
+ "required": false;
8665
+ "isSignal": true;
8666
+ };
8667
+ "colorHigh": {
8668
+ "alias": "colorHigh";
8669
+ "required": false;
8670
+ "isSignal": true;
8671
+ };
8672
+ "showLegend": {
8673
+ "alias": "showLegend";
8674
+ "required": false;
8675
+ "isSignal": true;
8676
+ };
8677
+ "showSmallStateButtons": {
8678
+ "alias": "showSmallStateButtons";
8679
+ "required": false;
8680
+ "isSignal": true;
8681
+ };
8682
+ "ariaLabel": {
8683
+ "alias": "ariaLabel";
8684
+ "required": false;
8685
+ "isSignal": true;
8686
+ };
8687
+ "maxWidth": {
8688
+ "alias": "maxWidth";
8689
+ "required": false;
8690
+ "isSignal": true;
8691
+ };
8692
+ "height": {
8693
+ "alias": "height";
8694
+ "required": false;
8695
+ "isSignal": true;
8696
+ };
8697
+ }, {
8698
+ "stateClick": "stateClick";
8699
+ }, never, never, true, never>;
8700
+ }
8376
8701
  export type DatePreset = 'today' | '7days' | '30days' | 'month' | 'quarter' | 'ytd' | 'all' | 'custom';
8377
8702
  export interface DateRange {
8378
8703
  preset: DatePreset;
@@ -8810,6 +9135,7 @@ export declare class RadioMatrixComponent implements ControlValueAccessor, Valid
8810
9135
  * Header (all optional - set `[showHeader]="false"` and the card is just the body):
8811
9136
  * - `title` / `subtitle`: the bold uppercase title and the grey line under it.
8812
9137
  * - `titleId`: an id for the title text, which also names the card for assistive tech (aria-labelledby).
9138
+ * - `ariaLabel`: the card's accessible name when the header does not provide one (`[showHeader]="false"`, or a header with no title). A visible title always wins; `titleId` still names the card by aria-labelledby.
8813
9139
  * - `<div card-header-leading>`: something before the title block, such as a logo or an icon.
8814
9140
  * - `<ng-container card-header>`: your own header content, shown under the title (or instead of it when no title is set).
8815
9141
  * - `<ng-container card-header-action>`: buttons or links on the right side of the header.
@@ -8825,6 +9151,7 @@ export declare class RadioMatrixComponent implements ControlValueAccessor, Valid
8825
9151
  * <ui-detail-card title="COMMUNICATIONS" subtitle="All calls, texts, and emails"> ...body... </ui-detail-card>
8826
9152
  * <ui-detail-card title="CONTACT INFO" [showEdit]="true" (editClick)="openEdit()"> ... </ui-detail-card>
8827
9153
  * <ui-detail-card [showHeader]="false"> ...body only... </ui-detail-card>
9154
+ * <ui-detail-card [showHeader]="false" ariaLabel="Report filters"> ...body only, but named for assistive tech... </ui-detail-card>
8828
9155
  * <ui-detail-card [collapsible]="false">
8829
9156
  * <div card-header>Any markup</div>
8830
9157
  * <ui-button card-header-action size="xs" variant="secondary">Add</ui-button>
@@ -8835,9 +9162,11 @@ export declare class DetailCardComponent {
8835
9162
  /** Bold uppercase title. Empty = no title text. */
8836
9163
  readonly title: import("@angular/core").InputSignal<string>;
8837
9164
  /** 1-6 makes the title a real heading for screen readers (role=heading, aria-level); null keeps it plain text. */
8838
- readonly headingLevel: import("@angular/core").InputSignal<1 | 2 | 3 | 4 | 5 | 6 | null>;
9165
+ readonly headingLevel: import("@angular/core").InputSignal<2 | 1 | 5 | 3 | 6 | 4 | null>;
8839
9166
  /** Optional id for the title text; the card is then labelled by it. Without it the title is the card's aria-label. */
8840
9167
  readonly titleId: import("@angular/core").InputSignal<string>;
9168
+ /** Accessible name of the card when the header gives none (no header, or no title). A visible title wins; blank = no name. */
9169
+ readonly ariaLabel: import("@angular/core").InputSignal<string>;
8841
9170
  /** Grey line under the title. */
8842
9171
  readonly subtitle: import("@angular/core").InputSignal<string>;
8843
9172
  /** Card background as any CSS colour (`#f8fafc`, `var(--surface)` …). Empty = white. */
@@ -8854,6 +9183,8 @@ export declare class DetailCardComponent {
8854
9183
  readonly showEdit: import("@angular/core").InputSignal<boolean>;
8855
9184
  readonly editLabel: import("@angular/core").InputSignal<string>;
8856
9185
  readonly editClick: import("@angular/core").OutputEmitterRef<void>;
9186
+ /** The group's aria-label: the visible title (unless `titleId` names the card instead), else `ariaLabel`, else none. */
9187
+ groupLabel(): string | null;
8857
9188
  /** The body is open unless the card has a header that is collapsible and was collapsed. */
8858
9189
  isOpen(): boolean;
8859
9190
  toggle(): void;
@@ -8876,6 +9207,11 @@ export declare class DetailCardComponent {
8876
9207
  "required": false;
8877
9208
  "isSignal": true;
8878
9209
  };
9210
+ "ariaLabel": {
9211
+ "alias": "ariaLabel";
9212
+ "required": false;
9213
+ "isSignal": true;
9214
+ };
8879
9215
  "subtitle": {
8880
9216
  "alias": "subtitle";
8881
9217
  "required": false;
@@ -9208,8 +9544,12 @@ export declare class ColorInputComponent implements ControlValueAccessor, Valida
9208
9544
  * - `iconColor`: colour of the icon (default blue #2563eb).
9209
9545
  * - `iconBackground`: colour of the tile behind the icon (default white when a `background` is set, otherwise light grey #f1f5f9).
9210
9546
  * - `bordered`: 1px #e2e8f0 border and 10px radius (default false).
9211
- * - `size`: 'md' (default; 1rem title, 28px tile) or 'sm' (0.875rem title, 24px tile).
9212
- * Padding is built in (14px 18px; 12px 14px at 480px and narrower) - there is no padding input.
9547
+ * - `size`: the visual size only (the semantic heading `level` is independent of it). Anything else becomes 'md'.
9548
+ * 'sm' 0.875rem (14px) title, 0.75rem description, 24px tile, 14px icon; padding 14px 18px (12px 14px at 480px and narrower)
9549
+ * 'md' (default) 1rem (16px) title, 0.8125rem description, 28px tile, 16px icon; padding 14px 18px (12px 14px at 480px and narrower)
9550
+ * 'lg' 1.25rem (20px) title, 0.9375rem description, 36px tile, 20px icon; padding 18px 22px (14px 16px at 480px and narrower)
9551
+ * 'xl' 1.5rem (24px) title (1.375rem at 480px and narrower), 1rem description, 44px tile, 24px icon; padding 22px 26px (16px 18px at 480px and narrower)
9552
+ * Padding is built in per size - there is no padding input.
9213
9553
  *
9214
9554
  * Content slots:
9215
9555
  * - `[section-header-icon]`: your own icon (an `<svg>`, an `<img>` ...) shown in the tile instead of the `icon` input.
@@ -9240,8 +9580,8 @@ export declare class SectionHeaderComponent {
9240
9580
  readonly iconBackground: import("@angular/core").InputSignal<string>;
9241
9581
  /** 1px border and 10px corners. */
9242
9582
  readonly bordered: import("@angular/core").InputSignal<boolean>;
9243
- /** 'md' (default) or 'sm'. */
9244
- readonly size: import("@angular/core").InputSignal<"sm" | "md">;
9583
+ /** Visual size: 'sm', 'md' (default), 'lg' or 'xl'. Independent of `level`; anything else renders as 'md'. */
9584
+ readonly size: import("@angular/core").InputSignal<"sm" | "md" | "lg" | "xl">;
9245
9585
  protected readonly titleId: string;
9246
9586
  protected readonly descriptionId: string;
9247
9587
  protected readonly headingLevel: import("@angular/core").Signal<number>;