@forgeroute/ui 0.4.71 → 0.4.72

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.
@@ -356,6 +356,34 @@ export type BulkUpdateOption<T = any> = string | {
356
356
  * else "N <itemLabel>(s) <doneLabel>.". Default 'updated'.
357
357
  */
358
358
  doneLabel?: string;
359
+ /**
360
+ * Direct action only: the request returns a FILE instead of JSON (a ZIP of PDFs, a CSV...). The table still confirms first and POSTs
361
+ * `<endpoint>/bulk/<field>` with exactly `{ ids }`, but asks for a blob response and saves it as one download (one file, so browsers do not
362
+ * block it the way several automatic downloads are blocked). The file name is the response's `Content-Disposition` filename, else
363
+ * `fileName`, else the action key. The toast reads "N <itemLabel>(s) <doneLabel>." (`doneLabel` defaults to 'downloaded' here); the server may
364
+ * send an `X-Skipped-Count` header with the number of selected rows it left out of the file ("N downloaded, M skipped."). The rows do not change,
365
+ * so the table is not refreshed; the selection is cleared and `(bulkAction)` is emitted. An error response is read as `{ message }` JSON and shown
366
+ * in an error toast. Omit it and the action expects JSON as before.
367
+ *
368
+ * { field: 'download-pdfs', action: true, label: 'Download PDFs', download: { fileName: 'inspections.zip' } }
369
+ */
370
+ download?: {
371
+ fileName?: string;
372
+ };
373
+ /**
374
+ * Direct action only (`opens: 'panel'`): the button does not confirm and does not POST. It emits `(bulkPanelClick)` with the
375
+ * eligible rows and the host opens its own panel or form (compose an e-mail, add a charge...) and does the work itself.
376
+ * The host calls `clearSelection()` and `refresh()` on the table when it is done. `confirm` and `doneLabel` are ignored for a panel action (no confirm is shown; `variant: 'danger'` still colours the button); `eligible` still applies (refused rows are never passed on). Omit it and nothing changes.
377
+ *
378
+ * { field: 'email', action: true, opens: 'panel', label: 'Email', eligible: (r: Resident) => !!r.email }
379
+ */
380
+ opens?: 'panel';
381
+ /**
382
+ * Panel action only (`opens: 'panel'`): true while the action is not available right now (e.g. text messaging is switched off). The button is
383
+ * then not shown at all. Read every time the bar renders, so it can read signals; a function that throws counts as "not hidden". A panel
384
+ * action is also not shown while none of the selected rows is `eligible`. Omit it and the button shows whenever a selected row is eligible.
385
+ */
386
+ hidden?: () => boolean;
359
387
  };
360
388
  /** What a bulk confirm function receives. For a direct bulk action: `columnLabel` is the action label, `targetValue`/`targetLabel` are '', `rows`/`skippedRows` the eligible / refused selected rows. For bulk Delete: `targetValue`/`targetLabel` are '', `columnLabel` is 'Delete', skipped counts are 0. */
