@forgeroute/ui 0.4.55 → 0.4.57

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@forgeroute/ui",
3
- "version": "0.4.55",
3
+ "version": "0.4.57",
4
4
  "peerDependencies": {
5
5
  "@angular/common": ">=22.0.0",
6
6
  "@angular/core": ">=22.0.0",
@@ -1049,6 +1049,11 @@ export declare function isoKey(p: {
1049
1049
  export declare function parseTime(value: string | null | undefined): number | null;
1050
1050
  /** "9:00 AM" / "12:30 PM" from an `HH:mm` value (returned unchanged when it cannot be parsed; '' for null/undefined/non-strings). */
1051
1051
  export declare function formatTime(value: string | null | undefined): string;
1052
+ /**
1053
+ * Joins a control's own `aria-describedby` ids with the ids a host passes through `[ariaDescribedBy]` (space separated, own ids first,
1054
+ * duplicates dropped). Returns null when there is nothing to point at, so the attribute is absent.
1055
+ */
1056
+ export declare function mergeDescribedBy(own: string | null | undefined, external: string | null | undefined): string | null;
1052
1057
  /**
1053
1058
  * One choice. `V` defaults to `string`, so existing `SelectOption[]` code is unchanged; `ui-select` itself accepts
1054
1059
  * `SelectOption<string | number>[]` (numeric values for `valueType="number"`).
@@ -1085,6 +1090,8 @@ export declare class SelectComponent implements ControlValueAccessor, Validator,
1085
1090
  readonly valueType: import("@angular/core").InputSignal<"string" | "number">;
1086
1091
  readonly required: import("@angular/core").InputSignal<boolean>;
1087
1092
  readonly hint: import("@angular/core").InputSignal<string>;
1093
+ /** Id(s) of an external element that also describes this control (e.g. one shared error text for a group of fields). Space separated; MERGED after the control's own hint / error id in `aria-describedby`, never replacing it. Empty = unchanged. */
1094
+ readonly ariaDescribedBy: import("@angular/core").InputSignal<string>;
1088
1095
  readonly error: import("@angular/core").InputSignal<string>;
1089
1096
  /** Reveal the built-in error messages now (e.g. after a failed Save click), without waiting for blur. */
1090
1097
  readonly showErrors: import("@angular/core").InputSignal<boolean>;
@@ -1098,7 +1105,7 @@ export declare class SelectComponent implements ControlValueAccessor, Validator,
1098
1105
  /** The selected option's `description` ('' when none is selected or it has none); hidden while an error shows. */
1099
1106
  protected readonly _selectedDescription: import("@angular/core").Signal<string>;
1100
1107
  /** ids of the texts that describe the select: the error / hint, then the selected option's description. */
1101
- protected readonly _describedBy: import("@angular/core").Signal<string>;
1108
+ protected readonly _describedBy: import("@angular/core").Signal<string | null>;
1102
1109
  private readonly _reveal;
1103
1110
  private readonly _issue;
1104
1111
  /** True while the value breaks a built-in rule or the host passed an `[error]`. */
@@ -1170,6 +1177,11 @@ export declare class SelectComponent implements ControlValueAccessor, Validator,
1170
1177
  "required": false;
1171
1178
  "isSignal": true;
1172
1179
  };
1180
+ "ariaDescribedBy": {
1181
+ "alias": "ariaDescribedBy";
1182
+ "required": false;
1183
+ "isSignal": true;
1184
+ };
1173
1185
  "error": {
1174
1186
  "alias": "error";
1175
1187
  "required": false;
@@ -1836,6 +1848,14 @@ export declare class DataTableComponent<T extends Record<string, any>> implement
1836
1848
  * zero rows, so they can change or clear it. Headers are plain labels otherwise.
1837
1849
  */
1838
1850
  protected readonly _showColumnControls: Signal<boolean>;
1851
+ /**
1852
+ * Keys of sortable columns whose cell is blank ('' or '—') on every loaded row — nothing to sort by, so the sort control is
1853
+ * hidden. Judged from the loaded page (the same text the cells show); an active sort on the column keeps its control so it
1854
+ * can be changed or cleared.
1855
+ */
1856
+ protected readonly _emptyColumnKeys: Signal<Set<string>>;
1857
+ /** A header sort control shows for a sortable column while there are rows and the column has a value somewhere. */
1858
+ protected _canShowSort(col: ColumnDef): boolean;
1839
1859
  protected readonly _hasPhoneControls: Signal<boolean>;
1840
1860
  /** Phone sort select → sets the sort directly (same state, page reset and load as the header's onSort). */
1841
1861
  protected onPhoneSort(value: string): void;
@@ -2250,12 +2270,28 @@ export declare class ModalComponent implements OnInit, OnDestroy {
2250
2270
  * (e.g. while a save is running; the host closes it itself). Default `true` = today's behaviour.
2251
2271
  */
2252
2272
  readonly closable: import("@angular/core").InputSignal<boolean>;
2273
+ /**
2274
+ * Look of the dialog. `'default'` (today's dialog; a bottom sheet on a phone) or `'kiosk'`: a darker backdrop and a centred card on every screen
2275
+ * size that never grows past the visible viewport (header and footer stay, the body scrolls, 100dvh with a 100vh fallback). Meant for full-attention
2276
+ * dialogs such as a payment or bank-account entry; combine with `[closeOnBackdrop]="false"` and `[busy]`. See docs/modal-kiosk-and-bank-account-form.md.
2277
+ */
2278
+ readonly layout: import("@angular/core").InputSignal<"default" | "kiosk">;
2279
+ /** `false` = a click on the backdrop does not close (a mis-click must not lose a half-filled payment form). Default `true`. */
2280
+ readonly closeOnBackdrop: import("@angular/core").InputSignal<boolean>;
2281
+ /** `false` = Escape does not close. Default `true`. */
2282
+ readonly closeOnEscape: import("@angular/core").InputSignal<boolean>;
2283
+ /**
2284
+ * `true` while a request is running (e.g. a payment is processing): sets `aria-busy` on the dialog, disables the X button and blocks Escape and
2285
+ * backdrop dismissal, whatever `closable` / `closeOnEscape` / `closeOnBackdrop` say. Default `false`.
2286
+ */
2287
+ readonly busy: import("@angular/core").InputSignal<boolean>;
2253
2288
  readonly close: import("@angular/core").OutputEmitterRef<void>;
2254
2289
  /**
2255
2290
  * Element that gets focus back when the dialog closes. Takes precedence over the element that was focused (or last
2256
2291
  * clicked / activated) when it opened; used only if it is still in the page and visible. Default null = the opener.
2257
2292
  */
2258
2293
  readonly returnFocusTo: import("@angular/core").InputSignal<HTMLElement | null>;
2294
+ protected readonly kiosk: import("@angular/core").Signal<boolean>;
2259
2295
  protected readonly titleId: string;
2260
2296
  private readonly el;
2261
2297
  private readonly ren;
@@ -2268,6 +2304,8 @@ export declare class ModalComponent implements OnInit, OnDestroy {
2268
2304
  private readonly _interaction;
2269
2305
  constructor();
2270
2306
  onKeydown(event: KeyboardEvent): void;
2307
+ /** Emits `close` when the dialog may be dismissed this way (not closable / busy / backdrop or Escape switched off = nothing). */
2308
+ protected dismiss(via: 'backdrop' | 'escape' | 'close'): void;
2271
2309
  /** A focus-guard sentinel received focus (Tab left the dialog's tab order, e.g. out of an iframe): send it back inside. */
2272
2310
  protected onGuardFocus(which: 'start' | 'end', event?: FocusEvent): void;
2273
2311
  /** Initial focus — see `focusInitial` (autofocus target → first usable field → dialog container). */
@@ -2317,6 +2355,26 @@ export declare class ModalComponent implements OnInit, OnDestroy {
2317
2355
  "required": false;
2318
2356
  "isSignal": true;
2319
2357
  };
2358
+ "layout": {
2359
+ "alias": "layout";
2360
+ "required": false;
2361
+ "isSignal": true;
2362
+ };
2363
+ "closeOnBackdrop": {
2364
+ "alias": "closeOnBackdrop";
2365
+ "required": false;
2366
+ "isSignal": true;
2367
+ };
2368
+ "closeOnEscape": {
2369
+ "alias": "closeOnEscape";
2370
+ "required": false;
2371
+ "isSignal": true;
2372
+ };
2373
+ "busy": {
2374
+ "alias": "busy";
2375
+ "required": false;
2376
+ "isSignal": true;
2377
+ };
2320
2378
  "returnFocusTo": {
2321
2379
  "alias": "returnFocusTo";
2322
2380
  "required": false;
@@ -2324,7 +2382,7 @@ export declare class ModalComponent implements OnInit, OnDestroy {
2324
2382
  };
2325
2383
  }, {
2326
2384
  "close": "close";
2327
- }, never, ["*", "[modal-footer-left]", "[modal-footer-center]", "[modal-footer-right]"], true, never>;
2385
+ }, never, ["[modal-header-end]", "*", "[modal-footer-left]", "[modal-footer-center]", "[modal-footer-right]"], true, never>;
2328
2386
  }
2329
2387
  export type ToastType = 'success' | 'error' | 'info';
2330
2388
  export declare class ToastService implements OnDestroy {
@@ -4590,6 +4648,130 @@ export declare class OptionCardComponent {
4590
4648
  "action": "action";
4591
4649
  }, never, ["*"], true, never>;
4592
4650
  }
4651
+ /** Default ACH debit authorization text (same wording the contractor bank-account kiosk used). */
4652
+ export declare const DEFAULT_BANK_MANDATE_TEXT: string;
4653
+ export type BankAccountType = 'checking' | 'savings';
4654
+ export type BankHolderType = 'individual' | 'company';
4655
+ /** What `(submitted)` emits: every text value trimmed, `mandateAccepted` always `true`. */
4656
+ export interface BankAccountFormValue {
4657
+ routingNumber: string;
4658
+ accountNumber: string;
4659
+ accountType: BankAccountType;
4660
+ accountHolderName: string;
4661
+ holderType: BankHolderType;
4662
+ mandateAccepted: true;
4663
+ }
4664
+ export declare const DEFAULT_BANK_ACCOUNT_TYPE_OPTIONS: SelectOption[];
4665
+ export declare const DEFAULT_BANK_HOLDER_TYPE_OPTIONS: SelectOption[];
4666
+ /**
4667
+ * `ui-bank-account-form` - the US bank-account entry form (routing number, account number + confirmation, account type, holder name + type,
4668
+ * ACH debit authorization). Built only from library inputs; it holds NO HTTP and no provider logic: the host listens to `(submitted)` and talks to
4669
+ * its payment provider (Stripe `confirmUsBankAccountSetup`, Square, ...). See docs/modal-kiosk-and-bank-account-form.md.
4670
+ *
4671
+ * - Validation is inline through the inputs' own `[error]` / built-in rules. The routing number is only checked for 9 digits (no ABA checksum: the
4672
+ * provider validates the real number, and a client checksum would reject test numbers). Account numbers are 4-17 digits.
4673
+ * - Messages show after blur, while a field holds something invalid, or while `[showErrors]` is true; a failed `submit()` reveals them all.
4674
+ * - The form provides `UiFieldValidity` (`invalid` = not submittable), so a host can gate its own button with `viewChildren(UiFieldValidity)`,
4675
+ * or use `(validChange)`.
4676
+ * - The host's footer button calls `form.submit()` (via `viewChild`); Enter in a text field submits too.
4677
+ */
4678
+ export declare class BankAccountFormComponent implements UiFieldValidity {
4679
+ /** Reveal every built-in error now (e.g. bind to a panel's `touched()`); `submit()` on an invalid form also reveals them. */
4680
+ readonly showErrors: import("@angular/core").InputSignal<boolean>;
4681
+ /** Disables every field and blocks `submit()`. */
4682
+ readonly disabled: import("@angular/core").InputSignal<boolean>;
4683
+ /** Like `disabled`, plus `aria-busy` on the host: a provider call is running. */
4684
+ readonly busy: import("@angular/core").InputSignal<boolean>;
4685
+ /** The authorization text next to the checkbox (it is the checkbox label). The unticked default is never changed by the form. */
4686
+ readonly mandateText: import("@angular/core").InputSignal<string>;
4687
+ /** Account type choices; values must stay `checking` / `savings`. */
4688
+ readonly accountTypeOptions: import("@angular/core").InputSignal<SelectOption<string>[]>;
4689
+ /** Holder type choices; values must stay `individual` / `company`. */
4690
+ readonly holderTypeOptions: import("@angular/core").InputSignal<SelectOption<string>[]>;
4691
+ /** Pre-fills the account holder name (e.g. the customer's name) whenever it changes; the user can edit it. */
4692
+ readonly accountHolderNameDefault: import("@angular/core").InputSignal<string>;
4693
+ /** Prefix of the inner test ids: `<prefix>-routing`, `-account`, `-confirm`, `-holder-name`, `-account-type`, `-holder-type`, `-mandate`. */
4694
+ readonly testIdPrefix: import("@angular/core").InputSignal<string>;
4695
+ /** Emits the typed payload when `submit()` runs on a valid form. */
4696
+ readonly submitted: import("@angular/core").OutputEmitterRef<BankAccountFormValue>;
4697
+ /** Emits `true` / `false` whenever the form becomes submittable / not (also once on init). */
4698
+ readonly validChange: import("@angular/core").OutputEmitterRef<boolean>;
4699
+ protected readonly routingNumber: import("@angular/core").WritableSignal<string>;
4700
+ protected readonly accountNumber: import("@angular/core").WritableSignal<string>;
4701
+ protected readonly confirmAccount: import("@angular/core").WritableSignal<string>;
4702
+ protected readonly accountHolderName: import("@angular/core").WritableSignal<string>;
4703
+ protected readonly accountType: import("@angular/core").WritableSignal<string>;
4704
+ protected readonly holderType: import("@angular/core").WritableSignal<string>;
4705
+ protected readonly mandateAccepted: import("@angular/core").WritableSignal<boolean>;
4706
+ private readonly _touched;
4707
+ protected readonly routingFormatter: (raw: string) => string;
4708
+ protected readonly accountFormatter: (raw: string) => string;
4709
+ protected readonly locked: import("@angular/core").Signal<boolean>;
4710
+ protected readonly reveal: import("@angular/core").Signal<boolean>;
4711
+ protected readonly routingError: import("@angular/core").Signal<"" | "Routing number must be 9 digits.">;
4712
+ protected readonly accountError: import("@angular/core").Signal<"" | "Account number must be at least 4 digits.">;
4713
+ protected readonly confirmError: import("@angular/core").Signal<"" | "Account numbers do not match.">;
4714
+ /** First reason the form cannot be submitted ('' when it can). */
4715
+ readonly errorMessage: import("@angular/core").Signal<"" | "Account holder name is required." | "Routing number is required." | "Routing number must be 9 digits." | "Account number is required." | "Account number must be at least 4 digits." | "Confirm account number is required." | "Account numbers do not match." | "Select a valid account type." | "Select a valid holder type." | "You must authorize ACH debits to continue.">;
4716
+ /** True while the form cannot be submitted (`UiFieldValidity`). */
4717
+ readonly invalid: import("@angular/core").Signal<boolean>;
4718
+ /** True when the form can be submitted (ignores `disabled` / `busy`). */
4719
+ readonly valid: import("@angular/core").Signal<boolean>;
4720
+ private readonly _fields;
4721
+ constructor();
4722
+ protected id(name: string): string;
4723
+ protected onEnter(event: Event): void;
4724
+ /** Validates and, when valid, emits `submitted`. An invalid form reveals all messages and emits nothing. Ignored while `disabled` / `busy`. */
4725
+ submit(): void;
4726
+ /** Clears every field back to the defaults (checking, individual, authorization unticked, holder name = `accountHolderNameDefault`). */
4727
+ reset(): void;
4728
+ static ɵfac: i0.ɵɵFactoryDeclaration<BankAccountFormComponent, never>;
4729
+ static ɵcmp: i0.ɵɵComponentDeclaration<BankAccountFormComponent, "ui-bank-account-form", never, {
4730
+ "showErrors": {
4731
+ "alias": "showErrors";
4732
+ "required": false;
4733
+ "isSignal": true;
4734
+ };
4735
+ "disabled": {
4736
+ "alias": "disabled";
4737
+ "required": false;
4738
+ "isSignal": true;
4739
+ };
4740
+ "busy": {
4741
+ "alias": "busy";
4742
+ "required": false;
4743
+ "isSignal": true;
4744
+ };
4745
+ "mandateText": {
4746
+ "alias": "mandateText";
4747
+ "required": false;
4748
+ "isSignal": true;
4749
+ };
4750
+ "accountTypeOptions": {
4751
+ "alias": "accountTypeOptions";
4752
+ "required": false;
4753
+ "isSignal": true;
4754
+ };
4755
+ "holderTypeOptions": {
4756
+ "alias": "holderTypeOptions";
4757
+ "required": false;
4758
+ "isSignal": true;
4759
+ };
4760
+ "accountHolderNameDefault": {
4761
+ "alias": "accountHolderNameDefault";
4762
+ "required": false;
4763
+ "isSignal": true;
4764
+ };
4765
+ "testIdPrefix": {
4766
+ "alias": "testIdPrefix";
4767
+ "required": false;
4768
+ "isSignal": true;
4769
+ };
4770
+ }, {
4771
+ "submitted": "submitted";
4772
+ "validChange": "validChange";
4773
+ }, never, never, true, never>;
4774
+ }
4593
4775
  export interface ActiveConfirm {
4594
4776
  title: string;
4595
4777
  message: string;
@@ -4778,6 +4960,8 @@ export declare class TextInputComponent implements ControlValueAccessor, Validat
4778
4960
  readonly inputmode: import("@angular/core").InputSignal<"" | "none" | "text" | "search" | "email" | "tel" | "url" | "decimal" | "numeric">;
4779
4961
  readonly readonly: import("@angular/core").InputSignal<boolean>;
4780
4962
  readonly hint: import("@angular/core").InputSignal<string>;
4963
+ /** Id(s) of an external element that also describes this control (e.g. one shared error text for a group of fields). Space separated; MERGED after the control's own hint / error id in `aria-describedby`, never replacing it. Empty = unchanged. */
4964
+ readonly ariaDescribedBy: import("@angular/core").InputSignal<string>;
4781
4965
  readonly error: import("@angular/core").InputSignal<string>;
4782
4966
  /** When true, automatically formats the value as a US phone number as the user types. */
4783
4967
  readonly phoneFormat: import("@angular/core").InputSignal<boolean>;
@@ -4963,6 +5147,11 @@ export declare class TextInputComponent implements ControlValueAccessor, Validat
4963
5147
  "required": false;
4964
5148
  "isSignal": true;
4965
5149
  };
5150
+ "ariaDescribedBy": {
5151
+ "alias": "ariaDescribedBy";
5152
+ "required": false;
5153
+ "isSignal": true;
5154
+ };
4966
5155
  "error": {
4967
5156
  "alias": "error";
4968
5157
  "required": false;
@@ -5035,6 +5224,8 @@ export declare class TextareaInputComponent implements ControlValueAccessor, Val
5035
5224
  readonly required: import("@angular/core").InputSignal<boolean>;
5036
5225
  readonly readonly: import("@angular/core").InputSignal<boolean>;
5037
5226
  readonly hint: import("@angular/core").InputSignal<string>;
5227
+ /** Id(s) of an external element that also describes this control (e.g. one shared error text for a group of fields). Space separated; MERGED after the control's own hint / error id in `aria-describedby`, never replacing it. Empty = unchanged. */
5228
+ readonly ariaDescribedBy: import("@angular/core").InputSignal<string>;
5038
5229
  /**
5039
5230
  * Opt-in. `false` (default) = unchanged: a labelled field's hint renders INSIDE the `<label>` ("Label (hint)" is the accessible name,
5040
5231
  * no aria-describedby for it). `true` = the hint is a sibling of the label (`.ta-head` row, id `<textarea id>-hint`), the accessible
@@ -5057,6 +5248,7 @@ export declare class TextareaInputComponent implements ControlValueAccessor, Val
5057
5248
  * hint is replaced by the error) followed by the error. The label is the accessible NAME; the hint is the DESCRIPTION.
5058
5249
  */
5059
5250
  protected readonly _describedBy: import("@angular/core").Signal<string | null>;
5251
+ private readonly _ownDescribedBy;
5060
5252
  private readonly _reveal;
5061
5253
  private readonly _issue;
5062
5254
  /** True while the value breaks a built-in rule or the host passed an `[error]`. */
@@ -5124,6 +5316,11 @@ export declare class TextareaInputComponent implements ControlValueAccessor, Val
5124
5316
  "required": false;
5125
5317
  "isSignal": true;
5126
5318
  };
5319
+ "ariaDescribedBy": {
5320
+ "alias": "ariaDescribedBy";
5321
+ "required": false;
5322
+ "isSignal": true;
5323
+ };
5127
5324
  "hintAsDescription": {
5128
5325
  "alias": "hintAsDescription";
5129
5326
  "required": false;
@@ -5527,6 +5724,8 @@ export declare class DateInputComponent implements ControlValueAccessor, Validat
5527
5724
  readonly min: import("@angular/core").InputSignal<string>;
5528
5725
  readonly max: import("@angular/core").InputSignal<string>;
5529
5726
  readonly hint: import("@angular/core").InputSignal<string>;
5727
+ /** Id(s) of an external element that also describes this control (e.g. one shared error text for a group of fields). Space separated; MERGED after the control's own hint / error id in `aria-describedby`, never replacing it. Empty = unchanged. */
5728
+ readonly ariaDescribedBy: import("@angular/core").InputSignal<string>;
5530
5729
  readonly error: import("@angular/core").InputSignal<string>;
5531
5730
  /** Reveal the built-in error messages now (e.g. after a failed Save click), without waiting for blur. */
5532
5731
  readonly showErrors: import("@angular/core").InputSignal<boolean>;
@@ -5535,6 +5734,8 @@ export declare class DateInputComponent implements ControlValueAccessor, Validat
5535
5734
  private readonly _cvaDisabled;
5536
5735
  protected readonly disabled: import("@angular/core").Signal<boolean>;
5537
5736
  protected readonly _value: import("@angular/core").WritableSignal<string>;
5737
+ /** `aria-describedby`: the error / hint text, then the host's `ariaDescribedBy` id(s). */
5738
+ protected readonly _describedBy: import("@angular/core").Signal<string | null>;
5538
5739
  private readonly _reveal;
5539
5740
  private readonly _issue;
5540
5741
  /** True while the value breaks a built-in rule or the host passed an `[error]`. */
@@ -5589,6 +5790,11 @@ export declare class DateInputComponent implements ControlValueAccessor, Validat
5589
5790
  "required": false;
5590
5791
  "isSignal": true;
5591
5792
  };
5793
+ "ariaDescribedBy": {
5794
+ "alias": "ariaDescribedBy";
5795
+ "required": false;
5796
+ "isSignal": true;
5797
+ };
5592
5798
  "error": {
5593
5799
  "alias": "error";
5594
5800
  "required": false;
@@ -5615,6 +5821,8 @@ export declare class DatetimeInputComponent implements ControlValueAccessor, Val
5615
5821
  readonly min: import("@angular/core").InputSignal<string>;
5616
5822
  readonly max: import("@angular/core").InputSignal<string>;
5617
5823
  readonly hint: import("@angular/core").InputSignal<string>;
5824
+ /** Id(s) of an external element that also describes this control (e.g. one shared error text for a group of fields). Space separated; MERGED after the control's own hint / error id in `aria-describedby`, never replacing it. Empty = unchanged. */
5825
+ readonly ariaDescribedBy: import("@angular/core").InputSignal<string>;
5618
5826
  readonly error: import("@angular/core").InputSignal<string>;
5619
5827
  /** Reveal the built-in error messages now (e.g. after a failed Save click), without waiting for blur. */
5620
5828
  readonly showErrors: import("@angular/core").InputSignal<boolean>;
@@ -5622,6 +5830,8 @@ export declare class DatetimeInputComponent implements ControlValueAccessor, Val
5622
5830
  private readonly _cvaDisabled;
5623
5831
  protected readonly disabled: import("@angular/core").Signal<boolean>;
5624
5832
  protected readonly _value: import("@angular/core").WritableSignal<string>;
5833
+ /** `aria-describedby`: the error / hint text, then the host's `ariaDescribedBy` id(s). */
5834
+ protected readonly _describedBy: import("@angular/core").Signal<string | null>;
5625
5835
  private readonly _reveal;
5626
5836
  private readonly _issue;
5627
5837
  /** True while the value breaks a built-in rule or the host passed an `[error]`. */
@@ -5674,6 +5884,11 @@ export declare class DatetimeInputComponent implements ControlValueAccessor, Val
5674
5884
  "required": false;
5675
5885
  "isSignal": true;
5676
5886
  };
5887
+ "ariaDescribedBy": {
5888
+ "alias": "ariaDescribedBy";
5889
+ "required": false;
5890
+ "isSignal": true;
5891
+ };
5677
5892
  "error": {
5678
5893
  "alias": "error";
5679
5894
  "required": false;
@@ -5701,6 +5916,8 @@ export declare class TimeInputComponent implements ControlValueAccessor, Validat
5701
5916
  readonly min: import("@angular/core").InputSignal<string>;
5702
5917
  readonly max: import("@angular/core").InputSignal<string>;
5703
5918
  readonly hint: import("@angular/core").InputSignal<string>;
5919
+ /** Id(s) of an external element that also describes this control (e.g. one shared error text for a group of fields). Space separated; MERGED after the control's own hint / error id in `aria-describedby`, never replacing it. Empty = unchanged. */
5920
+ readonly ariaDescribedBy: import("@angular/core").InputSignal<string>;
5704
5921
  readonly error: import("@angular/core").InputSignal<string>;
5705
5922
  /** Reveal the built-in error messages now (e.g. after a failed Save click), without waiting for blur. */
5706
5923
  readonly showErrors: import("@angular/core").InputSignal<boolean>;
@@ -5710,6 +5927,8 @@ export declare class TimeInputComponent implements ControlValueAccessor, Validat
5710
5927
  protected readonly disabled: import("@angular/core").Signal<boolean>;
5711
5928
  protected readonly _value: import("@angular/core").WritableSignal<string>;
5712
5929
  protected readonly _inputId: string;
5930
+ /** `aria-describedby`: the error / hint text, then the host's `ariaDescribedBy` id(s). */
5931
+ protected readonly _describedBy: import("@angular/core").Signal<string | null>;
5713
5932
  private readonly _reveal;
5714
5933
  private readonly _issue;
5715
5934
  /** True while the value breaks a built-in rule or the host passed an `[error]`. */
@@ -5766,6 +5985,11 @@ export declare class TimeInputComponent implements ControlValueAccessor, Validat
5766
5985
  "required": false;
5767
5986
  "isSignal": true;
5768
5987
  };
5988
+ "ariaDescribedBy": {
5989
+ "alias": "ariaDescribedBy";
5990
+ "required": false;
5991
+ "isSignal": true;
5992
+ };
5769
5993
  "error": {
5770
5994
  "alias": "error";
5771
5995
  "required": false;
@@ -6729,6 +6953,11 @@ export type CardListIcon = 'call' | 'email' | 'sms' | 'task' | 'doc' | 'money' |
6729
6953
  * Other projected content (default slot) shows after the chips at the row end; `[card-stats]` and `[card-detail]` add a footer row
6730
6954
  * under the row (use the `.cli-stat`, `.cli-stat-label`, `.cli-stat-value`, `.cli-stat-divider` classes inside `[card-stats]`).
6731
6955
  *
6956
+ * Delete and a generic action (additive; unused = the row looks exactly as before). Row-end order: Edit, View, action, delete, then projected content.
6957
+ * - `[deletable]="true"` shows a red icon-only trash button (28px, 44px hit area on touch) -> `(delete)`; name it with `deleteLabel` (default "Delete"), `deleteTestId` sets its `data-testid`.
6958
+ * The page owns the confirmation (the component never deletes anything itself).
6959
+ * - `actionLabel="Download"` shows a grey chip button with that text -> `(action)`; `actionTestId`, `actionAriaLabel` as for the other buttons.
6960
+ *
6732
6961
  * Accessibility: the Edit / View buttons are real buttons; give them a longer name with `editAriaLabel` / `viewAriaLabel`
6733
6962
  * ("Edit task Call John") when the visible word alone is ambiguous in a list. The priority dot (`high`/`medium`/`low`) has a tooltip and an
6734
6963
  * accessible name (`High priority`, ...), is focusable so the tooltip works by keyboard; `blue`/`green` dots are decorative. The icon circle is decorative.
@@ -6757,10 +6986,24 @@ export declare class CardListItemComponent {
6757
6986
  /** Accessible names for the buttons when the visible word is not enough ("Edit task Call John"). */
6758
6987
  readonly editAriaLabel: import("@angular/core").InputSignal<string>;
6759
6988
  readonly viewAriaLabel: import("@angular/core").InputSignal<string>;
6989
+ /** Built-in icon-only trash button -> `delete`. The accessible name comes from `deleteLabel` ("Delete task Call John"). */
6990
+ readonly deletable: import("@angular/core").InputSignal<boolean>;
6991
+ readonly deleteLabel: import("@angular/core").InputSignal<string>;
6992
+ /** `data-testid` of the delete button (none when empty). */
6993
+ readonly deleteTestId: import("@angular/core").InputSignal<string>;
6994
+ /** Built-in secondary chip button (text = `actionLabel`, e.g. "Download") -> `action`; shown only while `actionLabel` is not empty. */
6995
+ readonly actionLabel: import("@angular/core").InputSignal<string>;
6996
+ readonly actionTestId: import("@angular/core").InputSignal<string>;
6997
+ readonly actionAriaLabel: import("@angular/core").InputSignal<string>;
6998
+ /** A built-in Edit / View / action / delete button shows (the row then keeps a minimum height so a badge and a chip never overlap). */
6999
+ protected readonly hasBuiltInChip: import("@angular/core").Signal<boolean>;
6760
7000
  readonly editClick: import("@angular/core").OutputEmitterRef<void>;
6761
7001
  readonly viewClick: import("@angular/core").OutputEmitterRef<void>;
7002
+ readonly delete: import("@angular/core").OutputEmitterRef<void>;
7003
+ readonly action: import("@angular/core").OutputEmitterRef<void>;
6762
7004
  protected readonly calendarPath = "M5 4h14a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2z M16 2v4 M8 2v4 M3 10h18";
6763
7005
  protected readonly editPath = "M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7 M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z";
7006
+ protected readonly trashPath = "M3 6h18 M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2 M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6 M10 11v6 M14 11v6";
6764
7007
  protected readonly iconPath: import("@angular/core").Signal<string | null>;
6765
7008
  protected readonly indicatorLabel: import("@angular/core").Signal<string>;
6766
7009
  static ɵfac: i0.ɵɵFactoryDeclaration<CardListItemComponent, never>;
@@ -6830,9 +7073,41 @@ export declare class CardListItemComponent {
6830
7073
  "required": false;
6831
7074
  "isSignal": true;
6832
7075
  };
7076
+ "deletable": {
7077
+ "alias": "deletable";
7078
+ "required": false;
7079
+ "isSignal": true;
7080
+ };
7081
+ "deleteLabel": {
7082
+ "alias": "deleteLabel";
7083
+ "required": false;
7084
+ "isSignal": true;
7085
+ };
7086
+ "deleteTestId": {
7087
+ "alias": "deleteTestId";
7088
+ "required": false;
7089
+ "isSignal": true;
7090
+ };
7091
+ "actionLabel": {
7092
+ "alias": "actionLabel";
7093
+ "required": false;
7094
+ "isSignal": true;
7095
+ };
7096
+ "actionTestId": {
7097
+ "alias": "actionTestId";
7098
+ "required": false;
7099
+ "isSignal": true;
7100
+ };
7101
+ "actionAriaLabel": {
7102
+ "alias": "actionAriaLabel";
7103
+ "required": false;
7104
+ "isSignal": true;
7105
+ };
6833
7106
  }, {
6834
7107
  "editClick": "editClick";
6835
7108
  "viewClick": "viewClick";
7109
+ "delete": "delete";
7110
+ "action": "action";
6836
7111
  }, never, ["[card-list-inline]", "[card-list-action]", "*", "[card-stats]", "[card-detail]"], true, never>;
6837
7112
  }
6838
7113
  /** A note as the notes API returns it. */
@@ -6870,8 +7145,22 @@ export declare class NotesComponent {
6870
7145
  /** What the notes belong to, as the API names it: `contact`, `transaction`, `property`, `task`, ... */
6871
7146
  readonly resourceType: import("@angular/core").InputSignal<string>;
6872
7147
  readonly resourceId: import("@angular/core").InputSignal<string>;
7148
+ /**
7149
+ * Resource-specific notes API (optional). When set (e.g. `/permits/42/notes`, relative to `FORGEROUTE_CONFIG.baseUrl`), the component uses it instead of
7150
+ * the generic `/notes/{resourceType}/{resourceId}` API and `resourceType` / `resourceId` are not needed:
7151
+ * - `GET {basePath}?page=<0-based>&size=5` -> `{ content, totalElements, ... }` (`page` or Spring's `number` is accepted for the page index)
7152
+ * - `POST {basePath}` `{ content }` -> the new note
7153
+ * - `PUT {basePath}/{noteId}` `{ content }` (only when `editable` is true)
7154
+ * - `DELETE {basePath}/{noteId}`
7155
+ * A note's text may come as `body` or `content`; a missing `updatedAt` counts as `createdAt` (no "edited" tag). Empty (default) = the generic API.
7156
+ */
7157
+ readonly basePath: import("@angular/core").InputSignal<string>;
6873
7158
  /** True: list only, no add box, edit or delete. */
6874
7159
  readonly readOnly: import("@angular/core").InputSignal<boolean>;
7160
+ /** False hides the edit icon (for APIs without an update endpoint). Default true. */
7161
+ readonly editable: import("@angular/core").InputSignal<boolean>;
7162
+ /** Longest note, in characters after trimming (default `NOTES_MAX_LENGTH`, 10000). Set it to the API's column size, e.g. 255 for customer notes. */
7163
+ readonly maxLength: import("@angular/core").InputSignal<number>;
6875
7164
  /** Total number of notes after every load / add / delete. */
6876
7165
  readonly totalChange: import("@angular/core").OutputEmitterRef<number>;
6877
7166
  private readonly http;
@@ -6879,8 +7168,6 @@ export declare class NotesComponent {
6879
7168
  private readonly destroyRef;
6880
7169
  private readonly apiBase;
6881
7170
  readonly pageSize = 5;
6882
- /** The character limit of a note (see `NOTES_MAX_LENGTH`). */
6883
- readonly maxLength = 10000;
6884
7171
  readonly notes: import("@angular/core").WritableSignal<NoteItem[]>;
6885
7172
  readonly loading: import("@angular/core").WritableSignal<boolean>;
6886
7173
  readonly saving: import("@angular/core").WritableSignal<boolean>;
@@ -6898,6 +7185,12 @@ export declare class NotesComponent {
6898
7185
  /** True when the trimmed text is not empty and within the limit. */
6899
7186
  protected validBody(text: string): boolean;
6900
7187
  private get listUrl();
7188
+ private noteUrl;
7189
+ private get ready();
7190
+ /** Request body for create / update: `{ content }` for a `basePath` API, `{ body }` for the generic one. */
7191
+ private payload;
7192
+ /** Accepts `body` or `content` as the text and a missing `updatedAt`. */
7193
+ private normalize;
6901
7194
  constructor();
6902
7195
  loadPage(p: number): void;
6903
7196
  addNote(): void;
@@ -6918,11 +7211,26 @@ export declare class NotesComponent {
6918
7211
  "required": false;
6919
7212
  "isSignal": true;
6920
7213
  };
7214
+ "basePath": {
7215
+ "alias": "basePath";
7216
+ "required": false;
7217
+ "isSignal": true;
7218
+ };
6921
7219
  "readOnly": {
6922
7220
  "alias": "readOnly";
6923
7221
  "required": false;
6924
7222
  "isSignal": true;
6925
7223
  };
7224
+ "editable": {
7225
+ "alias": "editable";
7226
+ "required": false;
7227
+ "isSignal": true;
7228
+ };
7229
+ "maxLength": {
7230
+ "alias": "maxLength";
7231
+ "required": false;
7232
+ "isSignal": true;
7233
+ };
6926
7234
  }, {
6927
7235
  "totalChange": "totalChange";
6928
7236
  }, never, never, true, never>;