361
389
  export interface BulkConfirmContext<T = any> {
@@ -423,6 +451,14 @@ export interface BulkActionDef {
423
451
  eligible?: (row: any) => boolean;
424
452
  /** Direct action: past-tense word in the result toast (from `{ doneLabel }`), default 'updated'. */
425
453
  doneLabel?: string;
454
+ /** Direct action that returns a file (from `{ download }`): the response is saved as a download instead of read as JSON. */
455
+ download?: {
456
+ fileName?: string;
457
+ };
458
+ /** True for a direct action that opens a host panel instead of confirming and POSTing (from `{ opens: 'panel' }`). */
459
+ opensPanel?: boolean;
460
+ /** Panel action: true while it is not available (from `{ hidden }`); the button is not shown. */
461
+ hidden?: () => boolean;
426
462
  /**
427
463
  * The item field this action targets (e.g. 'status', 'type').
428
464
  * When set the table shows an inline select populated from the column's option sources.
@@ -437,6 +473,19 @@ export interface BulkActionEvent {
437
473
  value?: string;
438
474
  skippedCount: number;
439
475
  }
476
+ /** Emitted by (bulkPanelClick) when the user clicks a bulk action declared with `opens: 'panel'`. */
477
+ export interface BulkPanelEvent<T = any> {
478
+ /** `action-<key>` of the clicked bulk option. */
479
+ type: string;
480
+ /** The option's `field` (its key), e.g. 'email'. */
481
+ key: string;
482
+ /** Ids of the eligible selected rows. */
483
+ ids: string[];
484
+ /** The eligible selected rows (loaded page). */
485
+ rows: T[];
486
+ /** Selected rows the option's `eligible` refused. */
487
+ skippedCount: number;
488
+ }
440
489
  /** Emitted by (rowReorder) after the user moves a row (`reorderable`). */
441
490
  export interface TableRowReorderEvent<T = any> {
442
491
  /** The row that was moved. */
@@ -1084,6 +1133,8 @@ export declare class SelectComponent implements ControlValueAccessor, Validator,
1084
1133
  readonly label: import("@angular/core").InputSignal<string>;
1085
1134
  /** Accessible name for a select with no visible label (e.g. an inline row or table-cell select). */
1086
1135
  readonly ariaLabel: import("@angular/core").InputSignal<string>;
1136
+ /** Native `name` attribute placed on the inner `<select>` (e2e `[name=x]` selectors, autofill). None when empty. */
1137
+ readonly inputName: import("@angular/core").InputSignal<string>;
1087
1138
  readonly placeholder: import("@angular/core").InputSignal<string>;
1088
1139
  readonly options: import("@angular/core").InputSignal<SelectOption<string | number>[]>;
1089
1140
  /** What the control value is: `'string'` (default, numeric option values become strings) or `'number'` (`number | null`). */
@@ -1152,6 +1203,11 @@ export declare class SelectComponent implements ControlValueAccessor, Validator,
1152
1203
  "required": false;
1153
1204
  "isSignal": true;
1154
1205
  };
1206
+ "inputName": {
1207
+ "alias": "inputName";
1208
+ "required": false;
1209
+ "isSignal": true;
1210
+ };
1155
1211
  "placeholder": {
1156
1212
  "alias": "placeholder";
1157
1213
  "required": false;
@@ -1540,6 +1596,11 @@ export declare class DataTableComponent<T extends Record<string, any>> implement
1540
1596
  readonly tabChange: import("@angular/core").OutputEmitterRef<string>;
1541
1597
  /** Emitted when the user applies a bulk action. The table has already filtered to eligible IDs. */
1542
1598
  readonly bulkAction: import("@angular/core").OutputEmitterRef<BulkActionEvent>;
1599
+ /**
1600
+ * Emitted when the user clicks a bulk action declared `{ field, action: true, opens: 'panel' }`. The table sends nothing: the host opens its
1601
+ * own panel for `rows` and, when it has finished, calls `clearSelection()` and `refresh()` on the table.
1602
+ */
1603
+ readonly bulkPanelClick: import("@angular/core").OutputEmitterRef<BulkPanelEvent<T>>;
1543
1604
  /** Emitted after a built-in single-row delete completes successfully. */
1544
1605
  readonly rowDeleted: import("@angular/core").OutputEmitterRef<T>;
1545
1606
  /**
@@ -1763,6 +1824,8 @@ export declare class DataTableComponent<T extends Record<string, any>> implement
1763
1824
  private _hostConfirm;
1764
1825
  /** Why a bulk action can't be used right now ('' = it can). Only Delete with `deletable` and a direct action with `eligible` can be blocked. */
1765
1826
  protected _bulkBlockedReason(def: BulkActionDef): string;
1827
+ /** A panel action is not shown while the host says it is unavailable or no selected row is eligible. Everything else is always shown. */
1828
+ protected _bulkHidden(def: BulkActionDef): boolean;
1766
1829
  /** The distinct reasons of the currently blocked bulk actions, shown as visible text next to the disabled buttons. */
1767
1830
  protected _bulkBlockedHints(): string[];
1768
1831
  /** Selected rows (loaded page) split by the delete option's `deletable` predicate; without it every selected row is deletable. */
@@ -1773,8 +1836,14 @@ export declare class DataTableComponent<T extends Record<string, any>> implement
1773
1836
  protected readonly _runningAction: import("@angular/core").WritableSignal<string | null>;
1774
1837
  /** True while a direct action's confirm dialog is open (guards against a second click). */
1775
1838
  private _confirmingAction;
1839
+ /** Panel action: no confirm and no request; hands the eligible rows to the host, which opens its own panel. */
1840
+ private _openBulkPanel;
1776
1841
  /** Direct bulk action: confirm, then POST `<endpoint>/bulk/<key>` with `{ ids }` of the eligible rows. */
1777
1842
  private _runDirectAction;
1843
+ /** Direct action that returns a file: POST `{ ids }` asking for a blob, save it as one download, toast, clear the selection. */
1844
+ private _runDownloadAction;
1845
+ /** The `{ message }` of a failed file request: with a blob response the error body arrives as a Blob, so it is read as text first. */
1846
+ private _downloadErrorMessage;
1778
1847
  /** Called when the user clicks a bulk action button in the selection bar. */
1779
1848
  protected onBulkActionClick(def: BulkActionDef): void;
1780
1849
  /** True while the field-change confirmation dialog is open (guards against a second Apply click). */
@@ -2123,6 +2192,7 @@ export declare class DataTableComponent<T extends Record<string, any>> implement
2123
2192
  "selectionChange": "selectionChange";
2124
2193
  "tabChange": "tabChange";
2125
2194
  "bulkAction": "bulkAction";
2195
+ "bulkPanelClick": "bulkPanelClick";
2126
2196
  "rowDeleted": "rowDeleted";
2127
2197
  "rowReorder": "rowReorder";
2128
2198
  }, never, never, true, never>;
@@ -2158,7 +2228,7 @@ export declare class SidePanelComponent implements OnDestroy {
2158
2228
  readonly cancelLabel: import("@angular/core").InputSignal<string>;
2159
2229
  /** Right-aligned primary action button label. Empty string = hidden. */
2160
2230
  readonly primaryLabel: import("@angular/core").InputSignal<string>;
2161
- readonly primaryVariant: import("@angular/core").InputSignal<"primary" | "danger" | "warning">;
2231
+ readonly primaryVariant: import("@angular/core").InputSignal<"warning" | "danger" | "primary">;
2162
2232
  readonly primaryLoading: import("@angular/core").InputSignal<boolean>;
2163
2233
  readonly primaryDisabled: import("@angular/core").InputSignal<boolean>;
2164
2234
  /** `data-testid` of the Cancel button; none when empty (default). */
@@ -2272,7 +2342,7 @@ export declare class ModalComponent implements OnInit, OnDestroy {
2272
2342
  */
2273
2343
  readonly describedBy: import("@angular/core").InputSignal<string | null>;
2274
2344
  readonly maxWidth: import("@angular/core").InputSignal<string>;
2275
- readonly bodyOverflow: import("@angular/core").InputSignal<"hidden" | "auto" | "visible">;
2345
+ readonly bodyOverflow: import("@angular/core").InputSignal<"hidden" | "visible" | "auto">;
2276
2346
  /** `data-testid` of the dialog element itself (the host `<ui-modal>` is always in the page, the dialog only while open). None when empty. */
2277
2347
  readonly dialogTestId: import("@angular/core").InputSignal<string>;
2278
2348
  /** Hides the header X button (e.g. while a request is running). Escape and a backdrop click still close unless `closable` is false. */
@@ -2830,7 +2900,7 @@ export declare class AudioPlayerComponent {
2830
2900
  /** Accessible name of the player. */
2831
2901
  readonly ariaLabel: import("@angular/core").InputSignal<string>;
2832
2902
  /** How much to load before play: 'metadata' (default), 'auto' or 'none'. */
2833
- readonly preload: import("@angular/core").InputSignal<"none" | "auto" | "metadata">;
2903
+ readonly preload: import("@angular/core").InputSignal<"none" | "metadata" | "auto">;
2834
2904
  /** Fires when the browser can't load or decode the source. */
2835
2905
  readonly playbackError: import("@angular/core").OutputEmitterRef<void>;
2836
2906
  protected readonly failed: import("@angular/core").WritableSignal<boolean>;
@@ -3482,7 +3552,7 @@ export declare class StepperComponent {
3482
3552
  * its circle, one continuous line behind the circles that fills as steps complete; a complete step shows a check, the current step an
3483
3553
  * accent ring with a dot, an upcoming step an empty circle (no numbers). Circles are 40px (32px with `size="sm"`).
3484
3554
  */
3485
- readonly labelPosition: import("@angular/core").InputSignal<"beside" | "below">;
3555
+ readonly labelPosition: import("@angular/core").InputSignal<"below" | "beside">;
3486
3556
  /** Viewport width in px below which a horizontal stepper is drawn vertical (labels beside the circles), e.g. `640`. null (default) = never. */
3487
3557
  readonly stackBelow: import("@angular/core").InputSignal<number | null>;
3488
3558
  /** CSS length (e.g. `10.5rem`): horizontal only - the list gets `min-width: calc(<step count> * <value>)`. Empty (default) = no minimum. */
@@ -4111,7 +4181,7 @@ export declare class ButtonComponent {
4111
4181
  * `ghost-start`: a ghost button for list / section toggles - a full-width row with its content aligned to the start, transparent
4112
4182
  * background, hover tint and the normal focus ring. Pair it with `ariaExpanded` / `ariaPressed`; the label may contain a heading element.
4113
4183
  */
4114
- readonly variant: import("@angular/core").InputSignal<"primary" | "secondary" | "danger" | "warning" | "link" | "ghost" | "ghost-start" | "tab" | "icon" | "icon-danger">;
4184
+ readonly variant: import("@angular/core").InputSignal<"link" | "icon" | "warning" | "danger" | "primary" | "secondary" | "ghost" | "ghost-start" | "tab" | "icon-danger">;
4115
4185
  /** Renders an anchor to this route instead of a button (use with `variant="link"` for an inline text link). `['/settings']` or `'/settings'`. While `disabled` or `loading` it renders a non-clickable `<span role="link" aria-disabled>` with no href (like `href`). */
4116
4186
  readonly routerLink: import("@angular/core").InputSignal<string | readonly unknown[] | null>;
4117
4187
  /** Query params of the `routerLink` (e.g. `{ section: 'deal-defaults' }`). */
@@ -4157,7 +4227,7 @@ export declare class ButtonComponent {
4157
4227
  readonly color: import("@angular/core").InputSignal<string | undefined>;
4158
4228
  readonly active: import("@angular/core").InputSignal<boolean>;
4159
4229
  readonly size: import("@angular/core").InputSignal<"sm" | "md" | "lg" | "xs">;
4160
- readonly type: import("@angular/core").InputSignal<"reset" | "submit" | "button">;
4230
+ readonly type: import("@angular/core").InputSignal<"button" | "reset" | "submit">;
4161
4231
  readonly disabled: import("@angular/core").InputSignal<boolean>;
4162
4232
  readonly loading: import("@angular/core").InputSignal<boolean>;
4163
4233
  readonly fullWidth: import("@angular/core").InputSignal<boolean>;
@@ -4608,7 +4678,7 @@ export declare class BulkMessagePanelComponent {
4608
4678
  readonly sending: import("@angular/core").InputSignal<boolean>;
4609
4679
  readonly closed: import("@angular/core").OutputEmitterRef<void>;
4610
4680
  readonly send: import("@angular/core").OutputEmitterRef<BulkMessageSendEvent>;
4611
- readonly channel: import("@angular/core").WritableSignal<"text" | "email">;
4681
+ readonly channel: import("@angular/core").WritableSignal<"email" | "text">;
4612
4682
  private readonly _subject;
4613
4683
  private readonly _body;
4614
4684
  get subject(): string;
@@ -5082,6 +5152,8 @@ export declare class TextInputComponent implements ControlValueAccessor, Validat
5082
5152
  * and `inputTestId="email-input"`. Omitted = no attribute.
5083
5153
  */
5084
5154
  readonly inputTestId: import("@angular/core").InputSignal<string>;
5155
+ /** Native `name` attribute placed on the inner `<input>` (e2e `[name=x]` selectors, browser autofill). None when empty. */
5156
+ readonly inputName: import("@angular/core").InputSignal<string>;
5085
5157
  readonly placeholder: import("@angular/core").InputSignal<string>;
5086
5158
  /**
5087
5159
  * An optional leading mark shown inside the field, left of the text (e.g. `prefix="$"` for a dollar amount). Hidden unless set; it is
@@ -5101,7 +5173,7 @@ export declare class TextInputComponent implements ControlValueAccessor, Validat
5101
5173
  readonly passwordRequirements: import("@angular/core").InputSignal<boolean>;
5102
5174
  /** Rules for `passwordRequirements`; default = the library's five rules (8+ characters, upper, lower, digit, special). */
5103
5175
  readonly passwordRules: import("@angular/core").InputSignal<readonly PasswordRule[] | undefined>;
5104
- readonly type: import("@angular/core").InputSignal<"number" | "text" | "email" | "tel" | "password" | "url">;
5176
+ readonly type: import("@angular/core").InputSignal<"number" | "email" | "text" | "tel" | "password" | "url">;
5105
5177
  readonly maxlength: import("@angular/core").InputSignal<number | undefined>;
5106
5178
  readonly required: import("@angular/core").InputSignal<boolean>;
5107
5179
  readonly autocomplete: import("@angular/core").InputSignal<string>;
@@ -5110,7 +5182,7 @@ export declare class TextInputComponent implements ControlValueAccessor, Validat
5110
5182
  * `search`, `text`, `none`). Empty (default) = the browser's default for the field, except `type="tel"`, which keeps `tel`.
5111
5183
  * It only picks the keyboard; it does not restrict what can be typed or pasted.
5112
5184
  */
5113
- readonly inputmode: import("@angular/core").InputSignal<"" | "none" | "text" | "search" | "email" | "tel" | "url" | "decimal" | "numeric">;
5185
+ readonly inputmode: import("@angular/core").InputSignal<"" | "none" | "email" | "search" | "text" | "numeric" | "tel" | "url" | "decimal">;
5114
5186
  readonly readonly: import("@angular/core").InputSignal<boolean>;
5115
5187
  readonly hint: import("@angular/core").InputSignal<string>;
5116
5188
  /** 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. */
@@ -5176,7 +5248,7 @@ export declare class TextInputComponent implements ControlValueAccessor, Validat
5176
5248
  protected readonly _stepAttr: import("@angular/core").Signal<string | null>;
5177
5249
  protected readonly _revealable: import("@angular/core").Signal<boolean>;
5178
5250
  protected readonly _shown: import("@angular/core").WritableSignal<boolean>;
5179
- protected readonly _inputType: import("@angular/core").Signal<"number" | "text" | "email" | "tel" | "password" | "url">;
5251
+ protected readonly _inputType: import("@angular/core").Signal<"number" | "email" | "text" | "tel" | "password" | "url">;
5180
5252
  protected readonly _eyePath: string;
5181
5253
  protected readonly _eyeOffPath: string;
5182
5254
  protected readonly _showRequirements: import("@angular/core").Signal<boolean>;
@@ -5240,6 +5312,11 @@ export declare class TextInputComponent implements ControlValueAccessor, Validat
5240
5312
  "required": false;
5241
5313
  "isSignal": true;
5242
5314
  };
5315
+ "inputName": {
5316
+ "alias": "inputName";
5317
+ "required": false;
5318
+ "isSignal": true;
5319
+ };
5243
5320
  "placeholder": {
5244
5321
  "alias": "placeholder";
5245
5322
  "required": false;
@@ -6996,7 +7073,7 @@ export declare class FormRowComponent {
6996
7073
  * child simply takes the full width. Keep a numeric span within the row's `cols` (use `all` for the whole row).
6997
7074
  */
6998
7075
  export declare class FormColSpanDirective {
6999
- readonly uiColSpan: import("@angular/core").InputSignal<"" | "2" | "3" | 2 | 3 | "all">;
7076
+ readonly uiColSpan: import("@angular/core").InputSignal<"" | 2 | 3 | "2" | "3" | "all">;
7000
7077
  protected readonly _class: import("@angular/core").Signal<string>;
7001
7078
  static ɵfac: i0.ɵɵFactoryDeclaration<FormColSpanDirective, never>;
7002
7079
  static ɵdir: i0.ɵɵDirectiveDeclaration<FormColSpanDirective, "[uiColSpan]", never, {
@@ -7046,7 +7123,7 @@ export type ListItemDetail = string | {
7046
7123
  export type ListItemIconColor = 'slate' | 'amber' | 'red' | 'blue' | 'green' | 'purple' | 'teal' | 'orange';
7047
7124
  export declare class ListItemComponent {
7048
7125
  /** Show a radio button, checkbox, or nothing on the left. */
7049
- readonly leading: import("@angular/core").InputSignal<"none" | "checkbox" | "radio">;
7126
+ readonly leading: import("@angular/core").InputSignal<"none" | "radio" | "checkbox">;
7050
7127
  /** `name` attribute for the radio/checkbox (groups radios together). */
7051
7128
  readonly inputName: import("@angular/core").InputSignal<string>;
7052
7129
  /** `id` attribute for the radio/checkbox (links the label). */
@@ -8538,7 +8615,7 @@ export declare class IconComponent {
8538
8615
  readonly ariaLabel: import("@angular/core").InputSignal<string>;
8539
8616
  /** Icon size in px. */
8540
8617
  readonly size: import("@angular/core").InputSignal<number>;
8541
- readonly variant: import("@angular/core").InputSignal<"danger" | "default">;
8618
+ readonly variant: import("@angular/core").InputSignal<"default" | "danger">;
8542
8619
  readonly disabled: import("@angular/core").InputSignal<boolean>;
8543
8620
  /** The host is running the request this icon started: a spinner replaces the picture and the button is disabled (no click) until it is false again. */
8544
8621
  readonly loading: import("@angular/core").InputSignal<boolean>;
@@ -8650,7 +8727,7 @@ export declare class TimelineComponent {
8650
8727
  /** Any CSS length (e.g. `600px`). When set, the list scrolls inside a keyboard-focusable region of at most this height. Empty = no wrapper. */
8651
8728
  readonly maxHeight: import("@angular/core").InputSignal<string>;
8652
8729
  /** `below` (default): the time is under the title / description. `end`: the time sits right-aligned on the title row. */
8653
- readonly timePosition: import("@angular/core").InputSignal<"end" | "below">;
8730
+ readonly timePosition: import("@angular/core").InputSignal<"below" | "end">;
8654
8731
  /**
8655
8732
  * Group the items under a heading per calendar day of `dateTime` ("Today", "Yesterday", "Oct 3", "Oct 3, 2025"). Default false = no headings,
8656
8733
  * DOM unchanged. The given order is kept: consecutive items of one day share a heading, the same day appearing again later starts a new group.
@@ -8731,6 +8808,341 @@ export declare class HintComponent {
8731
8808
  static ɵfac: i0.ɵɵFactoryDeclaration<HintComponent, never>;
8732
8809
  static ɵcmp: i0.ɵɵComponentDeclaration<HintComponent, "ui-hint", never, {}, {}, never, ["*"], true, never>;
8733
8810
  }
8811
+ /**
8812
+ * The value of `ui-address-input`: five plain strings (never null). `apt` is the second line (apartment / suite / unit).
8813
+ *
8814
+ * Note: the library already exports `formatAddress(parts, options)` / `AddressParts` (utils/format) for display of an address with
8815
+ * city / state / zip parts. The helpers below work on this value model and are therefore named `...AddressValue`.
8816
+ */
8817
+ export interface AddressValue {
8818
+ street: string;
8819
+ apt: string;
8820
+ city: string;
8821
+ state: string;
8822
+ zip: string;
8823
+ }
8824
+ /** The 50 US states + DC as select options: value = 2-letter code, label = the code (compact, fits the narrow State column), description = the state name (read by screen readers, shown under the select). */
8825
+ export declare const US_STATE_OPTIONS: readonly SelectOption[];
8826
+ /** A fresh blank address. */
8827
+ export declare function emptyAddress(): AddressValue;
8828
+ /** Coerces anything (null, a partial object, non-string members) to a complete `AddressValue` of strings. */
8829
+ export declare function normalizeAddress(v: Partial<Record<keyof AddressValue, unknown>> | null | undefined): AddressValue;
8830
+ /** True when every part is empty or whitespace (null / undefined count as empty). */
8831
+ export declare function isEmptyAddress(a: Partial<Record<keyof AddressValue, unknown>> | null | undefined): boolean;
8832
+ /** The default ZIP rule of the component: US 5 digits or 5+4. */
8833
+ export declare const US_ZIP_PATTERN: RegExp;
8834
+ /**
8835
+ * Multi-line text, the storage form used by apps: street, apt, then "City, ST 12345", joined with "\n". Every part is trimmed and empty
8836
+ * parts are left out, so `parseAddressValue(formatAddressValue(x))` is stable.
8837
+ * `{street:'1 Main', apt:'Apt 4', city:'Austin', state:'TX', zip:'78701'}` -> `"1 Main\nApt 4\nAustin, TX 78701"`.
8838
+ */
8839
+ export declare function formatAddressValue(a: AddressValue | null | undefined): string;
8840
+ /**
8841
+ * The same address on ONE line for tables, labels and maps: "1 Main, Apt 4, Austin, TX 78701". `{ comma: false }` drops the comma between
8842
+ * city and state ("1 Main, Apt 4, Austin TX 78701", the older mfh resident style). Empty parts are left out.
8843
+ */
8844
+ export declare function formatAddressValueOneLine(a: AddressValue | null | undefined, options?: {
8845
+ comma?: boolean;
8846
+ }): string;
8847
+ /**
8848
+ * Reads the multi-line text form back into an address (the inverse of `formatAddressValue`; never throws).
8849
+ * - null / undefined / blank -> empty address.
8850
+ * - 1 line: the street only (`parseAddressOneLine` reads the one-line form).
8851
+ * - 2 lines: street + city line. 3 lines: street + apt + city line.
8852
+ * - 4+ lines: first = street, last = city line, everything in between = apt (joined with ", ").
8853
+ * - The city line may be "City, ST 12345", "City ST 12345", "City, ST 12345-6789", "city, st 12345" (any case with a comma), "City, ST",
8854
+ * "TX 78701" (city blank), with a trailing comma / period / semicolon tolerated. The state is two letters (capitals unless a comma
8855
+ * separates it), the ZIP 5 digits or 5+4. Anything else (a city only, a full state name, a 4-digit or foreign postcode, a unit line
8856
+ * without a city line) lands WHOLE in `city` - nothing is dropped.
8857
+ * - Lines are trimmed, blank lines dropped, \r\n accepted.
8858
+ */
8859
+ export declare function parseAddressValue(raw: string | null | undefined): AddressValue;
8860
+ /**
8861
+ * Reads the ONE-LINE form that `formatAddressValueOneLine` writes ("street[, apt], city, ST 12345", or "..., city ST 12345" without the
8862
+ * comma). Segments are split at commas: the last one carries "ST 12345" (and the city when there is no comma before the state), the city
8863
+ * is the segment before it, the first remaining segment is the street and the rest the apt. A street that itself contains a comma
8864
+ * ("Bldg 2, 100 Main St") therefore splits into street + apt. Text that does not end in "ST 12345" becomes the street whole.
8865
+ */
8866
+ export declare function parseAddressOneLine(raw: string | null | undefined): AddressValue;
8867
+ /** 5 digits or 5+4 ("12345", "12345-6789"); surrounding spaces are NOT accepted (trim first). */
8868
+ export declare function isValidZip(zip: string): boolean;
8869
+ type AddressField = keyof AddressValue;
8870
+ /**
8871
+ * Address entry (ControlValueAccessor): street, unit, city, state (select) and ZIP, built only from library inputs.
8872
+ *
8873
+ * Value: `AddressValue` ({ street, apt, city, state, zip }, all strings). Works with `[(ngModel)]`, `[formControl]`, or a signal via
8874
+ * `[value]` / `(valueChange)`. A written `null` / `undefined` clears the form; a written string is read with `parseAddressValue`.
8875
+ * Writing a value never emits; only user edits emit (the whole new `AddressValue`).
8876
+ *
8877
+ * Built-in validation (also reported on the form control as a `Validator`; `invalid` / `errorMessage` signals, `invalidChange` output,
8878
+ * provides `UiFieldValidity`): `required` -> street, city, state and ZIP are required ("<Field label> is required."); ZIP must be
8879
+ * 5 digits or 5+4 ("Enter a valid ZIP code."); state must be one of the options ("Select a valid option."); maxlengths
8880
+ * ("Too long (max N characters)."); `requireComplete` -> once ANY of street / city / state / ZIP is filled the others are required too
8881
+ * (for an optional address that must not be half-filled). The unit is never required. Messages show per field after that field was left,
8882
+ * or all at once while `showErrors` is true; the host `error` is shown under the group and always counts as invalid.
8883
+ *
8884
+ * Layout: street + unit, then city + state + ZIP in `ui-form-row`s (they collapse to one column on phones).
8885
+ */
8886
+ export declare class AddressInputComponent implements ControlValueAccessor, Validator, UiFieldValidity {
8887
+ /** Group label (the visible legend and the group's accessible name). Empty -> no legend, the group is named "Address". */
8888
+ readonly label: import("@angular/core").InputSignal<string>;
8889
+ /** Street, city, state and ZIP are required (never the unit). Shows `*` on the legend and on those fields. */
8890
+ readonly required: import("@angular/core").InputSignal<boolean>;
8891
+ /** Optional address that must not be half-filled: when any of street / city / state / ZIP has text, the other three are required. */
8892
+ readonly requireComplete: import("@angular/core").InputSignal<boolean>;
8893
+ readonly streetLabel: import("@angular/core").InputSignal<string>;
8894
+ readonly unitLabel: import("@angular/core").InputSignal<string>;
8895
+ readonly cityLabel: import("@angular/core").InputSignal<string>;
8896
+ readonly stateLabel: import("@angular/core").InputSignal<string>;
8897
+ readonly zipLabel: import("@angular/core").InputSignal<string>;
8898
+ readonly streetPlaceholder: import("@angular/core").InputSignal<string>;
8899
+ readonly unitPlaceholder: import("@angular/core").InputSignal<string>;
8900
+ readonly cityPlaceholder: import("@angular/core").InputSignal<string>;
8901
+ readonly zipPlaceholder: import("@angular/core").InputSignal<string>;
8902
+ /** Text of the empty State option (the one that clears the state). */
8903
+ readonly statePlaceholder: import("@angular/core").InputSignal<string>;
8904
+ /** Show the Apt / Suite field. Hidden -> the value's `apt` is kept as written and never edited. */
8905
+ readonly showUnit: import("@angular/core").InputSignal<boolean>;
8906
+ /** State choices (value = what is stored). Default: the 50 US states + DC by code. An empty "no state" option is added in front when missing. */
8907
+ readonly states: import("@angular/core").InputSignal<readonly SelectOption<string>[]>;
8908
+ readonly streetMaxlength: import("@angular/core").InputSignal<number>;
8909
+ readonly unitMaxlength: import("@angular/core").InputSignal<number>;
8910
+ readonly cityMaxlength: import("@angular/core").InputSignal<number>;
8911
+ readonly zipMaxlength: import("@angular/core").InputSignal<number>;
8912
+ /** Native select cannot be read-only: while `readonly`, the State select is disabled and the text fields are read-only. */
8913
+ readonly readonly: import("@angular/core").InputSignal<boolean>;
8914
+ /** Reveal every built-in message now (e.g. after a failed Save click). Switching back to false forgets which fields were left. */
8915
+ readonly showErrors: import("@angular/core").InputSignal<boolean>;
8916
+ readonly hint: import("@angular/core").InputSignal<string>;
8917
+ /** Host error for the whole address; shown under the group (replaces the hint), always makes the field invalid. */
8918
+ readonly error: import("@angular/core").InputSignal<string>;
8919
+ /** Prefix of the per-field test ids and native names: `<prefix>street`, `<prefix>apt`, `<prefix>city`, `<prefix>state`, `<prefix>zip` (and `<prefix>group`). */
8920
+ readonly idPrefix: import("@angular/core").InputSignal<string>;
8921
+ /** Alias of `idPrefix` (the name the old app-level address input used). When set (even to ''), it wins over `idPrefix`. */
8922
+ readonly prefix: import("@angular/core").InputSignal<string | undefined>;
8923
+ /**
8924
+ * What the form control (ngModel / FormControl) receives. 'auto' (default): the type last written to it - a string model gets the multi-line
8925
+ * string (`formatAddressValue`), an object / null / never-written model gets the `AddressValue`; 'text': always the string; 'object': always
8926
+ * the object. `valueChange` always emits the object. A written string is read with `parseAddressValue` for display only: the control keeps
8927
+ * the original text until the user edits a field (so a text the parser cannot split is not rewritten on load).
8928
+ */
8929
+ readonly valueFormat: import("@angular/core").InputSignal<"object" | "text" | "auto">;
8930
+ /** ZIP rule; the default is the US 5 digits / 5+4 rule. `null` accepts any non-empty ZIP. The ZIP is validated and stored trimmed. */
8931
+ readonly zipPattern: import("@angular/core").InputSignal<RegExp | null>;
8932
+ /** Message shown when the ZIP breaks `zipPattern`. */
8933
+ readonly zipError: import("@angular/core").InputSignal<string>;
8934
+ /** Signal-style value (use with `(valueChange)` or `[(value)]`); not needed with ngModel / FormControl. null / undefined = blank. */
8935
+ readonly value: import("@angular/core").InputSignal<string | AddressValue | null | undefined>;
8936
+ /** The `[disabled]` input (also set by the form control through `setDisabledState`). Public so `[disabled]="x"` type-checks in hosts. */
8937
+ readonly _disabledInput: import("@angular/core").InputSignal<boolean>;
8938
+ /** Emits the whole new address when the USER edits a field. Not emitted for written values. */
8939
+ readonly valueChange: import("@angular/core").OutputEmitterRef<AddressValue>;
8940
+ /** Emits whenever the address becomes invalid / valid. */
8941
+ readonly invalidChange: import("@angular/core").OutputEmitterRef<boolean>;
8942
+ private readonly host;
8943
+ private readonly _cvaDisabled;
8944
+ protected readonly disabled: import("@angular/core").Signal<boolean>;
8945
+ protected readonly _v: import("@angular/core").WritableSignal<AddressValue>;
8946
+ private readonly _touched;
8947
+ protected readonly _standalone: {
8948
+ standalone: boolean;
8949
+ };
8950
+ protected readonly _p: import("@angular/core").Signal<string>;
8951
+ private readonly _uid;
8952
+ protected readonly _legendId: string;
8953
+ protected readonly _errorId: string;
8954
+ protected readonly _hintId: string;
8955
+ protected readonly _stateOptions: import("@angular/core").Signal<SelectOption<string>[]>;
8956
+ private readonly _issues;
8957
+ /** True while the address breaks a built-in rule or the host passed an `[error]`. */
8958
+ readonly invalid: import("@angular/core").Signal<boolean>;
8959
+ /** Message of the first broken built-in rule in field order ('' when valid), shown or not. */
8960
+ readonly errorMessage: import("@angular/core").Signal<string>;
8961
+ /** Street, city, state and ZIP are required: always with `required`, and with `requireComplete` once any of them has text. */
8962
+ protected readonly _req: import("@angular/core").Signal<boolean>;
8963
+ protected readonly _describedBy: import("@angular/core").Signal<string | null>;
8964
+ private _onChange;
8965
+ /** True once a string was written to the control (valueFormat 'auto' then emits strings). */
8966
+ private _textModel;
8967
+ /** Fields whose text the USER changed since the last write; only those are trimmed when left. */
8968
+ private readonly _edited;
8969
+ private _onTouched;
8970
+ private _onValidatorChange;
8971
+ constructor();
8972
+ /** Re-run the form control's validation when a rule input (required, maxlength, states, ...) changes. */
8973
+ ngOnChanges(): void;
8974
+ writeValue(val: AddressValue | string | null | undefined): void;
8975
+ registerOnChange(fn: (v: AddressValue | string) => void): void;
8976
+ registerOnTouched(fn: () => void): void;
8977
+ setDisabledState(d: boolean): void;
8978
+ registerOnValidatorChange(fn: () => void): void;
8979
+ validate(control: AbstractControl): ValidationErrors | null;
8980
+ protected _set(field: AddressField, text: unknown): void;
8981
+ protected _onFocusOut(field: AddressField, event: FocusEvent): void;
8982
+ /** True while the field's own message may show: `showErrors`, or the field was left. Bound to the child's `showErrors` so a reset clears the child too. */
8983
+ protected _revealed(field: AddressField): boolean;
8984
+ protected _fieldError(field: AddressField): string;
8985
+ private _hasText;
8986
+ private _firstIssue;
8987
+ private _check;
8988
+ private _zipOk;
8989
+ static ɵfac: i0.ɵɵFactoryDeclaration<AddressInputComponent, never>;
8990
+ static ɵcmp: i0.ɵɵComponentDeclaration<AddressInputComponent, "ui-address-input", never, {
8991
+ "label": {
8992
+ "alias": "label";
8993
+ "required": false;
8994
+ "isSignal": true;
8995
+ };
8996
+ "required": {
8997
+ "alias": "required";
8998
+ "required": false;
8999
+ "isSignal": true;
9000
+ };
9001
+ "requireComplete": {
9002
+ "alias": "requireComplete";
9003
+ "required": false;
9004
+ "isSignal": true;
9005
+ };
9006
+ "streetLabel": {
9007
+ "alias": "streetLabel";
9008
+ "required": false;
9009
+ "isSignal": true;
9010
+ };
9011
+ "unitLabel": {
9012
+ "alias": "unitLabel";
9013
+ "required": false;
9014
+ "isSignal": true;
9015
+ };
9016
+ "cityLabel": {
9017
+ "alias": "cityLabel";
9018
+ "required": false;
9019
+ "isSignal": true;
9020
+ };
9021
+ "stateLabel": {
9022
+ "alias": "stateLabel";
9023
+ "required": false;
9024
+ "isSignal": true;
9025
+ };
9026
+ "zipLabel": {
9027
+ "alias": "zipLabel";
9028
+ "required": false;
9029
+ "isSignal": true;
9030
+ };
9031
+ "streetPlaceholder": {
9032
+ "alias": "streetPlaceholder";
9033
+ "required": false;
9034
+ "isSignal": true;
9035
+ };
9036
+ "unitPlaceholder": {
9037
+ "alias": "unitPlaceholder";
9038
+ "required": false;
9039
+ "isSignal": true;
9040
+ };
9041
+ "cityPlaceholder": {
9042
+ "alias": "cityPlaceholder";
9043
+ "required": false;
9044
+ "isSignal": true;
9045
+ };
9046
+ "zipPlaceholder": {
9047
+ "alias": "zipPlaceholder";
9048
+ "required": false;
9049
+ "isSignal": true;
9050
+ };
9051
+ "statePlaceholder": {
9052
+ "alias": "statePlaceholder";
9053
+ "required": false;
9054
+ "isSignal": true;
9055
+ };
9056
+ "showUnit": {
9057
+ "alias": "showUnit";
9058
+ "required": false;
9059
+ "isSignal": true;
9060
+ };
9061
+ "states": {
9062
+ "alias": "states";
9063
+ "required": false;
9064
+ "isSignal": true;
9065
+ };
9066
+ "streetMaxlength": {
9067
+ "alias": "streetMaxlength";
9068
+ "required": false;
9069
+ "isSignal": true;
9070
+ };
9071
+ "unitMaxlength": {
9072
+ "alias": "unitMaxlength";
9073
+ "required": false;
9074
+ "isSignal": true;
9075
+ };
9076
+ "cityMaxlength": {
9077
+ "alias": "cityMaxlength";
9078
+ "required": false;
9079
+ "isSignal": true;
9080
+ };
9081
+ "zipMaxlength": {
9082
+ "alias": "zipMaxlength";
9083
+ "required": false;
9084
+ "isSignal": true;
9085
+ };
9086
+ "readonly": {
9087
+ "alias": "readonly";
9088
+ "required": false;
9089
+ "isSignal": true;
9090
+ };
9091
+ "showErrors": {
9092
+ "alias": "showErrors";
9093
+ "required": false;
9094
+ "isSignal": true;
9095
+ };
9096
+ "hint": {
9097
+ "alias": "hint";
9098
+ "required": false;
9099
+ "isSignal": true;
9100
+ };
9101
+ "error": {
9102
+ "alias": "error";
9103
+ "required": false;
9104
+ "isSignal": true;
9105
+ };
9106
+ "idPrefix": {
9107
+ "alias": "idPrefix";
9108
+ "required": false;
9109
+ "isSignal": true;
9110
+ };
9111
+ "prefix": {
9112
+ "alias": "prefix";
9113
+ "required": false;
9114
+ "isSignal": true;
9115
+ };
9116
+ "valueFormat": {
9117
+ "alias": "valueFormat";
9118
+ "required": false;
9119
+ "isSignal": true;
9120
+ };
9121
+ "zipPattern": {
9122
+ "alias": "zipPattern";
9123
+ "required": false;
9124
+ "isSignal": true;
9125
+ };
9126
+ "zipError": {
9127
+ "alias": "zipError";
9128
+ "required": false;
9129
+ "isSignal": true;
9130
+ };
9131
+ "value": {
9132
+ "alias": "value";
9133
+ "required": false;
9134
+ "isSignal": true;
9135
+ };
9136
+ "_disabledInput": {
9137
+ "alias": "disabled";
9138
+ "required": false;
9139
+ "isSignal": true;
9140
+ };
9141
+ }, {
9142
+ "valueChange": "valueChange";
9143
+ "invalidChange": "invalidChange";
9144
+ }, never, never, true, never>;
9145
+ }
8734
9146
  export type ImagePreviewShape = 'circle' | 'rounded';
8735
9147
  export type ImagePreviewSize = 'sm' | 'md' | 'lg';
8736
9148
  export type ImagePreviewPlaceholder = 'person' | 'image';
@@ -10005,7 +10417,7 @@ export declare class PdfHotspotComponent {
10005
10417
  /** `ready`: clickable; `blocked`: disabled (a prerequisite is missing); `signed`: shows `image`. */
10006
10418
  readonly state: import("@angular/core").InputSignal<"ready" | "blocked" | "signed">;
10007
10419
  /** `warning` gives the ready state an amber look (e.g. for initials), default is blue. */
10008
- readonly tone: import("@angular/core").InputSignal<"primary" | "warning">;
10420
+ readonly tone: import("@angular/core").InputSignal<"warning" | "primary">;
10009
10421
  /** Text of the ready button (e.g. "Sign Here"). */
10010
10422
  readonly label: import("@angular/core").InputSignal<string>;
10011
10423
  /** Text of the blocked button (e.g. "Add signature above"). */
@@ -12322,6 +12734,12 @@ export declare function todayInTimezone(timezone?: string | null): string;
12322
12734
  * download). A no-op without a DOM (server-side rendering).
12323
12735
  */
12324
12736
  export declare function downloadBlob(blob: Blob, fileName: string): void;
12737
+ /**
12738
+ * The file name of a `Content-Disposition` header (`attachment; filename="a.zip"`, `filename=a.zip` or the encoded `filename*=UTF-8''a%20b.zip`),
12739
+ * or '' when the header is missing or names no file. Path separators and leading dots are removed so a server name can never point outside the
12740
+ * downloads folder.
12741
+ */
12742
+ export declare function fileNameFromContentDisposition(header: string | null | undefined): string;
12325
12743
  /**
12326
12744
  * A lightbox: a `ui-modal` that shows a `ui-image-gallery` with a Close button in the footer.
12327
12745
  *
@@ -14550,4 +14968,601 @@ export declare class ConversationsComponent {
14550
14968
  "messagesRetry": "messagesRetry";
14551
14969
  }, never, ["[uiConversationsContext]"], true, never>;
14552
14970
  }
14553
- export type { CalendarAgendaGroup, CalendarDay, CalendarDayLevel, CalendarRange, CalendarViewMode };
14971
+ /**
14972
+ * Types and pure helpers of `ui-payment-side-panel`. Nothing here knows a payment processor: Stripe / Square arrive as plugins
14973
+ * (`PaymentMethodPlugin`), the card-present terminal as host callbacks.
14974
+ */
14975
+ /** Well-known method values the panel gives behaviour to. Hosts may list any other value (it is recorded like Cash). */
14976
+ export declare const PAYMENT_METHOD: {
14977
+ readonly CARD: "CARD";
14978
+ readonly ACH: "ACH";
14979
+ readonly CASH: "CASH";
14980
+ readonly CHECK: "CHECK";
14981
+ readonly MONEY_ORDER: "MONEY_ORDER";
14982
+ readonly CARD_PRESENT: "CARD_PRESENT";
14983
+ };
14984
+ interface PaymentMethodOption {
14985
+ value: string;
14986
+ label: string;
14987
+ /** `'terminal'`: listed only while the host gave the terminal callbacks (`listReaders` + `startTerminalPayment`). */
14988
+ requires?: 'terminal';
14989
+ }
14990
+ /** The methods listed when the host gives none: Card and ACH are record-only until a processor plugin takes them over. */
14991
+ export declare const DEFAULT_PAYMENT_METHODS: readonly PaymentMethodOption[];
14992
+ interface PayableCharge {
14993
+ id: string;
14994
+ chargeType: string;
14995
+ description: string;
14996
+ /** ISO date `YYYY-MM-DD`. */
14997
+ dueDate: string;
14998
+ balanceDue: number;
14999
+ }
15000
+ interface SavedPaymentMethod {
15001
+ method: string;
15002
+ last4: string;
15003
+ label?: string;
15004
+ }
15005
+ interface AllocationModeOption {
15006
+ value: string;
15007
+ label: string;
15008
+ }
15009
+ export declare const ALLOCATION_CUSTOM = "custom";
15010
+ export declare const DEFAULT_ALLOCATION_MODES: readonly AllocationModeOption[];
15011
+ interface ChargeAllocation {
15012
+ chargeId: string;
15013
+ amount: number;
15014
+ }
15015
+ /**
15016
+ * How the payment is applied to charges. A non-custom mode sends `{ allocationMode }`. "Choose charges" sends `{ allocationChargeIds, allocations }`
15017
+ * (no `allocationMode`, like the old drawer); `allocations` carries the amount per charge.
15018
+ */
15019
+ interface PaymentAllocation {
15020
+ allocationMode?: string;
15021
+ allocationChargeIds?: string[];
15022
+ allocations?: ChargeAllocation[];
15023
+ }
15024
+ interface PaymentEntry {
15025
+ paymentMethod: string;
15026
+ amount: number;
15027
+ /** Check number / last 4 digits; `null` when the method has none. */
15028
+ reference: string | null;
15029
+ /** The receipt checkbox applies to the LAST entry only (like the old drawer); earlier split entries are `false`. */
15030
+ sendReceipt: boolean;
15031
+ }
15032
+ interface RecordPaymentPayload extends PaymentAllocation {
15033
+ /** Total of all entries. */
15034
+ amount: number;
15035
+ /** The method of a single payment, `'SPLIT'` when `split`. */
15036
+ paymentMethod: string;
15037
+ receivedDate: string;
15038
+ /** Reference of the single payment (`null` for a split: see `entries`). */
15039
+ reference: string | null;
15040
+ notes: string | null;
15041
+ sendReceipt: boolean;
15042
+ /** One per payment to create (the host posts one request per entry, or one request with all). */
15043
+ entries: PaymentEntry[];
15044
+ split: boolean;
15045
+ }
15046
+ interface RecordPaymentResult {
15047
+ type: 'manual' | 'stripe' | 'split';
15048
+ paymentMethod: string;
15049
+ amount: number;
15050
+ }
15051
+ /** What the panel reports for the host to word (toasts, analytics). It never toasts itself. */
15052
+ type PaymentPanelOutcome = {
15053
+ kind: 'recorded';
15054
+ result: RecordPaymentResult;
15055
+ } | {
15056
+ kind: 'split-recorded';
15057
+ result: RecordPaymentResult;
15058
+ } | {
15059
+ kind: 'terminal-paid';
15060
+ result: RecordPaymentResult;
15061
+ } | {
15062
+ kind: 'plugin';
15063
+ method: string;
15064
+ code: string;
15065
+ result?: RecordPaymentResult;
15066
+ message?: string;
15067
+ } | {
15068
+ kind: 'failed';
15069
+ stage: 'record' | 'readers' | 'terminal';
15070
+ message: string;
15071
+ };
15072
+ type HostResult<T> = Observable<T> | Promise<T> | T;
15073
+ type RecordPaymentFn = (payload: RecordPaymentPayload) => HostResult<unknown>;
15074
+ interface TerminalReader {
15075
+ id: string;
15076
+ label?: string;
15077
+ status: string;
15078
+ deviceType?: string;
15079
+ }
15080
+ interface TerminalStartContext extends PaymentAllocation {
15081
+ readerId: string;
15082
+ amount: number;
15083
+ receivedDate: string;
15084
+ notes: string | null;
15085
+ }
15086
+ interface TerminalStartResult {
15087
+ paymentIntentId: string;
15088
+ }
15089
+ interface TerminalStatusResult {
15090
+ status: string;
15091
+ }
15092
+ interface TerminalConfirmContext extends TerminalStartContext {
15093
+ paymentIntentId: string;
15094
+ }
15095
+ type TerminalPhase = 'idle' | 'waiting' | 'confirming' | 'success';
15096
+ /** Reader statuses that end the wait. */
15097
+ export declare function terminalVerdict(status: string | null | undefined): 'succeeded' | 'canceled' | 'declined' | 'pending';
15098
+ export declare function terminalTimeoutText(ms: number): string;
15099
+ export declare const MIN_PAYMENT_AMOUNT = 0.01;
15100
+ export declare const MAX_PAYMENT_AMOUNT = 99999.99;
15101
+ declare const toCents: (value: number) => number;
15102
+ declare const fromCents: (cents: number) => number;
15103
+ declare const roundMoney: (value: number) => number;
15104
+ /** A payable amount: a finite number from 0.01 to `max` with at most two decimals. */
15105
+ export declare function isValidAmount(value: unknown, max?: number): value is number;
15106
+ declare function sumMoney(values: readonly number[]): number;
15107
+ declare function referenceKind(method: string, live: boolean): 'check' | 'last4-card' | 'last4-account' | null;
15108
+ /** The last-4 box accepts digits only (blank is fine). */
15109
+ export declare function last4Error(value: string): string;
15110
+ declare function last4Digits(value: string, max?: number): string;
15111
+ interface AllocationCheck {
15112
+ general: string;
15113
+ perCharge: Record<string, string>;
15114
+ }
15115
+ type SelectedCharges = Record<string, number | null>;
15116
+ declare function allocationCheck(charges: readonly PayableCharge[], selected: SelectedCharges, totalPayment: number | null, format: (n: number) => string): AllocationCheck;
15117
+ /** The amount to propose when a charge is ticked: its balance, capped by what is left of the payment. */
15118
+ declare function defaultChargeAmount(charge: PayableCharge, selected: SelectedCharges, totalPayment: number | null): number | null;
15119
+ declare function buildAllocation(mode: string, charges: readonly PayableCharge[], selected: SelectedCharges): PaymentAllocation;
15120
+ /** "2026-11-03" -> "Nov 3, 2026" without `Date` string parsing (Safari-safe, time-zone independent). */
15121
+ declare function formatDueDate(iso: string, locale?: string): string;
15122
+ /** Runs a host callback that may return an Observable, a Promise or a value; a synchronous throw becomes a rejection. */
15123
+ export declare function callHost<T>(thunk: () => HostResult<T>): Promise<T>;
15124
+ /** The text of a failed host call: its HTTP body message, its message, else the fallback. */
15125
+ export declare function hostErrorMessage(err: unknown, fallback: string): string;
15126
+ /** A method a plugin contributes to the panel's method select (while the plugin is rendered inside the panel). */
15127
+ export interface PaymentPluginMethod {
15128
+ value: string;
15129
+ label: string;
15130
+ }
15131
+ /** The footer button a plugin body may ask the panel to show instead of the panel's own (the panel's own button is hidden for plugin methods). */
15132
+ export interface PaymentPluginPrimary {
15133
+ label: string;
15134
+ disabled?: boolean;
15135
+ loading?: boolean;
15136
+ onClick: () => void;
15137
+ }
15138
+ /**
15139
+ * What the panel hands to a plugin body (`<ng-template let-ctx>`). The values are a snapshot that is replaced whenever the form changes (read them in the
15140
+ * template or in an `input()` of a child component); the functions are stable.
15141
+ */
15142
+ export interface PaymentMethodContext {
15143
+ /** The selected method value (one of the plugin's `methods`). */
15144
+ readonly method: string;
15145
+ /** The entered amount, or `null` while it is empty or invalid (a plugin should not start a charge without it). */
15146
+ readonly amount: number | null;
15147
+ /** ISO date the payment was received. */
15148
+ readonly receivedDate: string;
15149
+ readonly note: string;
15150
+ /** How the payment is applied to charges (same shape the manual payload carries). */
15151
+ readonly allocation: PaymentAllocation;
15152
+ /** ISO 4217 code of the panel (`'USD'`). */
15153
+ readonly currency: string;
15154
+ /** Every field of the panel is valid (amount, date, note, allocation). */
15155
+ readonly valid: boolean;
15156
+ /** Reveals the panel's field errors (as a failed Save click does) and returns whether the form is valid. Call it before starting a charge. */
15157
+ validate(): boolean;
15158
+ /** Clears the whole form (method, amount, note, split, allocation; the date returns to today). */
15159
+ reset(): void;
15160
+ /** The payment is done: the panel reports it (`outcome` kind `'plugin'`, code `'complete'`, then `recorded`). Defaults: type `'manual'`, the selected method, the entered amount. Runs once. */
15161
+ complete(result?: Partial<RecordPaymentResult>): void;
15162
+ /** A flow is running: the fields are locked and the method cannot be changed. */
15163
+ setBusy(busy: boolean): void;
15164
+ /** The plugin's own footer button (e.g. "Pay $120.00"); `null` removes it. The panel's own Save button never shows for a plugin method. */
15165
+ setPrimary(button: PaymentPluginPrimary | null): void;
15166
+ /** Hide the panel's fields and show only the plugin body (e.g. a "payment submitted" notice). */
15167
+ setExclusive(on: boolean): void;
15168
+ /** Called when the body is about to go away unfinished: the panel closes, the method changes, or the plugin is removed. Not called after `complete()`. */
15169
+ onCancel(fn: (() => void) | null): void;
15170
+ /** Tell the host something happened (`outcome` kind `'plugin'`) so it can word a toast. */
15171
+ report(code: string, extra?: {
15172
+ result?: RecordPaymentResult;
15173
+ message?: string;
15174
+ }): void;
15175
+ /** Text for the panel's screen-reader status region. */
15176
+ announce(text: string): void;
15177
+ }
15178
+ export interface PaymentMethodBodyContext {
15179
+ $implicit: PaymentMethodContext;
15180
+ }
15181
+ /**
15182
+ * The contract of a payment plugin: a child element of `<ui-payment-side-panel>` that contributes live methods (Stripe, Square, ...).
15183
+ * The panel finds plugins with `contentChildren(PAYMENT_METHOD_PLUGIN)`, so presence IS the opt-in; remove the element and its methods leave the select.
15184
+ * A plugin whose method value is `CARD` or `ACH` replaces the record-only behaviour (last 4 digits) of that value while it is rendered.
15185
+ */
15186
+ export declare abstract class PaymentMethodPlugin {
15187
+ abstract readonly methods: Signal<readonly PaymentPluginMethod[]>;
15188
+ /** The body shown under the form while one of the plugin's methods is selected. */
15189
+ abstract readonly template: Signal<TemplateRef<PaymentMethodBodyContext> | undefined>;
15190
+ }
15191
+ export declare const PAYMENT_METHOD_PLUGIN: InjectionToken<PaymentMethodPlugin>;
15192
+ /**
15193
+ * The generic payment plugin: the host renders the body of a method it built itself (Square Web SDK, a gateway widget, ...).
15194
+ *
15195
+ * <ui-payment-side-panel ...>
15196
+ * <ui-payment-custom-method value="CARD" label="Card">
15197
+ * <ng-template let-ctx> <my-square-card [amount]="ctx.amount" (paid)="ctx.complete({ type: 'stripe' })" /> </ng-template>
15198
+ * </ui-payment-custom-method>
15199
+ * </ui-payment-side-panel>
15200
+ */
15201
+ export declare class PaymentCustomMethodComponent extends PaymentMethodPlugin {
15202
+ readonly value: import("@angular/core").InputSignal<string>;
15203
+ readonly label: import("@angular/core").InputSignal<string>;
15204
+ private readonly body;
15205
+ readonly methods: import("@angular/core").Signal<readonly PaymentPluginMethod[]>;
15206
+ readonly template: import("@angular/core").Signal<TemplateRef<PaymentMethodBodyContext> | undefined>;
15207
+ static ɵfac: i0.ɵɵFactoryDeclaration<PaymentCustomMethodComponent, never>;
15208
+ static ɵcmp: i0.ɵɵComponentDeclaration<PaymentCustomMethodComponent, "ui-payment-custom-method", never, {
15209
+ "value": {
15210
+ "alias": "value";
15211
+ "required": true;
15212
+ "isSignal": true;
15213
+ };
15214
+ "label": {
15215
+ "alias": "label";
15216
+ "required": true;
15217
+ "isSignal": true;
15218
+ };
15219
+ }, {}, ["body"], never, true, never>;
15220
+ }
15221
+ interface SplitEntry {
15222
+ method: string;
15223
+ amount: number;
15224
+ reference: string;
15225
+ }
15226
+ /**
15227
+ * Side panel for staff to RECORD or COLLECT a payment. Works on its own (record-only: Cash, Check, Money Order, Card and ACH with the last 4 digits) and grows
15228
+ * by PLUGINS the host drops in as child elements (`ui-payment-stripe-method` from `@forgeroute/ui/stripe`, `ui-payment-custom-method` for Square or any widget):
15229
+ * a plugin's presence IS the opt-in, and a plugin method with the value `CARD` / `ACH` replaces the record-only behaviour while it is rendered.
15230
+ * The panel has no HTTP and no processor knowledge: the host gives callbacks (`recordPayment`, the terminal calls) and words the `outcome` events.
15231
+ *
15232
+ * <ui-payment-side-panel [open]="open()" [today]="today()" [outstandingBalance]="due()" [charges]="charges()"
15233
+ * [recordPayment]="record" (recorded)="onRecorded($event)" (closed)="open.set(false)" />
15234
+ *
15235
+ * See docs/payment-side-panel.md.
15236
+ */
15237
+ export declare class PaymentSidePanelComponent {
15238
+ private readonly injector;
15239
+ private readonly hostEl;
15240
+ protected readonly ids: string;
15241
+ protected readonly customMode = "custom";
15242
+ readonly open: import("@angular/core").InputSignal<boolean>;
15243
+ readonly title: import("@angular/core").InputSignal<string>;
15244
+ readonly subtitle: import("@angular/core").InputSignal<string>;
15245
+ /** Today as `YYYY-MM-DD` (the host's clock/time zone): the default Received Date. The panel never builds dates itself. */
15246
+ readonly today: import("@angular/core").InputSignal<string>;
15247
+ /** When > 0 a banner shows it and the amount starts at this balance. */
15248
+ readonly outstandingBalance: import("@angular/core").InputSignal<number | null>;
15249
+ /** ISO 4217 code used for every amount shown. */
15250
+ readonly currency: import("@angular/core").InputSignal<string>;
15251
+ readonly maxAmount: import("@angular/core").InputSignal<number>;
15252
+ /** Latest Received Date (ISO). Default: `today`, because a payment cannot be received in the future. */
15253
+ readonly maxDate: import("@angular/core").InputSignal<string>;
15254
+ /** The methods listed (value/label). Default: Card, ACH / Bank Transfer, Cash, Check, Money Order, Card Present (terminal callbacks given). */
15255
+ readonly methods: import("@angular/core").InputSignal<readonly PaymentMethodOption[]>;
15256
+ readonly savedMethods: import("@angular/core").InputSignal<readonly SavedPaymentMethod[]>;
15257
+ readonly charges: import("@angular/core").InputSignal<readonly PayableCharge[]>;
15258
+ readonly allocationModes: import("@angular/core").InputSignal<readonly AllocationModeOption[]>;
15259
+ readonly defaultAllocationMode: import("@angular/core").InputSignal<string>;
15260
+ /** Text of the "send receipt" checkbox (e.g. "Email receipt to resident"); empty hides it. */
15261
+ readonly receiptLabel: import("@angular/core").InputSignal<string>;
15262
+ readonly submitLabel: import("@angular/core").InputSignal<string>;
15263
+ readonly splitSubmitLabel: import("@angular/core").InputSignal<string>;
15264
+ /** Records the payment. Returns an Observable / Promise; a rejection is shown in the panel and it stays open. */
15265
+ readonly recordPayment: import("@angular/core").InputSignal<RecordPaymentFn | null>;
15266
+ readonly listReaders: import("@angular/core").InputSignal<(() => HostResult<readonly TerminalReader[]>) | null>;
15267
+ readonly startTerminalPayment: import("@angular/core").InputSignal<((ctx: TerminalStartContext) => HostResult<TerminalStartResult>) | null>;
15268
+ readonly terminalStatus: import("@angular/core").InputSignal<((paymentIntentId: string) => HostResult<TerminalStatusResult>) | null>;
15269
+ readonly confirmTerminalPayment: import("@angular/core").InputSignal<((ctx: TerminalConfirmContext) => HostResult<unknown>) | null>;
15270
+ readonly cancelTerminal: import("@angular/core").InputSignal<((readerId: string) => HostResult<unknown>) | null>;
15271
+ readonly terminalProvider: import("@angular/core").InputSignal<string>;
15272
+ readonly noReadersText: import("@angular/core").InputSignal<string>;
15273
+ readonly terminalPollMs: import("@angular/core").InputSignal<number>;
15274
+ readonly terminalTimeoutMs: import("@angular/core").InputSignal<number>;
15275
+ readonly readerRefreshMs: import("@angular/core").InputSignal<number>;
15276
+ readonly terminalSuccessDelayMs: import("@angular/core").InputSignal<number>;
15277
+ readonly closed: import("@angular/core").OutputEmitterRef<void>;
15278
+ /** The payment is done (any flow). The host closes the panel. */
15279
+ readonly recorded: import("@angular/core").OutputEmitterRef<RecordPaymentResult>;
15280
+ /** What happened, for the host to word (the panel never toasts). */
15281
+ readonly outcome: import("@angular/core").OutputEmitterRef<PaymentPanelOutcome>;
15282
+ private readonly plugins;
15283
+ private readonly fields;
15284
+ readonly method: import("@angular/core").WritableSignal<string>;
15285
+ readonly amount: import("@angular/core").WritableSignal<number | null>;
15286
+ readonly receivedDate: import("@angular/core").WritableSignal<string>;
15287
+ readonly reference: import("@angular/core").WritableSignal<string>;
15288
+ readonly note: import("@angular/core").WritableSignal<string>;
15289
+ readonly sendReceipt: import("@angular/core").WritableSignal<boolean>;
15290
+ readonly splitEntries: import("@angular/core").WritableSignal<SplitEntry[]>;
15291
+ readonly allocationMode: import("@angular/core").WritableSignal<string>;
15292
+ readonly selectedCharges: import("@angular/core").WritableSignal<SelectedCharges>;
15293
+ readonly touched: import("@angular/core").WritableSignal<boolean>;
15294
+ readonly submitting: import("@angular/core").WritableSignal<boolean>;
15295
+ readonly submitError: import("@angular/core").WritableSignal<string>;
15296
+ readonly announcement: import("@angular/core").WritableSignal<string>;
15297
+ private readonly pluginBusy;
15298
+ protected readonly exclusive: import("@angular/core").WritableSignal<boolean>;
15299
+ private readonly pluginPrimary;
15300
+ private cancelHook;
15301
+ private completed;
15302
+ readonly readers: import("@angular/core").WritableSignal<readonly TerminalReader[]>;
15303
+ readonly readersLoaded: import("@angular/core").WritableSignal<boolean>;
15304
+ readonly loadingReaders: import("@angular/core").WritableSignal<boolean>;
15305
+ readonly readersError: import("@angular/core").WritableSignal<string>;
15306
+ readonly readerId: import("@angular/core").WritableSignal<string>;
15307
+ readonly terminalPhase: import("@angular/core").WritableSignal<TerminalPhase>;
15308
+ readonly terminalError: import("@angular/core").WritableSignal<string>;
15309
+ readonly sendingToReader: import("@angular/core").WritableSignal<boolean>;
15310
+ readonly retryIntentId: import("@angular/core").WritableSignal<string>;
15311
+ readonly retrying: import("@angular/core").WritableSignal<boolean>;
15312
+ readonly terminalAmount: import("@angular/core").WritableSignal<number>;
15313
+ /** Bumped when the form is reset or the panel closes: an async terminal step that finishes later must not touch the new state. */
15314
+ private session;
15315
+ private retryContext;
15316
+ private pollTimer;
15317
+ private pollToken;
15318
+ private refreshTimer;
15319
+ private successTimer;
15320
+ private pendingTerminalResult;
15321
+ private terminalContext;
15322
+ protected readonly busy: import("@angular/core").Signal<boolean>;
15323
+ /** Fields are read-only while something runs, and while a taken terminal payment still has to be recorded (its amount must not change). */
15324
+ protected readonly locked: import("@angular/core").Signal<boolean>;
15325
+ protected readonly dateMax: import("@angular/core").Signal<string>;
15326
+ protected readonly money: (value: number) => string;
15327
+ protected readonly currencySymbol: import("@angular/core").Signal<string>;
15328
+ private readonly terminalAvailable;
15329
+ /** value -> label of every live method the rendered plugins contribute (the first plugin wins a duplicate value). */
15330
+ private readonly liveMethods;
15331
+ protected readonly kind: import("@angular/core").Signal<"none" | "live" | "terminal" | "manual">;
15332
+ private kindOf;
15333
+ /** The method list as shown: record-only built-ins (a plugin takes over its own values), plugin extras, and only manual ones while a split is being built. */
15334
+ readonly methodList: import("@angular/core").Signal<PaymentMethodOption[]>;
15335
+ protected readonly methodOptions: import("@angular/core").Signal<{
15336
+ value: string;
15337
+ label: string;
15338
+ }[]>;
15339
+ protected readonly methodRequired: import("@angular/core").Signal<boolean>;
15340
+ protected readonly allocationOptions: import("@angular/core").Signal<{
15341
+ value: string;
15342
+ label: string;
15343
+ }[]>;
15344
+ /** Hidden while a taken terminal payment still has to be recorded: the method cannot change then. */
15345
+ protected readonly savedChips: import("@angular/core").Signal<SavedPaymentMethod[]>;
15346
+ protected readonly refKind: import("@angular/core").Signal<"check" | "last4-card" | "last4-account" | null>;
15347
+ protected readonly referenceError: import("@angular/core").Signal<string>;
15348
+ private readonly amountValid;
15349
+ protected readonly splitTotal: import("@angular/core").Signal<number>;
15350
+ private readonly totalPayment;
15351
+ protected readonly allocation: import("@angular/core").Signal<AllocationCheck>;
15352
+ private readonly allocationPayload;
15353
+ protected readonly hasInvalid: import("@angular/core").Signal<boolean>;
15354
+ protected readonly canSplit: import("@angular/core").Signal<boolean>;
15355
+ protected readonly readerOptions: import("@angular/core").Signal<{
15356
+ value: string;
15357
+ label: string;
15358
+ }[]>;
15359
+ protected readonly selectedReader: import("@angular/core").Signal<TerminalReader | null>;
15360
+ protected readonly canSendToReader: import("@angular/core").Signal<boolean>;
15361
+ protected readonly pluginTemplate: import("@angular/core").Signal<import("@angular/core").TemplateRef<PaymentMethodBodyContext> | undefined>;
15362
+ protected readonly pluginContext: import("@angular/core").Signal<PaymentMethodBodyContext>;
15363
+ protected readonly primaryLabel: import("@angular/core").Signal<string>;
15364
+ protected readonly primaryLoading: import("@angular/core").Signal<boolean>;
15365
+ protected readonly primaryDisabled: import("@angular/core").Signal<boolean>;
15366
+ constructor();
15367
+ private init;
15368
+ private teardown;
15369
+ private resetForm;
15370
+ /** A card payment the reader took but that was never recorded is being abandoned: the host must hear about it. */
15371
+ private dropPendingRetry;
15372
+ private cleanup;
15373
+ protected onClose(): void;
15374
+ private runCancelHook;
15375
+ protected onMethodChange(value: string | null): void;
15376
+ protected selectSaved(saved: SavedPaymentMethod): void;
15377
+ protected chipLabel(saved: SavedPaymentMethod): string;
15378
+ protected methodLabel(value: string): string;
15379
+ protected onLast4(value: string | null): void;
15380
+ protected addSplit(): void;
15381
+ protected removeSplit(index: number): void;
15382
+ protected onAllocationMode(value: string | null): void;
15383
+ protected isTicked(id: string): boolean;
15384
+ protected toggleCharge(charge: PayableCharge, checked: boolean): void;
15385
+ protected setChargeAmount(id: string, value: number | string | null): void;
15386
+ protected chargeDescription(charge: PayableCharge): string;
15387
+ private referenceFor;
15388
+ private buildEntries;
15389
+ /** The payload the host receives, or `null` when there is nothing valid to record. */
15390
+ buildPayload(): RecordPaymentPayload | null;
15391
+ protected onPrimary(): void;
15392
+ submit(): Promise<void>;
15393
+ /**
15394
+ * A host that posts the entries one by one can tell the panel how many went through before a failure: `throw { message, postedEntries: 1 }`.
15395
+ * Those first entries are removed, so a retry does not post them again.
15396
+ */
15397
+ private dropPostedEntries;
15398
+ private buildContext;
15399
+ private completeFromPlugin;
15400
+ private resetTerminal;
15401
+ private startTerminalSession;
15402
+ protected refreshReaders(): void;
15403
+ private loadReaders;
15404
+ private scheduleReaderRefresh;
15405
+ private stopReaderRefresh;
15406
+ private terminalBase;
15407
+ sendToReader(): Promise<void>;
15408
+ private startPolling;
15409
+ private stopPolling;
15410
+ private endWaiting;
15411
+ private confirmTerminal;
15412
+ /** Repeats the recording for the payment the reader already took, with the amount that was charged (not the form's current values). */
15413
+ protected retryRecording(): Promise<void>;
15414
+ private finishTerminal;
15415
+ protected cancelTerminalPayment(): void;
15416
+ private cancelTerminalIfWaiting;
15417
+ /** Moves focus after the next render (the control that had it was just removed from the DOM). */
15418
+ private focusLater;
15419
+ private fireCancelReader;
15420
+ static ɵfac: i0.ɵɵFactoryDeclaration<PaymentSidePanelComponent, never>;
15421
+ static ɵcmp: i0.ɵɵComponentDeclaration<PaymentSidePanelComponent, "ui-payment-side-panel", never, {
15422
+ "open": {
15423
+ "alias": "open";
15424
+ "required": false;
15425
+ "isSignal": true;
15426
+ };
15427
+ "title": {
15428
+ "alias": "title";
15429
+ "required": false;
15430
+ "isSignal": true;
15431
+ };
15432
+ "subtitle": {
15433
+ "alias": "subtitle";
15434
+ "required": false;
15435
+ "isSignal": true;
15436
+ };
15437
+ "today": {
15438
+ "alias": "today";
15439
+ "required": false;
15440
+ "isSignal": true;
15441
+ };
15442
+ "outstandingBalance": {
15443
+ "alias": "outstandingBalance";
15444
+ "required": false;
15445
+ "isSignal": true;
15446
+ };
15447
+ "currency": {
15448
+ "alias": "currency";
15449
+ "required": false;
15450
+ "isSignal": true;
15451
+ };
15452
+ "maxAmount": {
15453
+ "alias": "maxAmount";
15454
+ "required": false;
15455
+ "isSignal": true;
15456
+ };
15457
+ "maxDate": {
15458
+ "alias": "maxDate";
15459
+ "required": false;
15460
+ "isSignal": true;
15461
+ };
15462
+ "methods": {
15463
+ "alias": "methods";
15464
+ "required": false;
15465
+ "isSignal": true;
15466
+ };
15467
+ "savedMethods": {
15468
+ "alias": "savedMethods";
15469
+ "required": false;
15470
+ "isSignal": true;
15471
+ };
15472
+ "charges": {
15473
+ "alias": "charges";
15474
+ "required": false;
15475
+ "isSignal": true;
15476
+ };
15477
+ "allocationModes": {
15478
+ "alias": "allocationModes";
15479
+ "required": false;
15480
+ "isSignal": true;
15481
+ };
15482
+ "defaultAllocationMode": {
15483
+ "alias": "defaultAllocationMode";
15484
+ "required": false;
15485
+ "isSignal": true;
15486
+ };
15487
+ "receiptLabel": {
15488
+ "alias": "receiptLabel";
15489
+ "required": false;
15490
+ "isSignal": true;
15491
+ };
15492
+ "submitLabel": {
15493
+ "alias": "submitLabel";
15494
+ "required": false;
15495
+ "isSignal": true;
15496
+ };
15497
+ "splitSubmitLabel": {
15498
+ "alias": "splitSubmitLabel";
15499
+ "required": false;
15500
+ "isSignal": true;
15501
+ };
15502
+ "recordPayment": {
15503
+ "alias": "recordPayment";
15504
+ "required": false;
15505
+ "isSignal": true;
15506
+ };
15507
+ "listReaders": {
15508
+ "alias": "listReaders";
15509
+ "required": false;
15510
+ "isSignal": true;
15511
+ };
15512
+ "startTerminalPayment": {
15513
+ "alias": "startTerminalPayment";
15514
+ "required": false;
15515
+ "isSignal": true;
15516
+ };
15517
+ "terminalStatus": {
15518
+ "alias": "terminalStatus";
15519
+ "required": false;
15520
+ "isSignal": true;
15521
+ };
15522
+ "confirmTerminalPayment": {
15523
+ "alias": "confirmTerminalPayment";
15524
+ "required": false;
15525
+ "isSignal": true;
15526
+ };
15527
+ "cancelTerminal": {
15528
+ "alias": "cancelTerminal";
15529
+ "required": false;
15530
+ "isSignal": true;
15531
+ };
15532
+ "terminalProvider": {
15533
+ "alias": "terminalProvider";
15534
+ "required": false;
15535
+ "isSignal": true;
15536
+ };
15537
+ "noReadersText": {
15538
+ "alias": "noReadersText";
15539
+ "required": false;
15540
+ "isSignal": true;
15541
+ };
15542
+ "terminalPollMs": {
15543
+ "alias": "terminalPollMs";
15544
+ "required": false;
15545
+ "isSignal": true;
15546
+ };
15547
+ "terminalTimeoutMs": {
15548
+ "alias": "terminalTimeoutMs";
15549
+ "required": false;
15550
+ "isSignal": true;
15551
+ };
15552
+ "readerRefreshMs": {
15553
+ "alias": "readerRefreshMs";
15554
+ "required": false;
15555
+ "isSignal": true;
15556
+ };
15557
+ "terminalSuccessDelayMs": {
15558
+ "alias": "terminalSuccessDelayMs";
15559
+ "required": false;
15560
+ "isSignal": true;
15561
+ };
15562
+ }, {
15563
+ "closed": "closed";
15564
+ "recorded": "recorded";
15565
+ "outcome": "outcome";
15566
+ }, ["plugins"], never, true, never>;
15567
+ }
15568
+ export type { AllocationModeOption, CalendarAgendaGroup, CalendarDay, CalendarDayLevel, CalendarRange, CalendarViewMode, ChargeAllocation, HostResult, PayableCharge, PaymentAllocation, PaymentEntry, PaymentMethodOption, PaymentPanelOutcome, RecordPaymentFn, RecordPaymentPayload, RecordPaymentResult, SavedPaymentMethod, TerminalConfirmContext, TerminalPhase, TerminalReader, TerminalStartContext, TerminalStartResult, TerminalStatusResult };