@forgeroute/ui 0.4.1 → 0.4.3

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.
@@ -1,8 +1,9 @@
1
1
  import * as i0 from "@angular/core";
2
- import { ChangeDetectorRef, EnvironmentProviders, InjectionToken, OnDestroy, OnInit, Signal, TemplateRef, WritableSignal } from "@angular/core";
2
+ import { EnvironmentProviders, InjectionToken, OnDestroy, OnInit, Signal, TemplateRef, WritableSignal } from "@angular/core";
3
+ import { UrlTree } from "@angular/router";
3
4
  import { AbstractControl, ControlValueAccessor, FormControl, ValidationErrors, Validator } from "@angular/forms";
4
- import { Observable, Subject } from "rxjs";
5
- import { HttpClient, HttpInterceptorFn } from "@angular/common/http";
5
+ import { Observable } from "rxjs";
6
+ import { HttpInterceptorFn } from "@angular/common/http";
6
7
  import { SafeHtml } from "@angular/platform-browser";
7
8
  export interface ForgerouteConfig {
8
9
  baseUrl: string;
@@ -99,7 +100,38 @@ export interface RowAction {
99
100
  /** Page-level permission passed to `<ui-data-table [permission]>`. Anything other than 'full' is read-only
100
101
  * (apps use values like 'read-only' / 'hidden'). */
101
102
  export type TablePermission = 'full' | 'read' | 'read-only' | 'none' | 'hidden';
102
- export type CellType = 'text' | 'badge' | 'date' | 'phone' | 'number' | 'avatar-name' | 'days-ago' | 'progress' | 'tags' | 'image' | 'actions';
103
+ export type CellType = 'text' | 'badge' | 'date' | 'phone' | 'number' | 'avatar-name' | 'days-ago' | 'progress' | 'tags' | 'image' | 'link' | 'actions';
104
+ /**
105
+ * Where a `cellType: 'link'` cell points. Return a plain string from `linkFn` as shorthand for `{ href }`.
106
+ *
107
+ * - `routerLink` (+ `queryParams`) is an in-app route: the anchor gets the real URL as its `href` (so right-click,
108
+ * middle-click, ctrl/cmd-click, "open in new tab" and "copy link address" all work) and a plain left click
109
+ * navigates through the Angular `Router` without a page reload. `routerLink` wins when `href` is also set.
110
+ * - `href` accepts ONLY `mailto:`, `tel:`, `http:`, `https:` and root-relative paths (`/cases/12`). Anything else
111
+ * (`javascript:`, `data:`, `//host`, empty, control characters) is never rendered as an href: the cell shows plain
112
+ * text. A root-relative `href` is a normal link (full page load); use `routerLink` for in-app navigation.
113
+ * - `target: '_blank'` (default `'_self'`) adds `rel="noopener noreferrer"` and a "(opens in a new tab)" screen-reader
114
+ * hint. `http(s):` hrefs always get the same `rel`.
115
+ * - `label` is the link text when the cell has no text of its own (`render` and `item[key]` are empty).
116
+ * - `ariaLabel` replaces the link's accessible name (default: its text).
117
+ * - `download` adds the `download` attribute.
118
+ */
119
+ export interface LinkTarget {
120
+ href?: string;
121
+ routerLink?: string | readonly any[];
122
+ queryParams?: Record<string, any>;
123
+ target?: '_self' | '_blank';
124
+ label?: string;
125
+ ariaLabel?: string;
126
+ download?: boolean;
127
+ }
128
+ /** Payload of `(linkClick)`: a link cell's anchor was activated by a click (the row click is NOT also emitted). */
129
+ export interface LinkClickEvent<T = any> {
130
+ item: T;
131
+ column: ColumnDef;
132
+ /** The anchor's href (null only for a routerLink that could not be resolved, which renders no anchor anyway). */
133
+ href: string | null;
134
+ }
103
135
  export interface ColumnDef {
104
136
  key: string;
105
137
  label: string;
@@ -133,6 +165,13 @@ export interface ColumnDef {
133
165
  * Return null to render a plain '—' instead of a badge (e.g. for an empty value).
134
166
  */
135
167
  badgeFn?: (value: any, item?: any) => BadgeConfig | null;
168
+ /**
169
+ * Puts a gold `<ui-star>` to the LEFT of the cell's text when it returns a non-empty string; that string is the star's tooltip
170
+ * (hover / keyboard focus) and accessible name. Return null / undefined / '' for no star. The star is always gold.
171
+ * Applies to plain text cells (and the title of the phone card); the row's accessible name is unchanged (`nameFn` / `render`).
172
+ * Example: `{ key: 'name', label: 'Name', starFn: (doc) => doc.isAuthForm ? 'Authorization Form' : null }`
173
+ */
174
+ starFn?: (item: any) => string | null | undefined;
136
175
  /** Date format string. Default: 'MMM d, y' */
137
176
  dateFormat?: string;
138
177
  /** Returns the display name for the row. Default: item[col.key] */
@@ -158,6 +197,15 @@ export interface ColumnDef {
158
197
  /** Key in item holding the tags array. Defaults to col.key.
159
198
  * Expected shape: { name: string; variant?: BadgeVariant }[] */
160
199
  tagsKey?: string;
200
+ /**
201
+ * `cellType: 'link'` — returns where the cell points for a row (`value` is `item[key]`), or null / undefined /
202
+ * '' for no link (the cell then shows plain text). A string is shorthand for `{ href }`. See {@link LinkTarget}
203
+ * for the contract and the allowed schemes. Text shown: `render(item)` if set, else `item[key]`, else the
204
+ * target's `label`, else '—'. The text is always escaped. A throwing `linkFn` renders plain text.
205
+ * Sorting, search, filters and export are independent of the link (export uses the host's `exportRow`).
206
+ * Clicking or keying the anchor never emits `rowClick`; it emits `(linkClick)`.
207
+ */
208
+ linkFn?: (item: any, value: any) => LinkTarget | string | null | undefined;
161
209
  /** Returns the image URL for the row. A falsy value (null / undefined / '') shows the placeholder icon. */
162
210
  imageFn?: (item: any) => string | null | undefined;
163
211
  /** Focal point (percent, 50/50 = centered) of the cropped image, applied as CSS object-position. */
@@ -906,7 +954,7 @@ export declare class SelectComponent implements ControlValueAccessor, Validator,
906
954
  readonly error: import("@angular/core").InputSignal<string>;
907
955
  /** Reveal the built-in error messages now (e.g. after a failed Save click), without waiting for blur. */
908
956
  readonly showErrors: import("@angular/core").InputSignal<boolean>;
909
- readonly size: import("@angular/core").InputSignal<"sm" | "default">;
957
+ readonly size: import("@angular/core").InputSignal<"default" | "sm">;
910
958
  readonly _disabledInput: import("@angular/core").InputSignal<boolean>;
911
959
  private readonly _cvaDisabled;
912
960
  protected readonly disabled: import("@angular/core").Signal<boolean>;
@@ -1123,6 +1171,15 @@ export declare class ImportExportComponent {
1123
1171
  }
1124
1172
  /** Simple English plural: "property" → "properties", "box" → "boxes", "contact" → "contacts". */
1125
1173
  export declare function pluralize(word: string): string;
1174
+ /** Resolved anchor data of a link cell (internal). */
1175
+ interface ResolvedLink {
1176
+ href: string;
1177
+ tree: UrlTree | null;
1178
+ blank: boolean;
1179
+ rel: string | null;
1180
+ download: boolean;
1181
+ ariaLabel: string | null;
1182
+ }
1126
1183
  export declare class DataTableComponent<T extends Record<string, any>> implements OnInit {
1127
1184
  readonly endpoint: import("@angular/core").InputSignal<string>;
1128
1185
  readonly columns: import("@angular/core").InputSignal<ColumnDef[]>;
@@ -1202,6 +1259,12 @@ export declare class DataTableComponent<T extends Record<string, any>> implement
1202
1259
  */
1203
1260
  readonly bulkUpdateOptions: import("@angular/core").InputSignal<BulkUpdateOption<T>[]>;
1204
1261
  readonly rowClick: import("@angular/core").OutputEmitterRef<T>;
1262
+ /**
1263
+ * A `cellType: 'link'` anchor was clicked (plain or with ctrl/cmd/shift; a middle-button click is an `auxclick`, not emitted). Fires instead of
1264
+ * `rowClick`: the anchor stops the click from reaching the row. For an in-app `routerLink` the table has already
1265
+ * called `Router.navigateByUrl` on a plain left click (modifier / `_blank` clicks are left to the browser).
1266
+ */
1267
+ readonly linkClick: import("@angular/core").OutputEmitterRef<LinkClickEvent<T>>;
1205
1268
  /**
1206
1269
  * Optional per-row opt-out for (rowClick): rows where it returns false get no pointer cursor,
1207
1270
  * no tab stop and no click/keyboard activation (e.g. log rows with no linked record).
@@ -1535,6 +1598,16 @@ export declare class DataTableComponent<T extends Record<string, any>> implement
1535
1598
  protected imageClass(col: ColumnDef, small: boolean): string;
1536
1599
  protected onImageError(url: string): void;
1537
1600
  protected phoneCell(value: any): string;
1601
+ private readonly _injector;
1602
+ /** Safe hrefs only: mailto:, tel:, http(s):// and root-relative paths. Everything else is refused (null). */
1603
+ private _safeHref;
1604
+ /** Text and (when there is a safe target) the anchor data of a `cellType: 'link'` cell. Never throws. */
1605
+ protected linkView(col: ColumnDef, item: T): {
1606
+ text: string;
1607
+ link: ResolvedLink | null;
1608
+ };
1609
+ /** Anchor click: never reaches the row; a plain left click on an in-app route navigates via the Router (SPA, no reload). */
1610
+ protected onLinkClick(e: MouseEvent, link: ResolvedLink, col: ColumnDef, item: T): void;
1538
1611
  protected getInitials(name: string): string;
1539
1612
  protected isCardOverdue(col: ColumnDef, item: T): boolean;
1540
1613
  /** Renders any non-badge column value as a plain string for the mobile card view. */
@@ -1688,6 +1761,7 @@ export declare class DataTableComponent<T extends Record<string, any>> implement
1688
1761
  };
1689
1762
  }, {
1690
1763
  "rowClick": "rowClick";
1764
+ "linkClick": "linkClick";
1691
1765
  "tableButtonClick": "tableButtonClick";
1692
1766
  "panelActionClick": "panelActionClick";
1693
1767
  "saveViewClick": "saveViewClick";
@@ -2130,7 +2204,7 @@ export declare class AudioPlayerComponent {
2130
2204
  /** Accessible name of the player. */
2131
2205
  readonly ariaLabel: import("@angular/core").InputSignal<string>;
2132
2206
  /** How much to load before play: 'metadata' (default), 'auto' or 'none'. */
2133
- readonly preload: import("@angular/core").InputSignal<"none" | "metadata" | "auto">;
2207
+ readonly preload: import("@angular/core").InputSignal<"none" | "auto" | "metadata">;
2134
2208
  /** Fires when the browser can't load or decode the source. */
2135
2209
  readonly playbackError: import("@angular/core").OutputEmitterRef<void>;
2136
2210
  protected readonly failed: import("@angular/core").WritableSignal<boolean>;
@@ -2238,6 +2312,33 @@ export declare class TooltipDirective {
2238
2312
  };
2239
2313
  }, {}, never, never, true, never>;
2240
2314
  }
2315
+ /**
2316
+ * A small gold star with a hover / focus tooltip: `<ui-star tooltip="Authorization Form" />`.
2317
+ *
2318
+ * The star is always gold (there is no color input). `tooltip` is the text the user sees on hover or keyboard focus (library `uiTooltip`);
2319
+ * it is also the star's accessible name, so a screen reader reads it too. Without a tooltip the star is decorative (hidden from assistive tech).
2320
+ * In `<ui-data-table>` use `ColumnDef.starFn` to put one to the left of a text cell (e.g. the name column).
2321
+ */
2322
+ export declare class StarComponent {
2323
+ /** Tooltip text (also the accessible name). Empty = no tooltip and the star is decorative. */
2324
+ readonly tooltip: import("@angular/core").InputSignal<string>;
2325
+ /** Star size in px. Default 16. */
2326
+ readonly size: import("@angular/core").InputSignal<number>;
2327
+ protected readonly hasTooltip: import("@angular/core").Signal<boolean>;
2328
+ static ɵfac: i0.ɵɵFactoryDeclaration<StarComponent, never>;
2329
+ static ɵcmp: i0.ɵɵComponentDeclaration<StarComponent, "ui-star", never, {
2330
+ "tooltip": {
2331
+ "alias": "tooltip";
2332
+ "required": false;
2333
+ "isSignal": true;
2334
+ };
2335
+ "size": {
2336
+ "alias": "size";
2337
+ "required": false;
2338
+ "isSignal": true;
2339
+ };
2340
+ }, {}, never, never, true, never>;
2341
+ }
2241
2342
  export type ImageRepositionShape = 'circle' | 'rounded';
2242
2343
  /**
2243
2344
  * Drag-to-center photo frame. The image fills the frame (`object-fit: cover`) and the user drags it, or uses the arrow
@@ -3011,7 +3112,7 @@ export declare class PhoneNumberPickerComponent {
3011
3112
  protected readonly modeCtl: FormControl<string>;
3012
3113
  protected readonly zipCtl: FormControl<string>;
3013
3114
  protected readonly areaCtl: FormControl<string>;
3014
- protected readonly step: import("@angular/core").WritableSignal<2 | 1 | 3>;
3115
+ protected readonly step: import("@angular/core").WritableSignal<1 | 2 | 3>;
3015
3116
  protected readonly mode: import("@angular/core").WritableSignal<PhoneNumberSearchMode>;
3016
3117
  private readonly _zip;
3017
3118
  private readonly _area;
@@ -3134,7 +3235,7 @@ export declare class ButtonComponent {
3134
3235
  */
3135
3236
  readonly href: import("@angular/core").InputSignal<string | null>;
3136
3237
  /** Where to open the `href` (`_blank` = a new tab). */
3137
- readonly target: import("@angular/core").InputSignal<"_blank" | "_self" | "_parent" | "_top" | null>;
3238
+ readonly target: import("@angular/core").InputSignal<"_self" | "_blank" | "_parent" | "_top" | null>;
3138
3239
  /** `rel` of the `href` link. A `_blank` target always gets `noopener noreferrer` added. */
3139
3240
  readonly rel: import("@angular/core").InputSignal<string | null>;
3140
3241
  /** The href when it is allowed (http, https, mailto, tel, sms or a relative URL), else null. */
@@ -3142,8 +3243,8 @@ export declare class ButtonComponent {
3142
3243
  protected readonly _rel: import("@angular/core").Signal<string | null>;
3143
3244
  readonly color: import("@angular/core").InputSignal<string | undefined>;
3144
3245
  readonly active: import("@angular/core").InputSignal<boolean>;
3145
- readonly size: import("@angular/core").InputSignal<"sm" | "md" | "lg" | "xs">;
3146
- readonly type: import("@angular/core").InputSignal<"button" | "submit" | "reset">;
3246
+ readonly size: import("@angular/core").InputSignal<"sm" | "md" | "xs" | "lg">;
3247
+ readonly type: import("@angular/core").InputSignal<"reset" | "submit" | "button">;
3147
3248
  readonly disabled: import("@angular/core").InputSignal<boolean>;
3148
3249
  readonly loading: import("@angular/core").InputSignal<boolean>;
3149
3250
  readonly fullWidth: import("@angular/core").InputSignal<boolean>;
@@ -3338,9 +3439,9 @@ export interface ContactLookup {
3338
3439
  email: string | null;
3339
3440
  smsOptedIn: boolean;
3340
3441
  }
3341
- declare function formatPhone$1(raw: string | null | undefined): string;
3442
+ declare function formatPhone(raw: string | null | undefined): string;
3342
3443
  export declare class ContactPickerComponent {
3343
- readonly formatPhone: typeof formatPhone$1;
3444
+ readonly formatPhone: typeof formatPhone;
3344
3445
  readonly label: import("@angular/core").InputSignal<string>;
3345
3446
  readonly placeholder: import("@angular/core").InputSignal<string>;
3346
3447
  /** Helper text under the picker (linked to the search input via aria-describedby). */
@@ -3498,2566 +3599,161 @@ export declare class ContactPickerComponent {
3498
3599
  "invalidChange": "invalidChange";
3499
3600
  }, never, never, true, never>;
3500
3601
  }
3501
- export interface VideoMessage {
3602
+ export interface BulkMessageContact {
3502
3603
  id: string;
3503
- title: string;
3504
- category: string;
3505
- shareLink: string | null;
3604
+ name: string;
3605
+ email: string | null;
3606
+ phone: string | null;
3506
3607
  }
3507
- export declare class VideoPickerComponent implements UiFieldValidity {
3508
- readonly videoSelected: import("@angular/core").OutputEmitterRef<VideoMessage>;
3509
- /** Optional visible label (names the search field and the selected-video group). Without it the field is named "Search videos". */
3510
- readonly label: import("@angular/core").InputSignal<string>;
3511
- /** Shows the red required marker; the picker is then invalid until a video is picked. */
3512
- readonly required: import("@angular/core").InputSignal<boolean>;
3513
- /** Reveal the built-in "<label> is required." message now (e.g. after a failed Save click); otherwise it shows after the field was blurred. */
3514
- readonly showErrors: import("@angular/core").InputSignal<boolean>;
3515
- /** Emits whenever `invalid` flips. */
3516
- readonly invalidChange: import("@angular/core").OutputEmitterRef<boolean>;
3517
- private readonly http;
3518
- private readonly destroyRef;
3519
- private readonly host;
3520
- private readonly injector;
3521
- /** API root from FORGEROUTE_CONFIG (e.g. a cross-origin prod API); falls back to same-origin `/api`. */
3522
- private readonly apiBase;
3523
- private readonly uid;
3524
- readonly inputId: string;
3525
- readonly labelId: string;
3526
- readonly listboxId: string;
3527
- readonly errorId: string;
3528
- optionId(i: number): string;
3529
- query: string;
3530
- readonly selected: import("@angular/core").WritableSignal<VideoMessage | null>;
3531
- readonly results: import("@angular/core").WritableSignal<VideoMessage[]>;
3532
- readonly loading: import("@angular/core").WritableSignal<boolean>;
3533
- readonly showResults: import("@angular/core").WritableSignal<boolean>;
3534
- /** True from the first keystroke of a >=2-char query until its results arrive (covers the debounce). */
3535
- readonly pending: import("@angular/core").WritableSignal<boolean>;
3536
- /** Index of the keyboard-highlighted option; -1 = none (aria-activedescendant unset). */
3537
- readonly activeIndex: import("@angular/core").WritableSignal<number>;
3538
- private readonly reveal;
3539
- /** `UiFieldValidity`: true while `required` and no video is picked. */
3540
- readonly invalid: import("@angular/core").Signal<boolean>;
3541
- /** "<label> is required." while invalid ('' otherwise), shown or not. */
3542
- readonly errorMessage: import("@angular/core").Signal<string>;
3543
- /** `errorMessage` once the field was blurred or `showErrors` is set. */
3544
- readonly visibleError: import("@angular/core").Signal<string>;
3545
- readonly activeDescendant: import("@angular/core").Signal<string | null>;
3546
- /** Polite announcement for screen readers: searching, the result count, or no results (only while the list is open). */
3547
- readonly liveText: import("@angular/core").Signal<string>;
3548
- private readonly search$;
3549
- private blurTimer;
3550
- private lastMouseActivation;
3608
+ export interface BulkMessageSendEvent {
3609
+ channel: 'email' | 'text';
3610
+ subject: string;
3611
+ body: string;
3612
+ contacts: BulkMessageContact[];
3613
+ }
3614
+ export declare class BulkMessagePanelComponent {
3615
+ readonly open: import("@angular/core").InputSignal<boolean>;
3616
+ readonly contacts: import("@angular/core").InputSignal<BulkMessageContact[]>;
3617
+ readonly textEnabled: import("@angular/core").InputSignal<boolean>;
3618
+ readonly sending: import("@angular/core").InputSignal<boolean>;
3619
+ readonly closed: import("@angular/core").OutputEmitterRef<void>;
3620
+ readonly send: import("@angular/core").OutputEmitterRef<BulkMessageSendEvent>;
3621
+ readonly channel: import("@angular/core").WritableSignal<"text" | "email">;
3622
+ private readonly _subject;
3623
+ private readonly _body;
3624
+ get subject(): string;
3625
+ set subject(v: string);
3626
+ get body(): string;
3627
+ set body(v: string);
3628
+ readonly emailContacts: import("@angular/core").Signal<BulkMessageContact[]>;
3629
+ readonly textContacts: import("@angular/core").Signal<BulkMessageContact[]>;
3630
+ readonly activeContacts: import("@angular/core").Signal<BulkMessageContact[]>;
3631
+ readonly skippedCount: import("@angular/core").Signal<number>;
3632
+ readonly canSend: import("@angular/core").Signal<boolean>;
3633
+ readonly primaryLabel: import("@angular/core").Signal<string>;
3634
+ private _prevOpen;
3551
3635
  constructor();
3552
- onInput(): void;
3553
- onFocus(): void;
3554
- /** Delayed so a click on an option still lands; cancelled if focus returns (or the user types) first. */
3555
- onBlur(): void;
3556
- private clearBlurTimer;
3557
- /**
3558
- * ARIA combobox keys: ArrowDown/ArrowUp open the list and move the highlight (wrapping), Home/End jump to the first /
3559
- * last option, Enter picks the highlighted option, Escape closes the list only (so a surrounding side panel / modal
3560
- * stays open; with the list closed it passes through). Tab selects nothing.
3561
- */
3562
- onKeydown(e: KeyboardEvent): void;
3563
- private setActive;
3564
- onOptionMouseDown(): void;
3565
- /** Activation by assistive tech / a virtual cursor arrives as a click without a preceding mousedown. */
3566
- onOptionClick(v: VideoMessage): void;
3567
- select(v: VideoMessage): void;
3568
- clear(): void;
3569
- private focusAfterRender;
3570
- static ɵfac: i0.ɵɵFactoryDeclaration<VideoPickerComponent, never>;
3571
- static ɵcmp: i0.ɵɵComponentDeclaration<VideoPickerComponent, "ui-video-picker", never, {
3572
- "label": {
3573
- "alias": "label";
3636
+ onChannelChange(ch: 'email' | 'text'): void;
3637
+ onSend(): void;
3638
+ static ɵfac: i0.ɵɵFactoryDeclaration<BulkMessagePanelComponent, never>;
3639
+ static ɵcmp: i0.ɵɵComponentDeclaration<BulkMessagePanelComponent, "ui-bulk-message-panel", never, {
3640
+ "open": {
3641
+ "alias": "open";
3574
3642
  "required": false;
3575
3643
  "isSignal": true;
3576
3644
  };
3577
- "required": {
3578
- "alias": "required";
3645
+ "contacts": {
3646
+ "alias": "contacts";
3579
3647
  "required": false;
3580
3648
  "isSignal": true;
3581
3649
  };
3582
- "showErrors": {
3583
- "alias": "showErrors";
3650
+ "textEnabled": {
3651
+ "alias": "textEnabled";
3652
+ "required": false;
3653
+ "isSignal": true;
3654
+ };
3655
+ "sending": {
3656
+ "alias": "sending";
3584
3657
  "required": false;
3585
3658
  "isSignal": true;
3586
3659
  };
3587
3660
  }, {
3588
- "videoSelected": "videoSelected";
3589
- "invalidChange": "invalidChange";
3661
+ "closed": "closed";
3662
+ "send": "send";
3590
3663
  }, never, never, true, never>;
3591
3664
  }
3592
- export interface TemplateItem {
3593
- id: string;
3594
- name: string;
3595
- subject: string | null;
3596
- body: string;
3597
- isActive?: boolean;
3598
- /** Set when the API says whether this is a built-in system template (true) or one the company wrote (false); drives the System / Custom badge. Absent = no badge. */
3599
- isSystem?: boolean;
3600
- activeFrom?: string | null;
3601
- activeTo?: string | null;
3602
- useAllYear?: boolean;
3665
+ export interface ActiveConfirm {
3666
+ title: string;
3667
+ message: string;
3668
+ confirmLabel: string;
3669
+ cancelLabel: string;
3670
+ variant: 'danger' | 'primary' | 'warning';
3671
+ /** Optional bullet list rendered under the message (plain text). */
3672
+ details: string[];
3603
3673
  }
3604
- export declare class TemplatePickerComponent {
3605
- private readonly http;
3606
- /** API root from FORGEROUTE_CONFIG (e.g. a cross-origin prod API); falls back to same-origin `/api`. */
3607
- private readonly apiBase;
3608
- private readonly destroyRef;
3609
- private readonly toast;
3610
- private readonly host;
3611
- private readonly search$;
3612
- /** Filter results to a specific channel: 'email', 'text', or omit for all. */
3613
- readonly channel: import("@angular/core").InputSignal<"" | "text" | "email">;
3614
- readonly selectedId: import("@angular/core").InputSignal<string | null>;
3615
- readonly label: import("@angular/core").InputSignal<string>;
3616
- /** Shows the red required asterisk (same as the library inputs) — e.g. when a template must be picked to send. */
3617
- readonly required: import("@angular/core").InputSignal<boolean>;
3618
- /** Reveal the built-in "<label> is required." message now (e.g. after a failed Send click); otherwise it shows after the field was blurred. */
3619
- readonly showErrors: import("@angular/core").InputSignal<boolean>;
3620
- readonly templateSelected: import("@angular/core").OutputEmitterRef<TemplateItem>;
3621
- readonly previewClick: import("@angular/core").OutputEmitterRef<{
3622
- subject: string;
3623
- body: string;
3624
- }>;
3625
- /** Emits whenever `invalid` flips (required and no template picked). */
3626
- readonly invalidChange: import("@angular/core").OutputEmitterRef<boolean>;
3627
- readonly search: import("@angular/core").WritableSignal<string>;
3628
- readonly results: import("@angular/core").WritableSignal<TemplateItem[]>;
3629
- readonly loading: import("@angular/core").WritableSignal<boolean>;
3630
- /** Dropdown open state — like ui-contact-picker: open while focused with 2+ characters typed. */
3631
- readonly showResults: import("@angular/core").WritableSignal<boolean>;
3632
- /** Keyboard-highlighted option index (-1 = none). */
3633
- readonly activeIndex: import("@angular/core").WritableSignal<number>;
3634
- /** The picked template id: follows `[selectedId]`; a pick made in the picker overrides it until the host changes `[selectedId]`. */
3635
- private readonly picked;
3636
- private readonly reveal;
3637
- /** `UiFieldValidity`: true while `required` and no template is picked. */
3638
- readonly invalid: import("@angular/core").Signal<boolean>;
3639
- /** "<label> is required." while invalid ('' otherwise), shown or not. */
3640
- readonly errorMessage: import("@angular/core").Signal<string>;
3641
- /** `errorMessage` once the field was blurred or `showErrors` is set. */
3642
- readonly visibleError: import("@angular/core").Signal<string>;
3643
- /** Polite announcement for screen readers: searching, the result count, or no results (only while the list is open). */
3644
- readonly liveText: import("@angular/core").Signal<string>;
3645
- private static nextId;
3646
- private readonly uid;
3647
- readonly inputId: string;
3648
- readonly listId: string;
3649
- readonly errorId: string;
3650
- optionId(i: number): string;
3651
- private blurTimer;
3652
- constructor();
3653
- onInput(q: string): void;
3654
- onFocus(): void;
3655
- onBlur(): void;
3656
- private clearBlurTimer;
3674
+ export declare class ConfirmService {
3675
+ private _open;
3676
+ private _active;
3677
+ private _resolve;
3678
+ readonly open: import("@angular/core").Signal<boolean>;
3679
+ readonly active: import("@angular/core").Signal<ActiveConfirm | null>;
3657
3680
  /**
3658
- * ARIA combobox keys: ArrowDown/ArrowUp open the list and move the highlight (wrapping), Home/End jump to the first /
3659
- * last option, Enter picks the highlighted option, Escape closes the list only (so a surrounding side panel / modal
3660
- * stays open; with the list closed it passes through). Tab selects nothing.
3681
+ * Live <ui-confirm-outlet> instances, oldest first. Every ui-data-table renders an outlet, so
3682
+ * several can exist at once (e.g. during a route change the next page's table is created before
3683
+ * the previous page's is destroyed). Only the oldest live outlet renders the dialog; when it is
3684
+ * destroyed the next one takes over, so a confirm always has somewhere to render.
3661
3685
  */
3662
- onKeydown(e: KeyboardEvent): void;
3663
- /** Highlights option `i` and scrolls it into view inside the dropdown. */
3664
- private setActive;
3665
- /** Timestamps of the last mousedown activation: the click that follows it is the same gesture, not a second action. */
3666
- private lastOptionMouse;
3667
- private lastPreviewMouse;
3668
- onOptionMouseDown(): void;
3669
- /** Activation by assistive tech / a virtual cursor arrives as a click without a preceding mousedown. */
3670
- onOptionClick(tpl: TemplateItem): void;
3671
- onPreviewMouseDown(tpl: TemplateItem): void;
3672
- onPreviewClick(tpl: TemplateItem): void;
3673
- select(tpl: TemplateItem): void;
3674
- preview(tpl: TemplateItem): void;
3675
- private readonly sampleVars;
3676
- previewText(raw: string): string;
3677
- isCurrentlyActive(tpl: TemplateItem): boolean;
3678
- activeDateLabel(tpl: TemplateItem): string;
3679
- static ɵfac: i0.ɵɵFactoryDeclaration<TemplatePickerComponent, never>;
3680
- static ɵcmp: i0.ɵɵComponentDeclaration<TemplatePickerComponent, "ui-template-picker", never, {
3681
- "channel": {
3682
- "alias": "channel";
3686
+ private readonly _outlets;
3687
+ readonly primaryOutlet: import("@angular/core").Signal<object>;
3688
+ registerOutlet(outlet: object): void;
3689
+ unregisterOutlet(outlet: object): void;
3690
+ confirm(config: {
3691
+ title: string;
3692
+ message: string;
3693
+ confirmLabel?: string;
3694
+ cancelLabel?: string;
3695
+ variant?: 'danger' | 'primary' | 'warning';
3696
+ details?: string[];
3697
+ }): Promise<boolean>;
3698
+ dismiss(confirmed: boolean): void;
3699
+ static ɵfac: i0.ɵɵFactoryDeclaration<ConfirmService, never>;
3700
+ static ɵprov: i0.ɵɵInjectableDeclaration<any>;
3701
+ }
3702
+ export declare class ConfirmOutletComponent implements OnInit, OnDestroy {
3703
+ protected readonly svc: ConfirmService;
3704
+ protected readonly _isPrimary: import("@angular/core").Signal<boolean>;
3705
+ ngOnInit(): void;
3706
+ ngOnDestroy(): void;
3707
+ static ɵfac: i0.ɵɵFactoryDeclaration<ConfirmOutletComponent, never>;
3708
+ static ɵcmp: i0.ɵɵComponentDeclaration<ConfirmOutletComponent, "ui-confirm-outlet", never, {}, {}, never, never, true, never>;
3709
+ }
3710
+ export declare class EmptyStateComponent {
3711
+ readonly message: import("@angular/core").InputSignal<string>;
3712
+ readonly title: import("@angular/core").InputSignal<string>;
3713
+ readonly iconType: import("@angular/core").InputSignal<string>;
3714
+ static ɵfac: i0.ɵɵFactoryDeclaration<EmptyStateComponent, never>;
3715
+ static ɵcmp: i0.ɵɵComponentDeclaration<EmptyStateComponent, "ui-empty-state", never, {
3716
+ "message": {
3717
+ "alias": "message";
3683
3718
  "required": false;
3684
3719
  "isSignal": true;
3685
3720
  };
3686
- "selectedId": {
3687
- "alias": "selectedId";
3721
+ "title": {
3722
+ "alias": "title";
3688
3723
  "required": false;
3689
3724
  "isSignal": true;
3690
3725
  };
3691
- "label": {
3692
- "alias": "label";
3726
+ "iconType": {
3727
+ "alias": "iconType";
3693
3728
  "required": false;
3694
3729
  "isSignal": true;
3695
3730
  };
3696
- "required": {
3697
- "alias": "required";
3731
+ }, {}, never, ["*"], true, never>;
3732
+ }
3733
+ export declare class ErrorStateComponent {
3734
+ readonly message: import("@angular/core").InputSignal<string>;
3735
+ readonly retryLabel: import("@angular/core").InputSignal<string>;
3736
+ readonly retrying: import("@angular/core").InputSignal<boolean>;
3737
+ readonly retry: import("@angular/core").OutputEmitterRef<void>;
3738
+ static ɵfac: i0.ɵɵFactoryDeclaration<ErrorStateComponent, never>;
3739
+ static ɵcmp: i0.ɵɵComponentDeclaration<ErrorStateComponent, "ui-error-state", never, {
3740
+ "message": {
3741
+ "alias": "message";
3698
3742
  "required": false;
3699
3743
  "isSignal": true;
3700
3744
  };
3701
- "showErrors": {
3702
- "alias": "showErrors";
3745
+ "retryLabel": {
3746
+ "alias": "retryLabel";
3747
+ "required": false;
3748
+ "isSignal": true;
3749
+ };
3750
+ "retrying": {
3751
+ "alias": "retrying";
3703
3752
  "required": false;
3704
3753
  "isSignal": true;
3705
3754
  };
3706
3755
  }, {
3707
- "templateSelected": "templateSelected";
3708
- "previewClick": "previewClick";
3709
- "invalidChange": "invalidChange";
3710
- }, never, never, true, never>;
3711
- }
3712
- /** One selectable row. `data` carries any host payload (a typed record, an id, ...) back through `(valueChange)`. */
3713
- export interface ComboboxOption<T = unknown> {
3714
- value: string;
3715
- label: string;
3716
- /** Secondary line under the label (trade, customer name, ...). */
3717
- description?: string;
3718
- disabled?: boolean;
3719
- data?: T;
3720
- }
3721
- /** The selected value: what `[value]` and `ngModel` / `FormControl` hold. */
3722
- export interface ComboboxSelection {
3723
- value: string;
3724
- label: string;
3725
- }
3726
- /**
3727
- * Search-as-you-type single select (WAI-ARIA 1.2 combobox with listbox popup). The HOST fetches: the combobox emits
3728
- * `(searchChange)` with the typed term (debounced) and renders whatever `[options]` currently is, so a host using
3729
- * `switchMap` is race-safe and a stale array never "sticks" (the active option is re-validated on every change).
3730
- *
3731
- * ## API
3732
- * - `[options]` `ComboboxOption[]` current results (`{ value, label, description?, disabled?, data? }`).
3733
- * - `[value]` `{ value, label } | null` the selection. Also what `ngModel` / `formControl` hold (same shape).
3734
- * - `[displayText]` text shown in the field instead of the selected label — use it for legacy / orphaned links:
3735
- * `displayText="Not linked: Legacy Co"` (with `[value]="null"`) or `displayText="Acme (no longer exists)"`.
3736
- * Pair it with `[displayWarning]="true"` for the amber "needs attention" style. A `displayText` with no `value` is
3737
- * shown and has a clear button, but counts as EMPTY for `required`.
3738
- * - `[loading]` shows "Searching…" and announces it. `[noResultsText]` (default "No results found").
3739
- * - `[minChars]` (default 0): below it nothing is searched or listed ("Type at least N characters"). 0 = the list opens
3740
- * on focus and `(searchChange)` fires with '' so the host can show its initial results.
3741
- * - `[debounce]` ms between the last keystroke and `(searchChange)` (default 250). Focus / ArrowDown-open emit immediately.
3742
- * - `[label] [ariaLabel] [placeholder] [required] [hint] [error] [disabled] [showErrors]` like `ui-text-input`
3743
- * (host `[error]` wins over the built-in "<label> is required."; messages show after blur or `showErrors`).
3744
- * - `(searchChange)` string, `(valueChange)` `ComboboxOption | null` (the full chosen option, null when cleared),
3745
- * `(invalidChange)` boolean, `(focused)`, `(blurred)`. Validity: `UiFieldValidity` token + Angular `Validator`.
3746
- *
3747
- * ## Behaviour
3748
- * - The field shows the selected label. Focusing it selects that text; typing starts a NEW search and the old value is
3749
- * kept until another option is picked or the clear (x) button is pressed. Leaving the field (blur / Tab / Escape)
3750
- * discards the typed text and shows the selection again.
3751
- * - Escape: if the list is open it closes the list ONLY (stopPropagation, so a surrounding side panel / modal stays
3752
- * open). If the list is already closed and text was typed, it discards the text (also stopped). Otherwise the key
3753
- * passes through to the panel.
3754
- * - Tab never selects: it closes the list and moves on.
3755
- *
3756
- * ## Keyboard
3757
- * ArrowDown / ArrowUp open the list and move the active option (wraps, skips disabled). Home / End jump to the first /
3758
- * last option while the list is open. Enter picks the active option (and does not submit a surrounding form while open).
3759
- * Escape / Tab as above. Typing opens the list. Mouse: options are picked on mousedown so blur does not swallow it.
3760
- *
3761
- * ## ARIA
3762
- * The inner `<input>` is `role="combobox"` with `aria-expanded`, `aria-controls` (the listbox, while open),
3763
- * `aria-autocomplete="list"`, `aria-activedescendant`, `aria-invalid`, `aria-required`, `aria-describedby` (hint / error);
3764
- * the `<label for>` names it. The popup is `role="listbox"` of `role="option"` rows (`aria-selected` = active row,
3765
- * stable ids). A polite `role="status"` region announces "Searching", "N results available" or the no-results text.
3766
- *
3767
- * ## Example
3768
- * ```html
3769
- * <ui-combobox label="Subcontractor" [required]="true" [options]="opts()" [loading]="loading()"
3770
- * [value]="sub()" [displayText]="legacyName() ? 'Not linked: ' + legacyName() : ''" [error]="err()"
3771
- * (searchChange)="search$.next($event)" (valueChange)="onPick($event)" />
3772
- * ```
3773
- */
3774
- export declare class ComboboxComponent<T = unknown> implements ControlValueAccessor, Validator, UiFieldValidity {
3775
- readonly label: import("@angular/core").InputSignal<string>;
3776
- /** Accessible name for a field with no visible label. */
3777
- readonly ariaLabel: import("@angular/core").InputSignal<string>;
3778
- readonly placeholder: import("@angular/core").InputSignal<string>;
3779
- readonly required: import("@angular/core").InputSignal<boolean>;
3780
- readonly hint: import("@angular/core").InputSignal<string>;
3781
- /** Host error message; always wins over the built-in message. */
3782
- readonly error: import("@angular/core").InputSignal<string>;
3783
- readonly showErrors: import("@angular/core").InputSignal<boolean>;
3784
- /** Current results (host-owned). */
3785
- readonly options: import("@angular/core").InputSignal<ComboboxOption<T>[]>;
3786
- readonly loading: import("@angular/core").InputSignal<boolean>;
3787
- readonly noResultsText: import("@angular/core").InputSignal<string>;
3788
- /** Characters needed before searching / listing. 0 = open on focus. */
3789
- readonly minChars: import("@angular/core").InputSignal<number>;
3790
- /** Milliseconds between the last keystroke and `(searchChange)`. */
3791
- readonly debounce: import("@angular/core").InputSignal<number>;
3792
- /** The selection. */
3793
- readonly value: import("@angular/core").InputSignal<ComboboxSelection | null>;
3794
- /** Text shown instead of the selected label (legacy / orphaned links). */
3795
- readonly displayText: import("@angular/core").InputSignal<string>;
3796
- /** Amber style for a legacy / orphaned `displayText`. */
3797
- readonly displayWarning: import("@angular/core").InputSignal<boolean>;
3798
- /** Typed term, debounced (immediate on focus / open). */
3799
- readonly searchChange: import("@angular/core").OutputEmitterRef<string>;
3800
- /** The chosen option, or null when cleared. */
3801
- readonly valueChange: import("@angular/core").OutputEmitterRef<ComboboxOption<T> | null>;
3802
- readonly invalidChange: import("@angular/core").OutputEmitterRef<boolean>;
3803
- readonly focused: import("@angular/core").OutputEmitterRef<void>;
3804
- readonly blurred: import("@angular/core").OutputEmitterRef<void>;
3805
- protected readonly _disabledInput: import("@angular/core").InputSignal<boolean>;
3806
- private readonly _cvaDisabled;
3807
- protected readonly disabled: import("@angular/core").Signal<boolean>;
3808
- private readonly _field;
3809
- private readonly _host;
3810
- private readonly _injector;
3811
- private readonly _destroyRef;
3812
- /** Follows `[value]`; ngModel / formControl writes and user picks override it until `[value]` changes. */
3813
- protected readonly _selected: import("@angular/core").WritableSignal<ComboboxSelection | null>;
3814
- private readonly _text;
3815
- private readonly _editing;
3816
- protected readonly _open: import("@angular/core").WritableSignal<boolean>;
3817
- /** Reset to the first enabled option whenever `[options]` changes, so a stale index never survives new results. */
3818
- protected readonly _activeIndex: import("@angular/core").WritableSignal<number>;
3819
- protected readonly _uid: number;
3820
- protected readonly _inputId: string;
3821
- protected readonly _listId: string;
3822
- protected readonly _descId: string;
3823
- private readonly _reveal;
3824
- private readonly _issue;
3825
- readonly invalid: import("@angular/core").Signal<boolean>;
3826
- readonly errorMessage: import("@angular/core").Signal<string>;
3827
- protected readonly _activeError: import("@angular/core").Signal<string>;
3828
- protected readonly _inputText: import("@angular/core").Signal<string>;
3829
- protected readonly _showClear: import("@angular/core").Signal<boolean>;
3830
- protected readonly _belowMin: import("@angular/core").Signal<boolean>;
3831
- protected readonly _statusText: import("@angular/core").Signal<string>;
3832
- protected readonly _liveText: import("@angular/core").Signal<string>;
3833
- protected readonly _activeDescendant: import("@angular/core").Signal<string | null>;
3834
- private _debounceTimer;
3835
- private _onChange;
3836
- private _onTouched;
3837
- private _onValidatorChange;
3838
- constructor();
3839
- ngOnChanges(): void;
3840
- writeValue(val: ComboboxSelection | null): void;
3841
- validate(control: AbstractControl): ValidationErrors | null;
3842
- registerOnValidatorChange(fn: () => void): void;
3843
- registerOnChange(fn: (v: ComboboxSelection | null) => void): void;
3844
- registerOnTouched(fn: () => void): void;
3845
- setDisabledState(d: boolean): void;
3846
- private _check;
3847
- /** What the user typed (trimmed); '' while not editing. */
3848
- private _term;
3849
- protected _optionId(i: number): string;
3850
- private _firstEnabled;
3851
- private _emitSearch;
3852
- private _cancelTimer;
3853
- private _revert;
3854
- private _openList;
3855
- private _move;
3856
- private _setActive;
3857
- protected onInput(event: Event): void;
3858
- protected onFocus(event: FocusEvent): void;
3859
- protected onClick(): void;
3860
- protected onBlur(): void;
3861
- protected onKeydown(e: KeyboardEvent): void;
3862
- protected onOptionMouseDown(e: MouseEvent, o: ComboboxOption<T>): void;
3863
- protected onOptionHover(i: number, o: ComboboxOption<T>): void;
3864
- /** Select `o` (also callable by a host through a template ref). */
3865
- choose(o: ComboboxOption<T>): void;
3866
- /** Clear the selection (the x button). */
3867
- clear(): void;
3868
- static ɵfac: i0.ɵɵFactoryDeclaration<ComboboxComponent<any>, never>;
3869
- static ɵcmp: i0.ɵɵComponentDeclaration<ComboboxComponent<any>, "ui-combobox", never, {
3870
- "label": {
3871
- "alias": "label";
3872
- "required": false;
3873
- "isSignal": true;
3874
- };
3875
- "ariaLabel": {
3876
- "alias": "ariaLabel";
3877
- "required": false;
3878
- "isSignal": true;
3879
- };
3880
- "placeholder": {
3881
- "alias": "placeholder";
3882
- "required": false;
3883
- "isSignal": true;
3884
- };
3885
- "required": {
3886
- "alias": "required";
3887
- "required": false;
3888
- "isSignal": true;
3889
- };
3890
- "hint": {
3891
- "alias": "hint";
3892
- "required": false;
3893
- "isSignal": true;
3894
- };
3895
- "error": {
3896
- "alias": "error";
3897
- "required": false;
3898
- "isSignal": true;
3899
- };
3900
- "showErrors": {
3901
- "alias": "showErrors";
3902
- "required": false;
3903
- "isSignal": true;
3904
- };
3905
- "options": {
3906
- "alias": "options";
3907
- "required": false;
3908
- "isSignal": true;
3909
- };
3910
- "loading": {
3911
- "alias": "loading";
3912
- "required": false;
3913
- "isSignal": true;
3914
- };
3915
- "noResultsText": {
3916
- "alias": "noResultsText";
3917
- "required": false;
3918
- "isSignal": true;
3919
- };
3920
- "minChars": {
3921
- "alias": "minChars";
3922
- "required": false;
3923
- "isSignal": true;
3924
- };
3925
- "debounce": {
3926
- "alias": "debounce";
3927
- "required": false;
3928
- "isSignal": true;
3929
- };
3930
- "value": {
3931
- "alias": "value";
3932
- "required": false;
3933
- "isSignal": true;
3934
- };
3935
- "displayText": {
3936
- "alias": "displayText";
3937
- "required": false;
3938
- "isSignal": true;
3939
- };
3940
- "displayWarning": {
3941
- "alias": "displayWarning";
3942
- "required": false;
3943
- "isSignal": true;
3944
- };
3945
- "_disabledInput": {
3946
- "alias": "disabled";
3947
- "required": false;
3948
- "isSignal": true;
3949
- };
3950
- }, {
3951
- "searchChange": "searchChange";
3952
- "valueChange": "valueChange";
3953
- "invalidChange": "invalidChange";
3954
- "focused": "focused";
3955
- "blurred": "blurred";
3956
- }, never, never, true, never>;
3957
- }
3958
- /**
3959
- * Types and pure helpers for the signer side of sending documents (docs/send-documents-contract.md, Addendum 2026-10-19).
3960
- * Everything here is app-agnostic: the roles are `signer1 .. signer4`, labels / names come from the host.
3961
- */
3962
- /** A CUSTOMER signer role. The countersigner (the sending user) is never a role: it is the document's own setting. */
3963
- export type SignerRole = 'signer1' | 'signer2' | 'signer3' | 'signer4';
3964
- /** All roles, in signing order (the order is strictly sequential by role number). */
3965
- export declare const SIGNER_ROLES: readonly SignerRole[];
3966
- /** The part of a document the host's `resolveRoles` callback is called with. */
3967
- export interface DocumentRolesTarget {
3968
- id: string;
3969
- title: string;
3970
- fileName: string | null;
3971
- }
3972
- /**
3973
- * Turns the signer section on (`documentSigners` of `ui-send-message-panel`). `null` / not passed = the panel is the plain single-recipient
3974
- * panel and nothing about signers is shown or sent.
3975
- */
3976
- export interface DocumentSignersConfig {
3977
- /** Largest number of customer signers the panel accepts (roles above it are ignored). Default 4. */
3978
- maxSigners?: number;
3979
- /** Labels per role. Default `Signer 1` .. `Signer 4`. */
3980
- roleLabels?: Partial<Record<SignerRole, string>>;
3981
- /** May one person fill two roles? Default false. */
3982
- allowSameContactInRoles?: boolean;
3983
- /** Must every further signer have an email address (the chain emails each signer)? Default true; `false` only lets Send through with a warning-free row (the server then decides). */
3984
- requireSignerEmail?: boolean;
3985
- /** Name shown in the read-only countersign line ("Countersigned by <name> after all signers."). Default `you`. */
3986
- countersignerName?: string;
3987
- /**
3988
- * Reads the customer roles a document defines when its `GET /documents` row has no `signerRoles` key (an app that keeps its
3989
- * placements elsewhere). Called once per chosen document, and again on "Retry". A failure blocks Send and offers a retry. An empty
3990
- * list = the document has no signature fields (informational).
3991
- */
3992
- resolveRoles?: (doc: DocumentRolesTarget) => Observable<SignerRole[]>;
3993
- }
3994
- /** One entry of `documents.signers` (present only for a document with MORE THAN ONE customer signer, always complete). */
3995
- export interface SendSigner {
3996
- role: SignerRole;
3997
- contactId: string;
3998
- name: string;
3999
- email: string | null;
4000
- /** 1..N, equal to the role number (strictly sequential). */
4001
- order: number;
4002
- }
4003
- /** Values the host has for THIS send, keyed by the keys it declares in `documentContextTypes` (e.g. `{ propertyId: '…' }`). */
4004
- export type SendContext = Record<string, string>;
4005
- /** One context key the app's backend accepts. */
4006
- export interface ContextTypeDef {
4007
- key: string;
4008
- label: string;
4009
- }
4010
- /** What `documentMergeCheck` sends (default route `POST <baseUrl>/documents/merge-check`). */
4011
- export interface MergeCheckRequest {
4012
- documentIds: string[];
4013
- customerId?: string;
4014
- signers?: SendSigner[];
4015
- context?: SendContext;
4016
- }
4017
- /** One data field that would be left empty. */
4018
- export interface MergeCheckEmptyField {
4019
- key: string;
4020
- label: string;
4021
- page?: number;
4022
- /** `NO_CONTEXT` | `NO_DATA` | `UNKNOWN_PATH` (other values are shown generically). */
4023
- reason?: string;
4024
- /** Optional plain-language reason from the server ("no property selected"); wins over the generic text of `reason`. */
4025
- detail?: string;
4026
- }
4027
- export interface MergeCheckResult {
4028
- documents: {
4029
- documentId: string;
4030
- title?: string;
4031
- empty: MergeCheckEmptyField[];
4032
- }[];
4033
- }
4034
- /** A host function that runs the merge check itself (instead of the default route). */
4035
- export type MergeCheckFn = (req: MergeCheckRequest) => Observable<MergeCheckResult>;
4036
- /** The structural part of a chosen document the helpers below read. */
4037
- export interface SignerDocLike {
4038
- id: string;
4039
- title: string;
4040
- requiresCountersign?: boolean;
4041
- /** The row says whether the countersign box is placed on the document. `false` (with `requiresCountersign`) offers the "Place your countersignature box" link; `undefined` = unknown = no link. */
4042
- hasCountersignPlacement?: boolean;
4043
- signerRoles?: SignerRole[];
4044
- hasMapping?: boolean;
4045
- hasDataFields?: boolean;
4046
- }
4047
- /** Where the roles of a document without a `signerRoles` key stand when the host resolves them. */
4048
- export interface RoleState {
4049
- status: 'loading' | 'ready' | 'error';
4050
- roles: SignerRole[];
4051
- }
4052
- /** What the signer logic concluded for the chosen documents (only on the value when `documentSigners` is on). */
4053
- export interface DocumentSignerInfo {
4054
- /** `ready` once every document's roles are known; `loading` / `error` block Send. */
4055
- status: 'loading' | 'ready' | 'error';
4056
- /** Every chosen document has no signature fields: the send is informational (view-only). */
4057
- informational: boolean;
4058
- /** Customer roles of the ONE chosen document (always starting at signer1, no gaps). Empty for several documents / informational. */
4059
- roles: SignerRole[];
4060
- /** Exactly one document, with more than one customer signer. */
4061
- multiSigner: boolean;
4062
- /** A document that is sent for signing requires the sender's countersignature. */
4063
- countersign: boolean;
4064
- /**
4065
- * Only present (and non-empty) when a signable chosen document requires the countersignature and its row says the countersign box is NOT
4066
- * placed (`hasCountersignPlacement === false`): the documents the "Place your countersignature box" link is offered for.
4067
- */
4068
- countersignUnplaced?: {
4069
- id: string;
4070
- title: string;
4071
- }[];
4072
- /** Several documents are chosen and one of them has several signers (it still goes to the one recipient). */
4073
- multiDocumentNote: boolean;
4074
- /** Under the document chip: what the mapping covers ('' when unknown). */
4075
- fieldsLine: string;
4076
- }
4077
- export declare const SIGNER_ROLE_LABEL_DEFAULT: (role: SignerRole) => string;
4078
- export declare function roleNumber(role: SignerRole): number;
4079
- /** The label of a role: the host's `roleLabels` entry, else `Signer N`. */
4080
- export declare function signerRoleLabel(role: SignerRole, cfg?: DocumentSignersConfig | null): string;
4081
- /** Valid roles only (`signer1..N`, N ≤ maxSigners), unique, sorted. Anything else is dropped. */
4082
- export declare function normalizeRoles(raw: unknown, maxSigners?: number): SignerRole[];
4083
- /**
4084
- * The customer roles a send needs from a document's saved roles: signer1 is always the recipient, and the roles run without gaps up to
4085
- * the highest saved one (a partial list is never sent). `[]` stays `[]` (no signature fields).
4086
- */
4087
- export declare function effectiveRoles(saved: SignerRole[]): SignerRole[];
4088
- /** True when the document has mapped data fields (the pre-send "fields that will be empty" check applies to it only). */
4089
- export declare function hasMappedDataFields(doc: SignerDocLike): boolean;
4090
- /** What the signer logic concludes for the chosen documents. `null` = `documentSigners` is off or nothing is chosen. */
4091
- export declare function describeDocumentSigners(docs: SignerDocLike[], states: Record<string, RoleState>, cfg: DocumentSignersConfig | null | undefined): DocumentSignerInfo | null;
4092
- /** The read-only countersign line ('' = not shown). */
4093
- export declare function countersignLine(info: DocumentSignerInfo | null, cfg: DocumentSignersConfig | null | undefined, viaDocuSign: boolean): string;
4094
- export interface SignerPick {
4095
- id: string;
4096
- name: string;
4097
- email?: string | null;
4098
- }
4099
- /** The complete `signers` list (recipient first), or null while any role has no contact. */
4100
- export declare function buildSigners(roles: SignerRole[], recipient: SignerPick, picks: Partial<Record<SignerRole, SignerPick | null>>): SendSigner[] | null;
4101
- /**
4102
- * The first problem per role (`''` = fine) in signing order: empty → `<Role label> is required.`, no email → `<Name> has no email address.`,
4103
- * the same person twice (unless allowed) → `<Name> is already <Earlier role label>.` on the later row.
4104
- */
4105
- export declare function signerProblems(roles: SignerRole[], recipient: SignerPick, picks: Partial<Record<SignerRole, SignerPick | null>>, cfg: DocumentSignersConfig | null | undefined): Partial<Record<SignerRole, string>>;
4106
- /** Only the declared context keys, with non-blank values; `undefined` when nothing is left. */
4107
- export declare function forwardContext(ctx: SendContext | null | undefined, types: readonly ContextTypeDef[]): {
4108
- context?: SendContext;
4109
- dropped: string[];
4110
- };
4111
- /** One merge-check field as text: `Property Address (no property selected)`. */
4112
- export declare function mergeFieldText(f: MergeCheckEmptyField): string;
4113
- /** The warning lines of a merge-check answer: one line for one document, `<title>: …` per document for several. Nothing when nothing is empty. */
4114
- export declare function mergeWarningLines(res: MergeCheckResult | null | undefined, docTitles: Record<string, string>): string[];
4115
- /** The accessible name of the "Place your countersignature box" link of a document. */
4116
- export declare function countersignPlaceLabel(title: string): string;
4117
- /** What the sender wants done with the chosen documents. Same values as the backend (`ESIGN` | `ATTACH` | `BOTH`). */
4118
- export type DocumentSendPurpose = 'ESIGN' | 'ATTACH' | 'BOTH';
4119
- /** How the request reaches the recipient — derived from the channel: the Email tab sends `EMAIL`, the Text tab `TEXT`. */
4120
- export type DocumentSendDelivery = 'EMAIL' | 'TEXT';
4121
- /** Who sends a signature request: the app's own e-signature (`NATIVE`) or DocuSign. */
4122
- export type DocumentSignatureProvider = 'NATIVE' | 'DOCUSIGN';
4123
- /** One document from `GET <baseUrl>/documents`, reduced to what the picker needs. */
4124
- export interface DocumentOption {
4125
- id: string;
4126
- title: string;
4127
- fileName: string | null;
4128
- /** True when the document has a stored file (so it can be attached to an email). */
4129
- hasFile: boolean;
4130
- /** Only present (and true) when the row says the document needs the sender's countersignature (`requiresCountersign` on the `GET /documents` row): then a DocuSign send offers "Require my countersignature after client signs". */
4131
- requiresCountersign?: boolean;
4132
- /** Only with `documentSigners` and `requiresCountersign`: the row says whether the countersign box is placed. `false` shows the "Place your countersignature box" link after the countersign line (`mapFieldsClick`); absent = unknown = no link. */
4133
- hasCountersignPlacement?: boolean;
4134
- /** Only with `documentSigners`: the document's customer roles from the `GET /documents` row (`signerRoles`). `[]` = no signature fields (informational). */
4135
- signerRoles?: SignerRole[];
4136
- /** The row says the document has saved placements of any kind (drives the "Fields placed for N signers" line and the merge check). */
4137
- hasMapping?: boolean;
4138
- /** The row says the document has mapped DATA fields (the pre-send merge check applies to it); when absent, `hasMapping` stands in. */
4139
- hasDataFields?: boolean;
4140
- /** Only for an envelope's document (`DocumentSeed.status`). */
4141
- status?: string;
4142
- }
4143
- /** A document the form starts with (`initialDocuments`). `hasFile` defaults to true. */
4144
- export interface DocumentSeed {
4145
- id: string;
4146
- title: string;
4147
- fileName?: string | null;
4148
- hasFile?: boolean;
4149
- requiresCountersign?: boolean;
4150
- hasCountersignPlacement?: boolean;
4151
- signerRoles?: SignerRole[];
4152
- hasMapping?: boolean;
4153
- hasDataFields?: boolean;
4154
- /** An envelope's document that is not `ACTIVE` (e.g. `ARCHIVED`) blocks the send: "<title> is archived, so this envelope can't be sent. …". */
4155
- status?: string;
4156
- }
4157
- /**
4158
- * An existing envelope the panel sends (`documentEnvelope`): its documents are fixed (no search, no remove) and the request is sent, not
4159
- * created. Give `documents` when the host has read them already, or `loadDocuments` to let the panel read them (it shows the wait, and a
4160
- * failure blocks Send with a Retry button). With neither, the envelope has no documents and cannot be sent.
4161
- */
4162
- export interface DocumentEnvelopeTarget {
4163
- id: string;
4164
- /** Shown in the subject suggestion ("Signature required: <name>") and in the success toast. */
4165
- name: string;
4166
- documents?: DocumentSeed[];
4167
- loadDocuments?: () => Observable<DocumentSeed[]>;
4168
- }
4169
- /** The document a host's `documentPreview` handler is called with. */
4170
- export interface DocumentPreviewTarget {
4171
- id: string;
4172
- title: string;
4173
- fileName: string | null;
4174
- }
4175
- /** The recipient the panel currently holds (as the panel's `contactId` / `contactName` / `contactEmail` / `contactPhone` inputs). */
4176
- export interface DocumentPreviewContact {
4177
- id: string;
4178
- name: string;
4179
- email: string;
4180
- phone: string;
4181
- }
4182
- /**
4183
- * Second argument of `documentPreview`: who the document is being sent to, so the host can preview it filled for that recipient.
4184
- * `contact` is `null` when the panel has no recipient (all four contact inputs blank); `sendContext` is the panel's `sendContext` input
4185
- * as given (not filtered by `documentContextTypes`) or `null`.
4186
- */
4187
- export interface DocumentPreviewContext {
4188
- contact: DocumentPreviewContact | null;
4189
- sendContext: SendContext | null;
4190
- }
4191
- /**
4192
- * Opens a document for preview (the host knows its own route / viewer). Called synchronously inside the click. The second argument
4193
- * is new and optional to use: a handler that only declares `doc` keeps working.
4194
- */
4195
- export type DocumentPreviewHandler = (doc: DocumentPreviewTarget, context: DocumentPreviewContext) => void;
4196
- /**
4197
- * Turns on the "Expiry and Reminders" settings of the document section and sets their starting values (the keys you leave out start at
4198
- * the defaults below). `null` / not passed = the settings are not shown and nothing about them is sent.
4199
- */
4200
- export interface DocumentSigningOptions {
4201
- /** Days until an unsigned request expires: whole number 1-90 (default 7). */
4202
- expiryDays?: number;
4203
- /** Days between reminders: whole number 1-30 (default 2). */
4204
- reminderIntervalDays?: number;
4205
- /** How many reminders at most: whole number 0-10 (default 3). */
4206
- maxReminders?: number;
4207
- }
4208
- /** Defaults and limits of the signing settings (the same limits the servers enforce). */
4209
- export declare const DEFAULT_SIGNING_OPTIONS: {
4210
- readonly expiryDays: 7;
4211
- readonly reminderIntervalDays: 2;
4212
- readonly maxReminders: 3;
4213
- };
4214
- export declare const SIGNING_LIMITS: {
4215
- readonly expiryDays: {
4216
- readonly min: 1;
4217
- readonly max: 90;
4218
- readonly label: "Expiry (days)";
4219
- };
4220
- readonly reminderIntervalDays: {
4221
- readonly min: 1;
4222
- readonly max: 30;
4223
- readonly label: "Reminder Interval (days)";
4224
- };
4225
- readonly maxReminders: {
4226
- readonly min: 0;
4227
- readonly max: 10;
4228
- readonly label: "Max Reminders";
4229
- };
4230
- };
4231
- export declare const DOCUMENT_PROVIDER_OPTIONS: RadioOption[];
4232
- /** The value `ui-document-send-options` emits and the message forms turn into `SendEmailPayload.documents` / `SendTextPayload.documents`. */
4233
- export interface DocumentSendValue {
4234
- documentIds: string[];
4235
- documents: DocumentOption[];
4236
- purpose: DocumentSendPurpose;
4237
- delivery: DocumentSendDelivery;
4238
- /** Only when the signing settings are shown (host `signing` input), valid and the request is a native e-signature one. */
4239
- expiryDays?: number;
4240
- reminderIntervalDays?: number;
4241
- maxReminders?: number;
4242
- /** Only when the provider choice is offered (`docuSignConnected` and exactly one document on the email channel). */
4243
- provider?: DocumentSignatureProvider;
4244
- /** Only with `provider: 'DOCUSIGN'`. */
4245
- docuSign?: {
4246
- countersign: boolean;
4247
- };
4248
- /** Only when `signers` (the host's `documentSigners`) is on and a document is chosen: what the signer logic concluded. Never part of the payload. */
4249
- signerInfo?: DocumentSignerInfo;
4250
- }
4251
- export declare const DOCUMENT_PURPOSE_OPTIONS: SelectOption[];
4252
- /**
4253
- * ui-document-send-options — choose the documents that go out with an email or a text.
4254
- *
4255
- * Search-as-you-type over `GET <baseUrl>/documents?search=&size=20` (nothing is requested before 2 characters, the combobox
4256
- * debounces 250 ms, a newer search cancels an older one), the chosen documents shown as removable chips, and — on the email channel — a
4257
- * "What should the recipient do?" select (e-signature / attachment / both). On the text channel documents can only go as a
4258
- * link, so the purpose is fixed to e-signature and the select is not shown.
4259
- *
4260
- * Optional parts, all off by default (hosts reach them through the same-named inputs of `ui-send-message-panel`):
4261
- * - `signing` — "Expiry and Reminders" (expiry days, reminder interval, max reminders) for native e-signature requests;
4262
- * - `docuSignConnected` — "Native E-Sign / Send via DocuSign" choice (email channel, exactly one document);
4263
- * - `documentPreview` — "Preview Document" button(s) that call the host's handler.
4264
- * - `signers` — the signer logic of the panel's `documentSigners` (a document's customer roles, informational documents, the
4265
- * one-signer DocuSign rule, the document's own countersign setting); the value then carries `signerInfo`;
4266
- * - `envelope` — an existing envelope: its documents are the fixed list (given, or read through `loadDocuments`).
4267
- *
4268
- * The signing settings are ONE collapsed summary line ("Signing options: expires in 7 days, ...") with a Change / Hide button.
4269
- *
4270
- * It is embedded by `ui-send-message-panel` (`[documents]="true"`); it can also be used on its own.
4271
- *
4272
- * ```html
4273
- * <ui-document-send-options channel="email" [showErrors]="touched()" (valueChange)="docs.set($event)" (invalidChange)="docsInvalid.set($event)" />
4274
- * ```
4275
- *
4276
- * Validity: provides `UiFieldValidity` (`invalid` / `errorMessage`) and the `invalidChange` output. Invalid when `required`
4277
- * and nothing is chosen, when the purpose is "Send as attachment" and a chosen document has no stored file, or when a shown signing
4278
- * setting is blank / out of range. Messages
4279
- * show only while `showErrors` is true.
4280
- */
4281
- export declare class DocumentSendOptionsComponent implements UiFieldValidity {
4282
- private readonly http;
4283
- private readonly destroyRef;
4284
- /** API root from FORGEROUTE_CONFIG (e.g. a cross-origin prod API); falls back to same-origin `/api`. */
4285
- private readonly apiBase;
4286
- /** `email` → purpose select + attachment allowed; `text` → link only (purpose fixed to e-signature). */
4287
- readonly channel: import("@angular/core").InputSignal<"text" | "email">;
4288
- readonly label: import("@angular/core").InputSignal<string>;
4289
- /** When true, at least one document must be chosen. The message forms leave it false: documents are optional there. */
4290
- readonly required: import("@angular/core").InputSignal<boolean>;
4291
- /** Shows the validation message (bind it to the host's "tried to submit" flag). */
4292
- readonly showErrors: import("@angular/core").InputSignal<boolean>;
4293
- readonly valueChange: import("@angular/core").OutputEmitterRef<DocumentSendValue>;
4294
- readonly invalidChange: import("@angular/core").OutputEmitterRef<boolean>;
4295
- /**
4296
- * Which purposes the app's backend supports (default: all three). With a single purpose the select is hidden and that
4297
- * purpose is always sent — e.g. `['ESIGN']` for an app that only does e-signature.
4298
- */
4299
- readonly purposes: import("@angular/core").InputSignal<DocumentSendPurpose[]>;
4300
- /**
4301
- * Documents already chosen when the form opens (e.g. the row the user clicked "Send Document" on): shown as chips and part
4302
- * of the value straight away; the user can remove them or add more. Read once — later changes to the input are ignored.
4303
- * `hasFile` defaults to true (an attachment check then relies on the server's answer).
4304
- */
4305
- readonly initialDocuments: import("@angular/core").InputSignal<DocumentSeed[]>;
4306
- /**
4307
- * Shows the "Expiry and Reminders" settings (Expiry 1-90 days, Reminder Interval 1-30 days, Max Reminders 0-10, all required whole
4308
- * numbers; starting at 7 / 2 / 3 unless this object says otherwise) while at least one document is chosen and the request is a native
4309
- * e-signature one (purpose e-signature or both; always on the text channel). `null` (default) = not shown, nothing sent. Read once.
4310
- */
4311
- readonly signing: import("@angular/core").InputSignal<DocumentSigningOptions | null | undefined>;
4312
- /**
4313
- * The host knows whether DocuSign is connected (the library never calls `/docusign/status`). `true` offers "Native E-Sign / Send via
4314
- * DocuSign" on the email channel while exactly one document is chosen; `false` (default) = no choice, native only.
4315
- */
4316
- readonly docuSignConnected: import("@angular/core").InputSignal<boolean>;
4317
- /**
4318
- * "Preview Document": called with the document when its button is clicked (one button for one document, one per document for several).
4319
- * `null` (default) hides the buttons. The host opens its own viewer; to open a new tab do it synchronously inside this call
4320
- * (`window.open` after an await is blocked as a popup in Safari).
4321
- */
4322
- readonly documentPreview: import("@angular/core").InputSignal<DocumentPreviewHandler | null>;
4323
- /** The recipient passed to `documentPreview` as `context.contact` (the send panel sets it from its contact inputs). `null` = none. */
4324
- readonly previewContact: import("@angular/core").InputSignal<DocumentPreviewContact | null>;
4325
- /** The send context passed to `documentPreview` as `context.sendContext` (the send panel sets it from its `sendContext`). `null` = none. */
4326
- readonly previewSendContext: import("@angular/core").InputSignal<SendContext | null>;
4327
- /**
4328
- * Turns on the signer logic (`documentSigners` of the panel): a document's customer roles (from its row's `signerRoles`, or the config's
4329
- * `resolveRoles`), informational documents (no signature fields), the one-signer DocuSign rule and the read-only countersign rule.
4330
- * The value then carries `signerInfo`. `null` (default) = none of it; nothing changes.
4331
- */
4332
- readonly signers: import("@angular/core").InputSignal<DocumentSignersConfig | null | undefined>;
4333
- /**
4334
- * An existing envelope (`documentEnvelope` of the panel): its documents are the list, fixed (no search, no remove buttons). Read when it
4335
- * is set; `null` (default) = the sender chooses the documents.
4336
- */
4337
- readonly envelope: import("@angular/core").InputSignal<DocumentEnvelopeTarget | null>;
4338
- /** The document list is fixed: an existing envelope's. */
4339
- readonly locked: import("@angular/core").Signal<boolean>;
4340
- protected readonly purposeOptions: import("@angular/core").Signal<SelectOption<string>[]>;
4341
- readonly search$: Subject<string>;
4342
- readonly options: import("@angular/core").WritableSignal<ComboboxOption<DocumentOption>[]>;
4343
- readonly loading: import("@angular/core").WritableSignal<boolean>;
4344
- readonly selected: import("@angular/core").WritableSignal<DocumentOption[]>;
4345
- readonly purposeChoice: import("@angular/core").WritableSignal<DocumentSendPurpose>;
4346
- /** What the sender picked in the provider choice (only effective while the choice is offered). */
4347
- readonly providerChoice: import("@angular/core").WritableSignal<DocumentSignatureProvider>;
4348
- readonly countersignChoice: import("@angular/core").WritableSignal<boolean>;
4349
- /** Roles of documents whose row had no `signerRoles` and that the host resolves (`signers().resolveRoles`). */
4350
- readonly roleStates: import("@angular/core").WritableSignal<Record<string, RoleState>>;
4351
- /** The envelope's documents: `loading` / `error` while the panel reads them (`loadDocuments`), `ready` once known. */
4352
- readonly envelopeStatus: import("@angular/core").WritableSignal<"error" | "loading" | "ready" | "idle">;
4353
- private envelopeSub;
4354
- private readonly roleSubs;
4355
- /** The sender opened the collapsed "Signing options" line. */
4356
- readonly signingOpen: import("@angular/core").WritableSignal<boolean>;
4357
- readonly expiryDays: import("@angular/core").WritableSignal<string>;
4358
- readonly reminderIntervalDays: import("@angular/core").WritableSignal<string>;
4359
- readonly maxReminders: import("@angular/core").WritableSignal<string>;
4360
- protected readonly providerOptions: RadioOption[];
4361
- /** The search box; cleared (and kept focused) after each pick so the next search starts empty. */
4362
- private readonly combo;
4363
- /** True when the last search request failed (shown inline instead of "No matching documents"). */
4364
- readonly searchFailed: import("@angular/core").WritableSignal<boolean>;
4365
- /** Shown through the combobox's own `error` input, so it is announced and tied to the search field natively (aria-describedby on the inner input). */
4366
- protected readonly searchFailedMessage = "Couldn't search your documents. Check your connection and try again.";
4367
- /**
4368
- * False when the section can't be used: the text channel only sends an e-signature link, so an app whose `purposes` excludes
4369
- * `ESIGN` has nothing to offer there. The section then shows a short note instead of a picker (it never silently sends another purpose).
4370
- */
4371
- readonly available: import("@angular/core").Signal<boolean>;
4372
- /** True when the sender can choose DocuSign: the host says it is connected, email channel, exactly one document (DocuSign sends one), and e-signature is a supported purpose. */
4373
- readonly providerChoiceShown: import("@angular/core").Signal<boolean>;
4374
- /** The provider that is actually used: DocuSign only while the choice is offered. */
4375
- readonly provider: import("@angular/core").Signal<DocumentSignatureProvider>;
4376
- /** The countersignature checkbox: a DocuSign send of a document flagged `requiresCountersign`. */
4377
- readonly showCountersign: import("@angular/core").Signal<boolean>;
4378
- /** The checkbox (no `signers`) or, with `signers` on, the document's own setting: the document says whether it is countersigned. */
4379
- readonly countersign: import("@angular/core").Signal<boolean>;
4380
- /** The signing settings are shown: turned on by the host, a document is chosen, and it is a native e-signature request (not attachment only, not DocuSign). */
4381
- readonly signingVisible: import("@angular/core").Signal<boolean>;
4382
- /** What the signer logic concluded for the chosen documents (`null` when `signers` is off or nothing is chosen). */
4383
- readonly signerInfo: import("@angular/core").Signal<DocumentSignerInfo | null>;
4384
- /** Why an envelope cannot be sent ('' = it can): nothing to send, or a document that is no longer active. Shown under the section. */
4385
- readonly envelopeProblem: import("@angular/core").Signal<string>;
4386
- /** Why Send waits for the envelope's documents ('' when they are known). */
4387
- readonly envelopeReadMessage: import("@angular/core").Signal<"" | "Reading the envelope's documents…" | "The documents of this envelope couldn't be read, so it can't be sent yet.">;
4388
- /** Why Send waits for the document's signers ('' when they are known). */
4389
- readonly signerReadMessage: import("@angular/core").Signal<"" | "Reading the document's signers…" | "The signers of this document couldn't be read, so it can't be sent yet.">;
4390
- /** The collapsed line: "Signing options: expires in 7 days, reminders every 2 days, up to 3". */
4391
- readonly signingSummary: import("@angular/core").Signal<string>;
4392
- /** Open when the sender opened it, or while a value is broken (the error must be visible). */
4393
- readonly signingExpanded: import("@angular/core").Signal<boolean>;
4394
- /** The purpose that is actually sent: the text channel and DocuSign can only do e-signature. */
4395
- readonly purpose: import("@angular/core").Signal<DocumentSendPurpose>;
4396
- readonly delivery: import("@angular/core").Signal<DocumentSendDelivery>;
4397
- readonly value: import("@angular/core").Signal<DocumentSendValue>;
4398
- /** The first broken signing setting ('' when fine or not shown) — the inputs show their own messages. */
4399
- readonly signingError: import("@angular/core").Signal<string>;
4400
- /** The first broken document rule ('' when fine) — shown under the section. */
4401
- readonly documentError: import("@angular/core").Signal<string>;
4402
- /** The first broken rule ('' when valid): the document rules, the wait for the signers, then the signing settings. */
4403
- readonly errorMessage: import("@angular/core").Signal<string>;
4404
- readonly invalid: import("@angular/core").Signal<boolean>;
4405
- constructor();
4406
- private static seedToOption;
4407
- /** Sets the envelope's documents as the list; reads them first when the host gave a loader. */
4408
- private loadEnvelope;
4409
- /** "Retry" after the envelope's documents could not be read. */
4410
- retryEnvelope(): void;
4411
- private static toOption;
4412
- /** Asks the host for the roles of every chosen document that needs it; forgets documents that were removed. */
4413
- private syncRoleRequests;
4414
- private requestRoles;
4415
- /** "Retry" after the roles of a document could not be read. */
4416
- retryRoles(): void;
4417
- /** The Change / Hide button: it flips what the sender sees (a line kept open by an error stays open, but a later fix lets it close). */
4418
- toggleSigning(): void;
4419
- private seedSigning;
4420
- /** `ui-text-input` hands the typed text back as a string (or a number from a programmatic write). */
4421
- protected asText(v: unknown): string;
4422
- setProvider(p: string): void;
4423
- /** Calls the host's preview handler straight from the click (no await in between: Safari blocks a tab opened later). */
4424
- preview(doc: DocumentOption): void;
4425
- onPick(opt: ComboboxOption<DocumentOption> | null): void;
4426
- remove(id: string): void;
4427
- setPurpose(p: string): void;
4428
- /** Empties the selection (the host calls it after a successful send). */
4429
- reset(): void;
4430
- static ɵfac: i0.ɵɵFactoryDeclaration<DocumentSendOptionsComponent, never>;
4431
- static ɵcmp: i0.ɵɵComponentDeclaration<DocumentSendOptionsComponent, "ui-document-send-options", never, {
4432
- "channel": {
4433
- "alias": "channel";
4434
- "required": false;
4435
- "isSignal": true;
4436
- };
4437
- "label": {
4438
- "alias": "label";
4439
- "required": false;
4440
- "isSignal": true;
4441
- };
4442
- "required": {
4443
- "alias": "required";
4444
- "required": false;
4445
- "isSignal": true;
4446
- };
4447
- "showErrors": {
4448
- "alias": "showErrors";
4449
- "required": false;
4450
- "isSignal": true;
4451
- };
4452
- "purposes": {
4453
- "alias": "purposes";
4454
- "required": false;
4455
- "isSignal": true;
4456
- };
4457
- "initialDocuments": {
4458
- "alias": "initialDocuments";
4459
- "required": false;
4460
- "isSignal": true;
4461
- };
4462
- "signing": {
4463
- "alias": "signing";
4464
- "required": false;
4465
- "isSignal": true;
4466
- };
4467
- "docuSignConnected": {
4468
- "alias": "docuSignConnected";
4469
- "required": false;
4470
- "isSignal": true;
4471
- };
4472
- "documentPreview": {
4473
- "alias": "documentPreview";
4474
- "required": false;
4475
- "isSignal": true;
4476
- };
4477
- "previewContact": {
4478
- "alias": "previewContact";
4479
- "required": false;
4480
- "isSignal": true;
4481
- };
4482
- "previewSendContext": {
4483
- "alias": "previewSendContext";
4484
- "required": false;
4485
- "isSignal": true;
4486
- };
4487
- "signers": {
4488
- "alias": "signers";
4489
- "required": false;
4490
- "isSignal": true;
4491
- };
4492
- "envelope": {
4493
- "alias": "envelope";
4494
- "required": false;
4495
- "isSignal": true;
4496
- };
4497
- }, {
4498
- "valueChange": "valueChange";
4499
- "invalidChange": "invalidChange";
4500
- }, never, never, true, never>;
4501
- }
4502
- /**
4503
- * Video share-link helpers shared by every app (they replace the apps' own copies, e.g. real-estate `video-link.utils.ts`).
4504
- *
4505
- * The share link of a video (`VideoMessage.shareLink`) carries the playback settings as query parameters:
4506
- * autoplay=1 · ref=<contact id> · ctaType · ctaUrl · ctaLabel · hideReactions=1 (in exactly that order).
4507
- */
4508
- interface VideoLinkOptions {
4509
- autoplay?: boolean;
4510
- /** The recipient: lets the video page track who watched (`ref`). */
4511
- contactId?: string;
4512
- /** '' / undefined = none (the video's own default); `schedule` | `contact` | `custom`. */
4513
- ctaType?: string;
4514
- ctaUrl?: string;
4515
- ctaLabel?: string;
4516
- hideReactions?: boolean;
4517
- }
4518
- /**
4519
- * Default video settings the host reads from its Communication settings (same keys as `/comm-settings` without the `videoDefault`
4520
- * prefix): `videoDefaultAutoplay` → `autoplay`, `videoDefaultCtaType` → `ctaType`, … Missing keys mean "off" / "none".
4521
- */
4522
- interface VideoDefaults {
4523
- autoplay?: boolean;
4524
- ctaType?: string;
4525
- ctaUrl?: string;
4526
- ctaLabel?: string;
4527
- hideReactions?: boolean;
4528
- }
4529
- /** `baseLink` + the settings as query parameters (unchanged when no setting is on). A base that already has a query gets `&`. */
4530
- export declare function buildVideoLink(baseLink: string, options?: VideoLinkOptions): string;
4531
- /**
4532
- * The share link of a freshly attached video: `baseLink` with the host's defaults and the recipient applied — exactly the link
4533
- * `ui-video-link-settings` shows before the sender changes anything.
4534
- */
4535
- declare function videoLinkWithDefaults(baseLink: string, defaults?: VideoDefaults, contactId?: string): string;
4536
- /** Strips any "🎬 Watch video: <url>" line previously inserted into a message body (the line format the apps' own composers use). */
4537
- export declare function stripVideoLink(text: string): string;
4538
- /** Appends a "🎬 Watch video: <link>" line to a message body (replacing one that is already there). */
4539
- export declare function appendVideoLink(text: string, link: string): string;
4540
- /** The line `ui-send-message-panel` puts in the message for an attached video: `Watch "<title>": <link>`. */
4541
- export declare function videoMessageLine(title: string, link: string): string;
4542
- /**
4543
- * Puts `next` into `body` in place of `prev` (the line inserted earlier), so changing a video setting rewrites the link without
4544
- * touching the rest of the message:
4545
- * - no `prev` yet → appended after a blank line (no separator for an empty body);
4546
- * - `prev` is in the body → replaced in place; with an empty `next` it is removed together with its separator;
4547
- * - `prev` was edited away by the sender → the body is left as the sender wrote it.
4548
- */
4549
- export declare function applyVideoLine(body: string, prev: string, next: string): string;
4550
- /** The `documents` key of `SendEmailPayload` / `SendTextPayload`: present only when at least one document was chosen. */
4551
- interface SendDocumentsPayload {
4552
- documentIds: string[];
4553
- /** `ESIGN` | `ATTACH` | `BOTH` (always `ESIGN` for texts). */
4554
- purpose: DocumentSendPurpose;
4555
- /** `EMAIL` for the email form, `TEXT` for the text form. */
4556
- delivery: DocumentSendDelivery;
4557
- /** Only when the host turned on `documentSigningOptions` and the request is a native e-signature request (purpose `ESIGN` / `BOTH`): days until the request expires (1-90). */
4558
- expiryDays?: number;
4559
- /** Same condition as `expiryDays`: days between reminders (1-30). */
4560
- reminderIntervalDays?: number;
4561
- /** Same condition as `expiryDays`: how many reminders at most (0-10). */
4562
- maxReminders?: number;
4563
- /** Only when the host passed `docuSignConnected` and the sender can choose (email, exactly one document): which e-signature provider sends the request. */
4564
- provider?: DocumentSignatureProvider;
4565
- /** Only with `provider: 'DOCUSIGN'`: `countersign` is true when the sender ticked "Require my countersignature after client signs" (only offered for a document flagged `requiresCountersign`). */
4566
- docuSign?: {
4567
- countersign: boolean;
4568
- };
4569
- /**
4570
- * Only when the host turned on `documentSigners`, the request is a native e-signature one, ONE document is chosen and it has MORE THAN ONE
4571
- * customer signer: all N signers including signer1 (= the recipient), ordered by role, never partial. A single-signer send has no such key.
4572
- */
4573
- signers?: SendSigner[];
4574
- /** Only when the host passed `sendContext` and at least one key it declared in `documentContextTypes` has a value (other keys are dropped). */
4575
- context?: SendContext;
4576
- /** Only when the send is of an existing envelope (`documentEnvelope`): its id; the request is not created again, it is sent. */
4577
- envelopeId?: string;
4578
- /** Only with `documentSigners` on, when every chosen document has no signature fields: the send is informational (the recipient gets a view link, nothing is signed). */
4579
- informational?: true;
4580
- }
4581
- /** What the success toast of a document send can say (`documentSentMessage` of the panel). */
4582
- interface DocumentSentInfo {
4583
- titles: string[];
4584
- /** Only when an existing envelope was sent (`documentEnvelope`). */
4585
- envelopeName?: string;
4586
- channel: 'email' | 'text';
4587
- provider?: DocumentSignatureProvider;
4588
- /** Every chosen document has no signature fields (a view link was sent). */
4589
- informational: boolean;
4590
- }
4591
- /** Builds the success toast of a document send (default: `Email sent` / `Text message sent` / `"<title>" sent via DocuSign` / `Envelope "<name>" sent`). */
4592
- type DocumentSentMessage = (info: DocumentSentInfo) => string;
4593
- /** The optional parts the form adds to the `documents` payload besides what the document section holds. */
4594
- interface DocumentsPayloadExtras {
4595
- signers?: SendSigner[] | null;
4596
- context?: SendContext;
4597
- envelopeId?: string;
4598
- }
4599
- /**
4600
- * The `documents` part of a payload from what the document section holds. The optional keys (signing settings, provider, DocuSign
4601
- * options) are present only when the section produced them, so a host that turned none of them on gets exactly
4602
- * `{ documentIds, purpose, delivery }`.
4603
- */
4604
- declare function buildDocumentsPayload(v: DocumentSendValue, delivery: DocumentSendDelivery, purpose?: DocumentSendPurpose, extras?: DocumentsPayloadExtras): SendDocumentsPayload;
4605
- /**
4606
- * Subject of the signature request when the sender has none (texts have no subject). The server treats exactly this
4607
- * text as a placeholder and builds the real subject from the document names.
4608
- */
4609
- export declare const DEFAULT_DOCUMENT_SUBJECT = "Document Signature Required";
4610
- /**
4611
- * The subject the library suggests once documents are chosen on the email form — the same text the servers build when the
4612
- * sender leaves the subject out: signing (ESIGN / BOTH) → "Signature required: <title>" (several: "<N> documents to sign: <first>…");
4613
- * attachment only → "Document attached: <title>" (several: "<N> documents attached: <first>…"). '' for no documents.
4614
- */
4615
- export declare function suggestDocumentSubject(titles: string[], purpose: DocumentSendPurpose, informational?: boolean): string;
4616
- /** Most people that can be copied on one email (same limit as the server). */
4617
- export declare const MAX_CC = 10;
4618
- /** CC addresses typed as text: comma / semicolon / whitespace separated, trimmed, de-duplicated (case-insensitive). */
4619
- export declare function parseCcList(raw: string): string[];
4620
- /** The first problem with a CC list, '' when fine — the same rules the server enforces (valid addresses, at most 10, fits the column). */
4621
- declare function ccError(list: string[]): string;
4622
- /** What the library sends to create a document request (`POST <baseUrl>/documents/envelopes`). See docs/send-documents-contract.md. */
4623
- interface CreateDocumentRequestBody {
4624
- subject: string;
4625
- message: string;
4626
- customerId?: string;
4627
- customerName: string;
4628
- customerEmail?: string;
4629
- customerPhone?: string;
4630
- documentIds: string[];
4631
- purpose: DocumentSendPurpose;
4632
- delivery: DocumentSendDelivery;
4633
- ccEmails?: string[];
4634
- /** Native e-signature requests only, and only when the host turned on `documentSigningOptions`. */
4635
- expiryDays?: number;
4636
- reminderIntervalDays?: number;
4637
- maxReminders?: number;
4638
- /** Only with `documentSigners` and a document with several customer signers (complete, ordered). */
4639
- signers?: SendSigner[];
4640
- /** Only with `sendContext` / `documentContextTypes`. */
4641
- context?: SendContext;
4642
- }
4643
- /** The signing settings of a `documents` payload as optional keys of the create-request body (nothing when there are none). */
4644
- declare function signingBodyFields(d: SendDocumentsPayload): Pick<CreateDocumentRequestBody, 'expiryDays' | 'reminderIntervalDays' | 'maxReminders'>;
4645
- /** The body of `POST <baseUrl>/documents/envelopes/{id}/send` for an existing envelope: the create body without the document ids (the envelope already has them). */
4646
- type ExistingEnvelopeSendBody = Omit<CreateDocumentRequestBody, 'documentIds'> & {
4647
- templateId?: string;
4648
- };
4649
- /**
4650
- * Sends an envelope that already exists (`documentEnvelope`): `POST <baseUrl>/documents/envelopes/{id}/send` with the recipient, message and
4651
- * options in the body (nothing is created first). The host can replace it with `[sendEmail]` / `[sendText]` (payload `documents.envelopeId`).
4652
- */
4653
- export declare function sendExistingEnvelope(http: HttpClient, apiBase: string, envelopeId: string, body: ExistingEnvelopeSendBody): Observable<unknown>;
4654
- /** The `signers` / `context` of a `documents` payload as optional keys of the create-request body (nothing when there are none). */
4655
- declare function signersContextBodyFields(d: SendDocumentsPayload): Pick<CreateDocumentRequestBody, 'signers' | 'context'>;
4656
- /** What the library sends to send ONE document through DocuSign (`POST <baseUrl>/docusign/send`). See docs/send-documents-contract.md. */
4657
- interface DocuSignSendBody {
4658
- documentId: string;
4659
- contactId: string;
4660
- subject?: string;
4661
- message?: string;
4662
- countersignRequired: boolean;
4663
- }
4664
- /** The default DocuSign send: `POST <baseUrl>/docusign/send` → 200. The host can replace it with `[sendEmail]`. */
4665
- declare function sendDocuSignRequest(http: HttpClient, apiBase: string, body: DocuSignSendBody): Observable<unknown>;
4666
- /**
4667
- * The default way a message form sends documents: create the request, then send it.
4668
- * 1. POST <baseUrl>/documents/envelopes → 201 { id, ... }
4669
- * 2. POST <baseUrl>/documents/envelopes/{id}/send → 200 (body { templateId } only when the message came from a template)
4670
- * A failure in step 2 leaves the created request as a draft on the server; the error is surfaced like any send error.
4671
- */
4672
- declare function sendDocumentRequest(http: HttpClient, apiBase: string, body: CreateDocumentRequestBody, templateId?: string): Observable<unknown>;
4673
- /** What the email form sends — the default `POST <baseUrl>/email-messages` body, or the host's `sendFn` argument. */
4674
- interface SendEmailPayload {
4675
- contactName: string;
4676
- contactEmail: string;
4677
- subject: string;
4678
- body: string;
4679
- contactId?: string;
4680
- scheduledAt?: string;
4681
- attachments?: {
4682
- filename: string;
4683
- content: string;
4684
- contentType: string;
4685
- }[];
4686
- /** Only present when the host enabled `showReceiptOption`: whether the sender ticked the receipt checkbox. */
4687
- includeReceipt?: boolean;
4688
- /** Only present when the email was sent from a saved template (still set after editing its text); lets the server count the template use. */
4689
- templateId?: string;
4690
- /** Only present when the host enabled `showCc` and the sender typed addresses: the people copied on the email (valid, deduplicated, at most 10). */
4691
- cc?: string[];
4692
- /** Only present when the host enabled `documents` and the sender chose at least one document (then `attachments` and `scheduledAt` are never set). */
4693
- documents?: SendDocumentsPayload;
4694
- }
4695
- /**
4696
- * HTML for the Preview pane, the "View Send Preview" modal AND the sent email body — the server converts the sent
4697
- * body with the same rules (contractor `messagePreviewHtml` in EmailTemplateService.kt), so what is previewed is
4698
- * exactly what is sent:
4699
- * - empty → ''
4700
- * - a body containing an HTML tag (`/<[a-z][\s\S]*>/i`) is HTML and is used untouched
4701
- * - otherwise it is plain text: `&`, `<`, `>`, `"` and `'` are escaped (`&amp;` `&lt;` `&gt;` `&quot;` `&#39;`)
4702
- * and every line break (`\r\n`, `\r`, `\n`) becomes `<br>`.
4703
- */
4704
- export declare function messagePreviewHtml(body: string): string;
4705
- declare class SendEmailComponent implements OnInit {
4706
- private readonly destroyRef;
4707
- private readonly http;
4708
- /** API root from FORGEROUTE_CONFIG (e.g. a cross-origin prod API); falls back to same-origin `/api`. */
4709
- private readonly apiBase;
4710
- private readonly toast;
4711
- readonly cdr: ChangeDetectorRef;
4712
- readonly contactName: import("@angular/core").InputSignal<string>;
4713
- readonly contactEmail: import("@angular/core").InputSignal<string>;
4714
- /** The contact's phone — fills `{{phone}}` (a blank phone makes `{{phone}}` a prompted field). */
4715
- readonly contactPhone: import("@angular/core").InputSignal<string>;
4716
- readonly contactId: import("@angular/core").InputSignal<string>;
4717
- /** Prefills Subject in "Create Message" mode (e.g. "Estimate #1042 — Kitchen Remodel"). */
4718
- readonly defaultSubject: import("@angular/core").InputSignal<string>;
4719
- /** Prefills Message in "Create Message" mode. */
4720
- readonly defaultBody: import("@angular/core").InputSignal<string>;
4721
- /** Extra merge variables (e.g. `estimate_number`, `estimate_total`) used in templates and the preview. */
4722
- readonly context: import("@angular/core").InputSignal<Record<string, string>>;
4723
- /**
4724
- * Sends through the host instead of `POST <baseUrl>/email-messages` — e.g. a page-specific endpoint that
4725
- * also marks a record Sent. Loading, toasts, `sent` and the double-send guard behave the same.
4726
- */
4727
- readonly sendFn: import("@angular/core").InputSignal<((payload: SendEmailPayload) => Observable<unknown>) | null>;
4728
- /** Shows an "include receipt" checkbox; the choice is sent as `includeReceipt`. Off = payload has no such key. */
4729
- readonly showReceiptOption: import("@angular/core").InputSignal<boolean>;
4730
- readonly receiptLabel: import("@angular/core").InputSignal<string>;
4731
- /** Initial state of the receipt checkbox (and the state it returns to after a send). */
4732
- readonly receiptDefault: import("@angular/core").InputSignal<boolean>;
4733
- /** Shows the "Documents" section (search your documents, choose what the recipient does with them). Off = the form is unchanged. */
4734
- readonly documents: import("@angular/core").InputSignal<boolean>;
4735
- /** Purposes the app's backend supports for documents (default all); a single entry hides the purpose select. */
4736
- readonly documentPurposes: import("@angular/core").InputSignal<DocumentSendPurpose[]>;
4737
- /** Documents already chosen in the Documents section when the form opens. */
4738
- readonly initialDocuments: import("@angular/core").InputSignal<DocumentSeed[]>;
4739
- /**
4740
- * Turns on the signer logic: one required contact per customer signer role of the chosen document, the read-only countersign line,
4741
- * informational documents (no signature fields) and the one-signer DocuSign rule. `null` (default) = the single recipient, unchanged.
4742
- */
4743
- readonly documentSigners: import("@angular/core").InputSignal<DocumentSignersConfig | null>;
4744
- /** Values the host has for THIS send; only the keys declared in `documentContextTypes` are sent, as `documents.context`. */
4745
- readonly sendContext: import("@angular/core").InputSignal<SendContext | null>;
4746
- /** The context keys the app's backend accepts. */
4747
- readonly documentContextTypes: import("@angular/core").InputSignal<ContextTypeDef[]>;
4748
- /** `true` = check (default route `POST <baseUrl>/documents/merge-check`), a function = the host's own check; shows a non-blocking "fields that will be empty" warning. */
4749
- readonly documentMergeCheck: import("@angular/core").InputSignal<boolean | MergeCheckFn>;
4750
- /** An existing envelope to send: its documents are fixed and it is sent (not created). Payload `documents.envelopeId`. `null` (default) = a new request from the chosen documents. */
4751
- readonly documentEnvelope: import("@angular/core").InputSignal<DocumentEnvelopeTarget | null>;
4752
- /** false = the app's email sending is switched off (Communication settings): Send stays off and the form says why. */
4753
- readonly emailEnabled: import("@angular/core").InputSignal<boolean>;
4754
- /** Builds the success toast of a document send (default texts otherwise). */
4755
- readonly documentSentMessage: import("@angular/core").InputSignal<DocumentSentMessage | null>;
4756
- /** Shows a CC field; the typed addresses are sent as `cc`. Off = payload has no such key. */
4757
- readonly showCc: import("@angular/core").InputSignal<boolean>;
4758
- /** Shows "Expiry and Reminders" for e-signature requests (see `DocumentSigningOptions`); sent as `documents.expiryDays` / `reminderIntervalDays` / `maxReminders`. `null` = off. */
4759
- readonly documentSigningOptions: import("@angular/core").InputSignal<DocumentSigningOptions | null | undefined>;
4760
- /** The host says DocuSign is connected: offers "Native E-Sign / Send via DocuSign" for a single document. Off = native only. */
4761
- readonly docuSignConnected: import("@angular/core").InputSignal<boolean>;
4762
- /** "Preview Document" button(s) in the Documents section call this; `null` hides them. */
4763
- readonly documentPreview: import("@angular/core").InputSignal<DocumentPreviewHandler | null>;
4764
- /** The recipient handed to `documentPreview` (second argument): the panel's contact inputs, `null` while all four are blank. */
4765
- readonly previewContact: import("@angular/core").Signal<DocumentPreviewContact | null>;
4766
- /**
4767
- * Turns on the video settings (Playback, Call-to-Action, Hide reactions, Watch Preview, Remove Video) once a video is attached, starting
4768
- * from these defaults, and makes the video link carry them. `null` (default) = the attached video's plain share link is inserted, as before.
4769
- */
4770
- readonly videoDefaults: import("@angular/core").InputSignal<VideoDefaults | null>;
4771
- /** false hides Attach Files and "Schedule for later" (for a host whose send function can't deliver them). */
4772
- readonly attachmentsAndScheduling: import("@angular/core").InputSignal<boolean>;
4773
- readonly sent: import("@angular/core").OutputEmitterRef<void>;
4774
- readonly emailAdded: import("@angular/core").OutputEmitterRef<string>;
4775
- readonly validChange: import("@angular/core").OutputEmitterRef<boolean>;
4776
- /** A document send was refused because the document / envelope changed meanwhile (404 / 409): the host refreshes its list. */
4777
- readonly rejected: import("@angular/core").OutputEmitterRef<void>;
4778
- /** The "Place your countersignature box" link under the countersign line was clicked (document row `hasCountersignPlacement: false`). */
4779
- readonly mapFieldsClick: import("@angular/core").OutputEmitterRef<{
4780
- id: string;
4781
- title: string;
4782
- }>;
4783
- readonly EMAIL_DISABLED_MESSAGE = "Email sending is disabled, so this can't be sent. Enable it in Communication Settings.";
4784
- mode: 'compose' | 'template';
4785
- subject: string;
4786
- body: string;
4787
- templateId: string | null;
4788
- previewFormat: 'preview' | 'raw';
4789
- showSendPreview: boolean;
4790
- previewingTemplate: {
4791
- subject: string;
4792
- body: string;
4793
- } | null;
4794
- customVars: Record<string, string>;
4795
- pendingInputs: Record<string, string>;
4796
- loading: boolean;
4797
- includeReceipt: boolean;
4798
- showSchedule: boolean;
4799
- scheduledAt: string;
4800
- attachments: {
4801
- filename: string;
4802
- content: string;
4803
- contentType: string;
4804
- sizeLabel: string;
4805
- }[];
4806
- pendingEmail: string;
4807
- ccText: string;
4808
- /** What the document section holds (null / empty = no documents) and whether it currently breaks a rule. */
4809
- documentsValue: DocumentSendValue | null;
4810
- documentsInvalid: boolean;
4811
- /** The complete signer list of the signer rows (null while a role has no contact) and whether they break a rule. */
4812
- signersValue: SendSigner[] | null;
4813
- signersInvalid: boolean;
4814
- /** Lines of the merge check ("These fields will be left empty: …"). */
4815
- mergeWarnings: string[];
4816
- readonly savingEmail: import("@angular/core").WritableSignal<boolean>;
4817
- readonly modeTabs: PillTab[];
4818
- /** Market values (`area`, `median_price`, `dom`, `new_listings`) — only the ones `/service-areas` returned. */
4819
- private marketVars;
4820
- ngOnInit(): void;
4821
- /** Defaults last applied to compose mode — a default only replaces text the user hasn't edited. */
4822
- private _appliedDefaults;
4823
- constructor();
4824
- /** The Subject last filled from the chosen documents — it is replaced only while the Subject still equals it (the user hasn't edited it). */
4825
- private _suggestedSubject;
4826
- /** Fills / updates / clears the document-based Subject suggestion (compose mode only; never touches text the user or the host wrote). */
4827
- private syncSuggestedSubject;
4828
- /** Puts the host's defaults into compose mode unless the user already changed that field. */
4829
- private applyDefaults;
4830
- protected readonly previewHtml: typeof messagePreviewHtml;
4831
- setPreviewFormat(f: 'preview' | 'raw'): void;
4832
- get pendingEmailValid(): boolean;
4833
- /** True when the sender chose at least one document (only possible when the `documents` input is on). */
4834
- get hasDocuments(): boolean;
4835
- /** True when the sender chose to send the (single) document through DocuSign: DocuSign emails it itself, so CC, attachments and the required Subject / Message do not apply. */
4836
- get viaDocuSign(): boolean;
4837
- /** The recipient as Signer 1 (a stable object: it feeds a child input). */
4838
- readonly recipientPick: import("@angular/core").Signal<{
4839
- id: string;
4840
- name: string;
4841
- email: string;
4842
- }>;
4843
- /** The declared context keys with a value (`documents.context`); keys the app did not declare are dropped (with a development warning). */
4844
- readonly forwardedContext: import("@angular/core").Signal<SendContext | undefined>;
4845
- /** What the signer logic concluded for the chosen documents (null when `documentSigners` is off or nothing is chosen). */
4846
- get signerInfo(): DocumentSignerInfo | null;
4847
- /** The chosen documents the merge check looks at. */
4848
- get mergeDocuments(): DocumentOption[];
4849
- /** True when a native e-signature request for ONE document with several customer signers is being built: the signer rows are required. */
4850
- get signersActive(): boolean;
4851
- /** The signer section is shown: signer rows, and/or the countersign line (a signed document that is not just attached). */
4852
- get signersSectionShown(): boolean;
4853
- /** The signer rows restart whenever the chosen document changes. */
4854
- get signersKey(): string;
4855
- onSigners(v: SendSigner[] | null): void;
4856
- onSignersInvalid(bad: boolean): void;
4857
- onMergeWarnings(lines: string[]): void;
4858
- /** The lines of the ONE warning banner: what choosing a document removed, a multi-signer document among several, the merge check. */
4859
- get warningLines(): {
4860
- key: string;
4861
- text: string;
4862
- testId: string | null;
4863
- }[];
4864
- /** The people copied on the email, as typed (empty unless `showCc` is on, and not used by a DocuSign send). */
4865
- get ccList(): string[];
4866
- /** The first problem with the CC field ('' when fine). */
4867
- get ccError(): string;
4868
- /** Set when choosing the first document removed something the sender had already added - said out loud (aria-live), never silently. */
4869
- docsRemovedNote: string;
4870
- onDocumentsChange(v: DocumentSendValue): void;
4871
- onDocumentsInvalid(bad: boolean): void;
4872
- /** Server limits (400 "Subject must be 255 characters or fewer." / "Body must be 10000 characters or fewer."). */
4873
- readonly MAX_SUBJECT = 255;
4874
- readonly MAX_BODY = 10000;
4875
- /** Inline error when the message, as it will be sent, is over the server limit ('' when fine). */
4876
- get bodyLengthError(): string;
4877
- /** Inline error when the subject, as it will be sent, is over the server limit ('' when fine). */
4878
- get subjectLengthError(): string;
4879
- /** The length problem shown under the form in every mode; compose mode shows the message one on the editor instead. */
4880
- get sendLengthError(): string;
4881
- get canSend(): boolean;
4882
- get minScheduleTime(): string;
4883
- /**
4884
- * Values every tag can resolve from before the user types anything: the contact (name, first / last name, email,
4885
- * phone), the date, the market values `/service-areas` returned and the host's `context` — non-blank values only,
4886
- * later sources winning.
4887
- */
4888
- private get knownVars();
4889
- /** Merges `text` with every known value plus what the user typed — the ONE merge the pane, modal and payload use. */
4890
- resolveMergeTags(text: string): string;
4891
- /** Applied values plus anything typed into a missing-field input — so the preview updates as the user types. */
4892
- private get liveVars();
4893
- /** The subject / body exactly as they will be sent (live: recomputed on every read, never cached). */
4894
- get resolvedSubject(): string;
4895
- get resolvedBody(): string;
4896
- /** The Preview pane's HTML — the same HTML the server sends (see messagePreviewHtml). */
4897
- get previewBodyHtml(): string;
4898
- /** The send-preview modal: the eye-button template when one is being previewed, otherwise the selected one. */
4899
- get sendPreviewSubject(): string;
4900
- get sendPreviewHtml(): string;
4901
- /** Template fields the user still has to fill — tags with no non-blank known value and nothing applied. */
4902
- get missingVars(): string[];
4903
- /** Compose mode: a `{{…}}` the form can't fill blocks sending (the server would refuse it). */
4904
- get composeTagError(): string;
4905
- /** Missing fields with nothing typed yet — Send stays disabled until this is empty. */
4906
- get unresolvedVars(): string[];
4907
- /**
4908
- * Applies every typed missing-field value (what the preview already shows) before sending. Never saves
4909
- * to the contact — only the explicit "+" / Enter apply does that.
4910
- */
4911
- private applyPendingVars;
4912
- formatVarLabel(key: string): string;
4913
- /** Applies a typed missing-field value. The explicit "+" / Enter apply (`persist`) also saves phone / address to the contact. */
4914
- applyVar(key: string, persist?: boolean): void;
4915
- stripBlockWrappers(html: string): string;
4916
- /** "View Send Preview": always the SELECTED template (never a template last opened with the eye button). */
4917
- openSendPreview(): void;
4918
- /** The picker's eye button: previews that template without selecting it. */
4919
- openQuickPreview(tpl: {
4920
- subject: string;
4921
- body: string;
4922
- }): void;
4923
- closeSendPreview(): void;
4924
- notifyValid(): void;
4925
- setMode(key: string): void;
4926
- saveEmail(): void;
4927
- clearTemplate(): void;
4928
- onTemplateSelected(tpl: TemplateItem): void;
4929
- onFilesSelected(event: Event): void;
4930
- removeAttachment(index: number): void;
4931
- insertVideo(v: VideoMessage): void;
4932
- /** The body of the default DocuSign send: Subject / Message only when the sender has them (DocuSign has its own defaults otherwise). */
4933
- private docuSignBody;
4934
- /** The video attached through the settings flow (null = none) and the line it put into the message. */
4935
- videoPicked: VideoMessage | null;
4936
- /** Bumped to re-create the video picker (it keeps its own selection and has no clear output). */
4937
- videoPickerKey: number;
4938
- private _videoLine;
4939
- /** The picker's output: with `videoDefaults` the video gets its settings section, otherwise the plain link is inserted as before. */
4940
- onVideoSelected(v: VideoMessage): void;
4941
- /** The settings section's output: rewrites the video line of the message with the current link (the rest of the message is untouched). */
4942
- onVideoLink(link: string): void;
4943
- /** "Remove Video": takes the video line out of the message and brings the picker back. */
4944
- removeVideo(): void;
4945
- private discardVideo;
4946
- submit(): void;
4947
- static ɵfac: i0.ɵɵFactoryDeclaration<SendEmailComponent, never>;
4948
- static ɵcmp: i0.ɵɵComponentDeclaration<SendEmailComponent, "ui-send-email", never, {
4949
- "contactName": {
4950
- "alias": "contactName";
4951
- "required": false;
4952
- "isSignal": true;
4953
- };
4954
- "contactEmail": {
4955
- "alias": "contactEmail";
4956
- "required": false;
4957
- "isSignal": true;
4958
- };
4959
- "contactPhone": {
4960
- "alias": "contactPhone";
4961
- "required": false;
4962
- "isSignal": true;
4963
- };
4964
- "contactId": {
4965
- "alias": "contactId";
4966
- "required": false;
4967
- "isSignal": true;
4968
- };
4969
- "defaultSubject": {
4970
- "alias": "defaultSubject";
4971
- "required": false;
4972
- "isSignal": true;
4973
- };
4974
- "defaultBody": {
4975
- "alias": "defaultBody";
4976
- "required": false;
4977
- "isSignal": true;
4978
- };
4979
- "context": {
4980
- "alias": "context";
4981
- "required": false;
4982
- "isSignal": true;
4983
- };
4984
- "sendFn": {
4985
- "alias": "sendFn";
4986
- "required": false;
4987
- "isSignal": true;
4988
- };
4989
- "showReceiptOption": {
4990
- "alias": "showReceiptOption";
4991
- "required": false;
4992
- "isSignal": true;
4993
- };
4994
- "receiptLabel": {
4995
- "alias": "receiptLabel";
4996
- "required": false;
4997
- "isSignal": true;
4998
- };
4999
- "receiptDefault": {
5000
- "alias": "receiptDefault";
5001
- "required": false;
5002
- "isSignal": true;
5003
- };
5004
- "documents": {
5005
- "alias": "documents";
5006
- "required": false;
5007
- "isSignal": true;
5008
- };
5009
- "documentPurposes": {
5010
- "alias": "documentPurposes";
5011
- "required": false;
5012
- "isSignal": true;
5013
- };
5014
- "initialDocuments": {
5015
- "alias": "initialDocuments";
5016
- "required": false;
5017
- "isSignal": true;
5018
- };
5019
- "documentSigners": {
5020
- "alias": "documentSigners";
5021
- "required": false;
5022
- "isSignal": true;
5023
- };
5024
- "sendContext": {
5025
- "alias": "sendContext";
5026
- "required": false;
5027
- "isSignal": true;
5028
- };
5029
- "documentContextTypes": {
5030
- "alias": "documentContextTypes";
5031
- "required": false;
5032
- "isSignal": true;
5033
- };
5034
- "documentMergeCheck": {
5035
- "alias": "documentMergeCheck";
5036
- "required": false;
5037
- "isSignal": true;
5038
- };
5039
- "documentEnvelope": {
5040
- "alias": "documentEnvelope";
5041
- "required": false;
5042
- "isSignal": true;
5043
- };
5044
- "emailEnabled": {
5045
- "alias": "emailEnabled";
5046
- "required": false;
5047
- "isSignal": true;
5048
- };
5049
- "documentSentMessage": {
5050
- "alias": "documentSentMessage";
5051
- "required": false;
5052
- "isSignal": true;
5053
- };
5054
- "showCc": {
5055
- "alias": "showCc";
5056
- "required": false;
5057
- "isSignal": true;
5058
- };
5059
- "documentSigningOptions": {
5060
- "alias": "documentSigningOptions";
5061
- "required": false;
5062
- "isSignal": true;
5063
- };
5064
- "docuSignConnected": {
5065
- "alias": "docuSignConnected";
5066
- "required": false;
5067
- "isSignal": true;
5068
- };
5069
- "documentPreview": {
5070
- "alias": "documentPreview";
5071
- "required": false;
5072
- "isSignal": true;
5073
- };
5074
- "videoDefaults": {
5075
- "alias": "videoDefaults";
5076
- "required": false;
5077
- "isSignal": true;
5078
- };
5079
- "attachmentsAndScheduling": {
5080
- "alias": "attachmentsAndScheduling";
5081
- "required": false;
5082
- "isSignal": true;
5083
- };
5084
- }, {
5085
- "sent": "sent";
5086
- "emailAdded": "emailAdded";
5087
- "validChange": "validChange";
5088
- "rejected": "rejected";
5089
- "mapFieldsClick": "mapFieldsClick";
5090
- }, never, never, true, never>;
5091
- }
5092
- /** What the text form sends — the default `POST <baseUrl>/text-messages` body, or the host's `sendFn` argument. */
5093
- interface SendTextPayload {
5094
- contactName: string;
5095
- contactPhone: string;
5096
- body: string;
5097
- contactId?: string;
5098
- scheduledAt?: string;
5099
- mediaUrl?: string;
5100
- mediaType?: string;
5101
- mediaFileName?: string;
5102
- /** The template the message was made from (template mode only) — the backend counts it toward the template's Sent total. */
5103
- templateId?: string;
5104
- /** Only present when the host enabled `documents` and the sender chose at least one document (then `mediaUrl` and `scheduledAt` are never set). Texts send a link: `delivery` is `TEXT`, `purpose` is `ESIGN`. */
5105
- documents?: SendDocumentsPayload;
5106
- }
5107
- declare function formatPhone(raw: string | null | undefined): string;
5108
- declare class SendTextComponent implements OnInit {
5109
- protected readonly formatPhone: typeof formatPhone;
5110
- private readonly destroyRef;
5111
- private readonly http;
5112
- /** API root from FORGEROUTE_CONFIG (e.g. a cross-origin prod API); falls back to same-origin `/api`. */
5113
- private readonly apiBase;
5114
- private readonly toast;
5115
- readonly cdr: ChangeDetectorRef;
5116
- readonly contactName: import("@angular/core").InputSignal<string>;
5117
- readonly contactPhone: import("@angular/core").InputSignal<string>;
5118
- /** The contact's email — fills `{{email}}` (a blank email makes `{{email}}` a prompted field). */
5119
- readonly contactEmail: import("@angular/core").InputSignal<string>;
5120
- readonly contactId: import("@angular/core").InputSignal<string>;
5121
- /** Prefills Message in "Create Message" mode. */
5122
- readonly defaultBody: import("@angular/core").InputSignal<string>;
5123
- /** Extra merge variables (e.g. `estimate_number`) used in templates and the preview. */
5124
- readonly context: import("@angular/core").InputSignal<Record<string, string>>;
5125
- /**
5126
- * Sends through the host instead of `POST <baseUrl>/text-messages` — e.g. a page-specific endpoint that
5127
- * also marks a record Sent. Loading, toasts, `sent` and the double-send guard behave the same.
5128
- */
5129
- readonly sendFn: import("@angular/core").InputSignal<((payload: SendTextPayload) => Observable<unknown>) | null>;
5130
- /** Builds the success toast of a document send (default texts otherwise). */
5131
- readonly documentSentMessage: import("@angular/core").InputSignal<DocumentSentMessage | null>;
5132
- /** Shows the "Documents" section (search your documents; they are texted as a link). Off = the form is unchanged. */
5133
- readonly documents: import("@angular/core").InputSignal<boolean>;
5134
- /** false hides Attach Image and "Schedule for later" (for a host whose send function can't deliver them). */
5135
- readonly attachmentsAndScheduling: import("@angular/core").InputSignal<boolean>;
5136
- /** Purposes the app's backend supports for documents (default all). The text form only sends `ESIGN`; without it the section is unavailable. */
5137
- readonly documentPurposes: import("@angular/core").InputSignal<DocumentSendPurpose[]>;
5138
- /** Documents already chosen in the Documents section when the form opens. */
5139
- readonly initialDocuments: import("@angular/core").InputSignal<DocumentSeed[]>;
5140
- /**
5141
- * Turns on the signer logic for documents (informational documents, the multi-signer rule). A document with several customer signers
5142
- * can't be texted (the link goes to the first signer only): the section says "Send it by email." and Send stays off. `null` = unchanged.
5143
- */
5144
- readonly documentSigners: import("@angular/core").InputSignal<DocumentSignersConfig | null>;
5145
- /** Values the host has for THIS send; only the keys declared in `documentContextTypes` are sent, as `documents.context`. */
5146
- readonly sendContext: import("@angular/core").InputSignal<SendContext | null>;
5147
- /** The context keys the app's backend accepts. */
5148
- readonly documentContextTypes: import("@angular/core").InputSignal<ContextTypeDef[]>;
5149
- /** `true` = check (default route `POST <baseUrl>/documents/merge-check`), a function = the host's own check; shows a non-blocking "fields that will be empty" warning. */
5150
- readonly documentMergeCheck: import("@angular/core").InputSignal<boolean | MergeCheckFn>;
5151
- /** An existing envelope to text: its documents are fixed and it is sent (not created). Payload `documents.envelopeId`. */
5152
- readonly documentEnvelope: import("@angular/core").InputSignal<DocumentEnvelopeTarget | null>;
5153
- /** Shows "Expiry and Reminders" for the texted signing link (see `DocumentSigningOptions`); sent as `documents.expiryDays` / `reminderIntervalDays` / `maxReminders`. `null` = off. */
5154
- readonly documentSigningOptions: import("@angular/core").InputSignal<DocumentSigningOptions | null | undefined>;
5155
- /** "Preview Document" button(s) in the Documents section call this; `null` hides them. */
5156
- readonly documentPreview: import("@angular/core").InputSignal<DocumentPreviewHandler | null>;
5157
- /** The recipient handed to `documentPreview` (second argument): the panel's contact inputs, `null` while all four are blank. */
5158
- readonly previewContact: import("@angular/core").Signal<DocumentPreviewContact | null>;
5159
- /**
5160
- * Turns on the video settings (Playback, Call-to-Action, Hide reactions, Watch Preview, Remove Video) once a video is attached, starting
5161
- * from these defaults, and makes the video link carry them. `null` (default) = the plain share link is inserted, as before.
5162
- * A text is limited to 320 characters: a link with settings is longer, and Send stays off while the message is over the limit.
5163
- */
5164
- readonly videoDefaults: import("@angular/core").InputSignal<VideoDefaults | null>;
5165
- readonly sent: import("@angular/core").OutputEmitterRef<void>;
5166
- readonly phoneAdded: import("@angular/core").OutputEmitterRef<string>;
5167
- readonly validChange: import("@angular/core").OutputEmitterRef<boolean>;
5168
- /** A document send was refused because the document / envelope changed meanwhile (404 / 409): the host refreshes its list. */
5169
- readonly rejected: import("@angular/core").OutputEmitterRef<void>;
5170
- readonly MAX_LENGTH = 320;
5171
- mode: 'compose' | 'template';
5172
- body: string;
5173
- templateId: string | null;
5174
- previewFormat: 'preview' | 'raw';
5175
- previewingTemplate: {
5176
- subject: string | null;
5177
- body: string;
5178
- } | null;
5179
- showQuickPreview: boolean;
5180
- /** "View Send Preview" for the selected template. */
5181
- showSendPreview: boolean;
5182
- customVars: Record<string, string>;
5183
- pendingInputs: Record<string, string>;
5184
- loading: boolean;
5185
- showSchedule: boolean;
5186
- scheduledAt: string;
5187
- pendingPhone: string;
5188
- /** What the document section holds (null / empty = no documents) and whether it currently breaks a rule. */
5189
- documentsValue: DocumentSendValue | null;
5190
- documentsInvalid: boolean;
5191
- /** Lines of the merge check ("These fields will be left empty: …"). */
5192
- mergeWarnings: string[];
5193
- readonly mediaAttachment: import("@angular/core").WritableSignal<{
5194
- url: string;
5195
- mediaType: string;
5196
- mediaFileName: string;
5197
- sizeLabel: string;
5198
- } | null>;
5199
- readonly mediaUploading: import("@angular/core").WritableSignal<boolean>;
5200
- readonly savingPhone: import("@angular/core").WritableSignal<boolean>;
5201
- readonly modeTabs: PillTab[];
5202
- /** Market values (`area`, `median_price`, `dom`, `new_listings`) — only the ones `/service-areas` returned. */
5203
- private marketVars;
5204
- ngOnInit(): void;
5205
- /** Default last applied to compose mode — it only replaces text the user hasn't edited. */
5206
- private _appliedDefaultBody;
5207
- constructor();
5208
- setPreviewFormat(f: 'preview' | 'raw'): void;
5209
- get pendingPhoneValid(): boolean;
5210
- /** True when the sender chose at least one document (only possible when the `documents` input is on). */
5211
- get hasDocuments(): boolean;
5212
- /** The declared context keys with a value (`documents.context`). */
5213
- readonly forwardedContext: import("@angular/core").Signal<SendContext | undefined>;
5214
- /** The chosen documents the merge check looks at. */
5215
- get mergeDocuments(): DocumentOption[];
5216
- onMergeWarnings(lines: string[]): void;
5217
- /** The lines of the ONE warning banner: what choosing a document removed, the merge check. */
5218
- get warningLines(): {
5219
- key: string;
5220
- text: string;
5221
- testId: string | null;
5222
- }[];
5223
- /** Set when choosing the first document removed something the sender had already added - said out loud (aria-live), never silently. */
5224
- docsRemovedNote: string;
5225
- onDocumentsChange(v: DocumentSendValue): void;
5226
- onDocumentsInvalid(bad: boolean): void;
5227
- get canSend(): boolean;
5228
- get minScheduleTime(): string;
5229
- /**
5230
- * Values every tag can resolve from before the user types anything: the contact (name, first / last name, phone,
5231
- * email), the date, the market values `/service-areas` returned and the host's `context` — non-blank values only,
5232
- * later sources winning.
5233
- */
5234
- private get knownVars();
5235
- /** Merges `text` with every known value plus what the user typed — the ONE merge the pane, modal and payload use. */
5236
- resolveMergeTags(text: string): string;
5237
- /** Applied values plus anything typed into a missing-field input — so the preview updates as the user types. */
5238
- private get liveVars();
5239
- /** The body exactly as it will be sent (live: recomputed on every read, never cached). */
5240
- get resolvedBody(): string;
5241
- /** Template fields the user still has to fill — tags with no non-blank known value and nothing applied. */
5242
- get missingVars(): string[];
5243
- /** Why Send is off when the video link pushes the text over the SMS limit ('' otherwise). */
5244
- get videoLengthError(): string;
5245
- /** Compose mode: a `{{…}}` the form can't fill blocks sending (the server would refuse it). */
5246
- get composeTagError(): string;
5247
- /** Missing fields with nothing typed yet — Send stays disabled until this is empty. */
5248
- get unresolvedVars(): string[];
5249
- /**
5250
- * Applies every typed missing-field value (what the preview already shows) before sending. Never saves
5251
- * to the contact — only the explicit "+" / Enter apply does that.
5252
- */
5253
- private applyPendingVars;
5254
- formatVarLabel(key: string): string;
5255
- /** "View Send Preview": the selected template, merged exactly as it will be sent. */
5256
- openSendPreview(): void;
5257
- closeSendPreview(): void;
5258
- /** The picker's eye button: previews that template without selecting it. */
5259
- openQuickPreview(tpl: {
5260
- subject: string | null;
5261
- body: string;
5262
- }): void;
5263
- /** Applies a typed missing-field value. The explicit "+" / Enter apply (`persist`) also saves phone / address to the contact. */
5264
- applyVar(key: string, persist?: boolean): void;
5265
- clearTemplate(): void;
5266
- notifyValid(): void;
5267
- setMode(key: string): void;
5268
- savePhone(): void;
5269
- onTemplateSelected(tpl: TemplateItem): void;
5270
- onFileSelected(event: Event): void;
5271
- removeMedia(): void;
5272
- insertVideo(v: VideoMessage): void;
5273
- /** The video attached through the settings flow (null = none) and the line it put into the message. */
5274
- videoPicked: VideoMessage | null;
5275
- /** Bumped to re-create the video picker (it keeps its own selection and has no clear output). */
5276
- videoPickerKey: number;
5277
- private _videoLine;
5278
- /** The picker's output: with `videoDefaults` the video gets its settings section, otherwise the plain link is inserted as before. */
5279
- onVideoSelected(v: VideoMessage): void;
5280
- /** The settings section's output: rewrites the video line of the message with the current link (the rest of the message is untouched). */
5281
- onVideoLink(link: string): void;
5282
- /** "Remove Video": takes the video line out of the message and brings the picker back. */
5283
- removeVideo(): void;
5284
- private discardVideo;
5285
- submit(): void;
5286
- static ɵfac: i0.ɵɵFactoryDeclaration<SendTextComponent, never>;
5287
- static ɵcmp: i0.ɵɵComponentDeclaration<SendTextComponent, "ui-send-text", never, {
5288
- "contactName": {
5289
- "alias": "contactName";
5290
- "required": false;
5291
- "isSignal": true;
5292
- };
5293
- "contactPhone": {
5294
- "alias": "contactPhone";
5295
- "required": false;
5296
- "isSignal": true;
5297
- };
5298
- "contactEmail": {
5299
- "alias": "contactEmail";
5300
- "required": false;
5301
- "isSignal": true;
5302
- };
5303
- "contactId": {
5304
- "alias": "contactId";
5305
- "required": false;
5306
- "isSignal": true;
5307
- };
5308
- "defaultBody": {
5309
- "alias": "defaultBody";
5310
- "required": false;
5311
- "isSignal": true;
5312
- };
5313
- "context": {
5314
- "alias": "context";
5315
- "required": false;
5316
- "isSignal": true;
5317
- };
5318
- "sendFn": {
5319
- "alias": "sendFn";
5320
- "required": false;
5321
- "isSignal": true;
5322
- };
5323
- "documentSentMessage": {
5324
- "alias": "documentSentMessage";
5325
- "required": false;
5326
- "isSignal": true;
5327
- };
5328
- "documents": {
5329
- "alias": "documents";
5330
- "required": false;
5331
- "isSignal": true;
5332
- };
5333
- "attachmentsAndScheduling": {
5334
- "alias": "attachmentsAndScheduling";
5335
- "required": false;
5336
- "isSignal": true;
5337
- };
5338
- "documentPurposes": {
5339
- "alias": "documentPurposes";
5340
- "required": false;
5341
- "isSignal": true;
5342
- };
5343
- "initialDocuments": {
5344
- "alias": "initialDocuments";
5345
- "required": false;
5346
- "isSignal": true;
5347
- };
5348
- "documentSigners": {
5349
- "alias": "documentSigners";
5350
- "required": false;
5351
- "isSignal": true;
5352
- };
5353
- "sendContext": {
5354
- "alias": "sendContext";
5355
- "required": false;
5356
- "isSignal": true;
5357
- };
5358
- "documentContextTypes": {
5359
- "alias": "documentContextTypes";
5360
- "required": false;
5361
- "isSignal": true;
5362
- };
5363
- "documentMergeCheck": {
5364
- "alias": "documentMergeCheck";
5365
- "required": false;
5366
- "isSignal": true;
5367
- };
5368
- "documentEnvelope": {
5369
- "alias": "documentEnvelope";
5370
- "required": false;
5371
- "isSignal": true;
5372
- };
5373
- "documentSigningOptions": {
5374
- "alias": "documentSigningOptions";
5375
- "required": false;
5376
- "isSignal": true;
5377
- };
5378
- "documentPreview": {
5379
- "alias": "documentPreview";
5380
- "required": false;
5381
- "isSignal": true;
5382
- };
5383
- "videoDefaults": {
5384
- "alias": "videoDefaults";
5385
- "required": false;
5386
- "isSignal": true;
5387
- };
5388
- }, {
5389
- "sent": "sent";
5390
- "phoneAdded": "phoneAdded";
5391
- "validChange": "validChange";
5392
- "rejected": "rejected";
5393
- }, never, never, true, never>;
5394
- }
5395
- /** One match of the host's `jobSearch` function; `description` is the small second line (e.g. the customer). */
5396
- export interface JobSearchResult {
5397
- id: string;
5398
- name: string;
5399
- description?: string | null;
5400
- }
5401
- export interface MessageContact {
5402
- id: string;
5403
- name: string;
5404
- email?: string | null;
5405
- phone?: string | null;
5406
- smsOptedIn?: boolean | null;
5407
- }
5408
- export declare class SendMessagePanelComponent {
5409
- readonly open: import("@angular/core").InputSignal<boolean>;
5410
- readonly contact: import("@angular/core").InputSignal<MessageContact | null>;
5411
- readonly loading: import("@angular/core").InputSignal<boolean>;
5412
- /** Pass true when Twilio / SMS is enabled in the consuming app's settings. */
5413
- readonly textEnabled: import("@angular/core").InputSignal<boolean>;
5414
- /** Panel header. */
5415
- readonly title: import("@angular/core").InputSignal<string>;
5416
- /** Prefill for the email Subject / Message and the text Message in "Create Message" mode. */
5417
- readonly defaultSubject: import("@angular/core").InputSignal<string>;
5418
- readonly defaultBody: import("@angular/core").InputSignal<string>;
5419
- readonly defaultMessage: import("@angular/core").InputSignal<string>;
5420
- /** Extra merge variables (e.g. `estimate_number`, `estimate_total`) for templates and the preview. */
5421
- readonly context: import("@angular/core").InputSignal<Record<string, string>>;
5422
- /**
5423
- * Page-specific sending: when set, the email / text form calls this instead of POSTing to the default
5424
- * `/email-messages` / `/text-messages` endpoint (e.g. an endpoint that also marks an estimate Sent).
5425
- */
5426
- readonly sendEmail: import("@angular/core").InputSignal<((payload: SendEmailPayload) => Observable<unknown>) | null>;
5427
- readonly sendText: import("@angular/core").InputSignal<((payload: SendTextPayload) => Observable<unknown>) | null>;
5428
- /** Email tab only: shows an "include receipt" checkbox; the choice is sent as `SendEmailPayload.includeReceipt`. */
5429
- readonly showReceiptOption: import("@angular/core").InputSignal<boolean>;
5430
- readonly receiptLabel: import("@angular/core").InputSignal<string>;
5431
- readonly receiptDefault: import("@angular/core").InputSignal<boolean>;
5432
- /**
5433
- * Adds a "Documents" section to the email and text forms: the sender searches the company's documents and sends them
5434
- * with the message (e-signature link, attachment or both on email; a link on text). Needs the standard documents routes —
5435
- * see docs/send-documents-contract.md. Off (default) = both forms are exactly as before.
5436
- */
5437
- readonly documents: import("@angular/core").InputSignal<boolean>;
5438
- /** Pass false for a user who may not send documents (e.g. read-only): the Documents section is hidden even when `documents` is on. */
5439
- readonly documentsEnabled: import("@angular/core").InputSignal<boolean>;
5440
- /** Email tab only: adds a CC field; the addresses are sent as `SendEmailPayload.cc`. */
5441
- readonly showCc: import("@angular/core").InputSignal<boolean>;
5442
- /** false hides Attach Files / Attach Image and "Schedule for later" in both forms (a host `sendEmail` / `sendText` that can't deliver them). */
5443
- readonly attachmentsAndScheduling: import("@angular/core").InputSignal<boolean>;
5444
- /** Purposes the app's backend supports for documents (default all three); `['ESIGN']` hides the purpose select. */
5445
- readonly documentPurposes: import("@angular/core").InputSignal<DocumentSendPurpose[]>;
5446
- /** Documents already chosen when the panel opens (e.g. the row "Send Document" was clicked on); the user can change them. */
5447
- readonly initialDocuments: import("@angular/core").InputSignal<DocumentSeed[]>;
5448
- /**
5449
- * Turns on the signer logic of the Documents section (docs/send-documents-contract.md, Addendum 2026-10-19), all off when `null` (default):
5450
- * - a document with MORE THAN ONE customer signer shows one required contact picker per further role (Signer 1 is the recipient), Send
5451
- * stays off until every role has a contact, and `documents.signers` (complete, ordered by role) is added to the payload;
5452
- * - a document that requires the sender's countersignature shows one read-only line ("Countersigned by <name> after all signers.");
5453
- * - a document with no signature fields (`signerRoles: []`) is informational: no signers, countersign line, DocuSign or signing options -
5454
- * the recipient gets a view link;
5455
- * - DocuSign is offered only for a signed document with one customer signer, and the countersign checkbox is replaced by the document's setting.
5456
- * The roles come from the `GET /documents` row (`signerRoles`) or from `resolveRoles`. A multi-signer document can't be texted.
5457
- */
5458
- readonly documentSigners: import("@angular/core").InputSignal<DocumentSignersConfig | null>;
5459
- /** Values the host has for THIS send (e.g. `{ propertyId }`); only keys listed in `documentContextTypes` are sent, as `documents.context`. */
5460
- readonly sendContext: import("@angular/core").InputSignal<SendContext | null>;
5461
- /** The context keys the app's backend accepts. */
5462
- readonly documentContextTypes: import("@angular/core").InputSignal<ContextTypeDef[]>;
5463
- /**
5464
- * The pre-send "fields that will be empty" check, for documents with mapped data fields only (non-blocking warning): `true` = default route
5465
- * `POST <baseUrl>/documents/merge-check`, a function = your own call, `false` (default) = off.
5466
- */
5467
- readonly documentMergeCheck: import("@angular/core").InputSignal<boolean | MergeCheckFn>;
5468
- /**
5469
- * Sends an EXISTING envelope: its documents are fixed (no search, no remove), the recipient is chosen in the panel, and the request is sent
5470
- * (`POST <baseUrl>/documents/envelopes/{id}/send`, or your `sendEmail` / `sendText` with `documents.envelopeId`) instead of created.
5471
- * Turns the Documents section on by itself. `null` (default) = a new request from the chosen documents.
5472
- */
5473
- readonly documentEnvelope: import("@angular/core").InputSignal<DocumentEnvelopeTarget | null>;
5474
- /** Builds the success toast of a document send (`"<title>" sent for signature`, `Envelope "<name>" sent` …); the default texts apply when unset. */
5475
- readonly documentSentMessage: import("@angular/core").InputSignal<DocumentSentMessage | null>;
5476
- /** false = the app's email sending is switched off (Communication settings): the Email tab says so and Send stays off. Default true. */
5477
- readonly emailEnabled: import("@angular/core").InputSignal<boolean>;
5478
- /** The footer button text instead of `Send Email` / `Send Text` (e.g. `Send Document`, `Send Envelope`). */
5479
- readonly sendLabel: import("@angular/core").InputSignal<string>;
5480
- /** The 620px wide panel (a long form with signers). Default false. */
5481
- readonly wide: import("@angular/core").InputSignal<boolean>;
5482
- /**
5483
- * Shows "Expiry and Reminders" in the Documents section (Expiry 1-90 days, Reminder Interval 1-30 days, Max Reminders 0-10; required
5484
- * whole numbers) for native e-signature requests, on the Email tab (purpose e-signature or both) and the Text tab. Pass `{}` for the
5485
- * defaults 7 / 2 / 3 or set any of `expiryDays`, `reminderIntervalDays`, `maxReminders`. The values are sent as
5486
- * `documents.expiryDays` / `reminderIntervalDays` / `maxReminders`. `null` (default) = not shown, nothing sent.
5487
- */
5488
- readonly documentSigningOptions: import("@angular/core").InputSignal<DocumentSigningOptions | null | undefined>;
5489
- /**
5490
- * Email tab: the host says DocuSign is connected (the library never calls `/docusign/status`). Offers "Native E-Sign / Send via DocuSign"
5491
- * while exactly one document is chosen; DocuSign sends through `POST <baseUrl>/docusign/send` (or your `sendEmail`, which then gets
5492
- * `documents.provider === 'DOCUSIGN'`). A document row/`initialDocuments` entry with `requiresCountersign: true` also offers "Require my
5493
- * countersignature after client signs". Default `false` = native only.
5494
- */
5495
- readonly docuSignConnected: import("@angular/core").InputSignal<boolean>;
5496
- /**
5497
- * "Preview Document" in the Documents section: called with the chosen document when its button is clicked. The library has no route
5498
- * of its own — the host opens its viewer. Open a tab synchronously inside this function (Safari blocks `window.open` after an await).
5499
- * `null` (default) = no preview button.
5500
- */
5501
- readonly documentPreview: import("@angular/core").InputSignal<DocumentPreviewHandler | null>;
5502
- /**
5503
- * The "Video" section (always the last section of the Email and Text forms): once a video is attached it shows Playback, Call-to-Action
5504
- * (+ URL / label), Hide reactions, Watch Preview and Remove Video, starting from these defaults (your Communication settings), and the
5505
- * link in the message carries them (`buildVideoLink`). `null` (default) = the plain share link is inserted, with no settings.
5506
- */
5507
- readonly videoDefaults: import("@angular/core").InputSignal<VideoDefaults | null>;
5508
- /** The Documents section is shown only when the host turned it on AND the user may send documents. */
5509
- protected readonly documentsOn: import("@angular/core").Signal<boolean>;
5510
- /**
5511
- * Shows an optional "Job" search under the contact (off by default): the sender may link the message to one of the
5512
- * company's jobs (found with the host's `jobSearch` function). The pick is reported through `jobSelected`; it is cleared whenever the
5513
- * panel opens or another contact is chosen. The panel itself sends nothing about it — the host's `sendEmail` / `sendText`
5514
- * function adds it to its request.
5515
- */
5516
- readonly showJobPicker: import("@angular/core").InputSignal<boolean>;
5517
- readonly jobLabel: import("@angular/core").InputSignal<string>;
5518
- readonly jobHint: import("@angular/core").InputSignal<string>;
5519
- /**
5520
- * Looks jobs up for the Job field (the panel knows nothing about the app's API): called with the typed text (2+ characters,
5521
- * debounced); returns the matches. Required for `showJobPicker` to find anything.
5522
- */
5523
- readonly jobSearch: import("@angular/core").InputSignal<((query: string) => Observable<JobSearchResult[]>) | null>;
5524
- readonly jobSelected: import("@angular/core").OutputEmitterRef<{
5525
- id: string;
5526
- name: string;
5527
- } | null>;
5528
- readonly closed: import("@angular/core").OutputEmitterRef<void>;
5529
- readonly sent: import("@angular/core").OutputEmitterRef<void>;
5530
- readonly emailAdded: import("@angular/core").OutputEmitterRef<string>;
5531
- /** A document / envelope send was refused because it changed meanwhile (404 / 409): the host refreshes its list. */
5532
- readonly rejected: import("@angular/core").OutputEmitterRef<void>;
5533
- /**
5534
- * With `documentSigners` on: the user clicked "Place your countersignature box" under the countersign line of a document that requires a
5535
- * countersignature but whose row says `hasCountersignPlacement: false` (docs/send-documents-contract.md, Addendum 2026-10-19 (b)).
5536
- * Payload = that document `{ id, title }`; the host navigates to Map Data Fields. Never emitted when the flag is true / absent.
5537
- */
5538
- readonly mapFieldsClick: import("@angular/core").OutputEmitterRef<{
5539
- id: string;
5540
- title: string;
5541
- }>;
5542
- readonly phoneAdded: import("@angular/core").OutputEmitterRef<string>;
5543
- readonly sendEmailRef: import("@angular/core").Signal<SendEmailComponent | undefined>;
5544
- readonly sendTextRef: import("@angular/core").Signal<SendTextComponent | undefined>;
5545
- private readonly destroyRef;
5546
- readonly jobSearch$: Subject<string>;
5547
- readonly jobOptions: import("@angular/core").WritableSignal<ComboboxOption<unknown>[]>;
5548
- readonly jobLoading: import("@angular/core").WritableSignal<boolean>;
5549
- private readonly pickedJob;
5550
- readonly jobValue: import("@angular/core").Signal<ComboboxSelection | null>;
5551
- onJobPick(o: ComboboxOption | null): void;
5552
- /** A new form (fresh open / another contact) starts without a linked job. */
5553
- private resetJob;
5554
- readonly activeContact: import("@angular/core").WritableSignal<MessageContact | null>;
5555
- /** What the sender should know about the picked contact before sending (why a channel is missing, what to add). */
5556
- readonly contactNotices: import("@angular/core").Signal<string[]>;
5557
- readonly channel: import("@angular/core").WritableSignal<"text" | "email">;
5558
- readonly valid: import("@angular/core").WritableSignal<boolean>;
5559
- /** Bumped on every fresh open / new contact — re-creates the email and text forms so no draft carries over. */
5560
- readonly formEpoch: import("@angular/core").WritableSignal<number>;
5561
- private _prevOpen;
5562
- constructor();
5563
- onContactSelected(c: ContactLookup | null): void;
5564
- onChannelChange(ch: 'email' | 'text'): void;
5565
- onEmailAdded(email: string): void;
5566
- onPhoneAdded(phone: string): void;
5567
- submit(): void;
5568
- onSent(): void;
5569
- onClose(): void;
5570
- static ɵfac: i0.ɵɵFactoryDeclaration<SendMessagePanelComponent, never>;
5571
- static ɵcmp: i0.ɵɵComponentDeclaration<SendMessagePanelComponent, "ui-send-message-panel", never, {
5572
- "open": {
5573
- "alias": "open";
5574
- "required": false;
5575
- "isSignal": true;
5576
- };
5577
- "contact": {
5578
- "alias": "contact";
5579
- "required": false;
5580
- "isSignal": true;
5581
- };
5582
- "loading": {
5583
- "alias": "loading";
5584
- "required": false;
5585
- "isSignal": true;
5586
- };
5587
- "textEnabled": {
5588
- "alias": "textEnabled";
5589
- "required": false;
5590
- "isSignal": true;
5591
- };
5592
- "title": {
5593
- "alias": "title";
5594
- "required": false;
5595
- "isSignal": true;
5596
- };
5597
- "defaultSubject": {
5598
- "alias": "defaultSubject";
5599
- "required": false;
5600
- "isSignal": true;
5601
- };
5602
- "defaultBody": {
5603
- "alias": "defaultBody";
5604
- "required": false;
5605
- "isSignal": true;
5606
- };
5607
- "defaultMessage": {
5608
- "alias": "defaultMessage";
5609
- "required": false;
5610
- "isSignal": true;
5611
- };
5612
- "context": {
5613
- "alias": "context";
5614
- "required": false;
5615
- "isSignal": true;
5616
- };
5617
- "sendEmail": {
5618
- "alias": "sendEmail";
5619
- "required": false;
5620
- "isSignal": true;
5621
- };
5622
- "sendText": {
5623
- "alias": "sendText";
5624
- "required": false;
5625
- "isSignal": true;
5626
- };
5627
- "showReceiptOption": {
5628
- "alias": "showReceiptOption";
5629
- "required": false;
5630
- "isSignal": true;
5631
- };
5632
- "receiptLabel": {
5633
- "alias": "receiptLabel";
5634
- "required": false;
5635
- "isSignal": true;
5636
- };
5637
- "receiptDefault": {
5638
- "alias": "receiptDefault";
5639
- "required": false;
5640
- "isSignal": true;
5641
- };
5642
- "documents": {
5643
- "alias": "documents";
5644
- "required": false;
5645
- "isSignal": true;
5646
- };
5647
- "documentsEnabled": {
5648
- "alias": "documentsEnabled";
5649
- "required": false;
5650
- "isSignal": true;
5651
- };
5652
- "showCc": {
5653
- "alias": "showCc";
5654
- "required": false;
5655
- "isSignal": true;
5656
- };
5657
- "attachmentsAndScheduling": {
5658
- "alias": "attachmentsAndScheduling";
5659
- "required": false;
5660
- "isSignal": true;
5661
- };
5662
- "documentPurposes": {
5663
- "alias": "documentPurposes";
5664
- "required": false;
5665
- "isSignal": true;
5666
- };
5667
- "initialDocuments": {
5668
- "alias": "initialDocuments";
5669
- "required": false;
5670
- "isSignal": true;
5671
- };
5672
- "documentSigners": {
5673
- "alias": "documentSigners";
5674
- "required": false;
5675
- "isSignal": true;
5676
- };
5677
- "sendContext": {
5678
- "alias": "sendContext";
5679
- "required": false;
5680
- "isSignal": true;
5681
- };
5682
- "documentContextTypes": {
5683
- "alias": "documentContextTypes";
5684
- "required": false;
5685
- "isSignal": true;
5686
- };
5687
- "documentMergeCheck": {
5688
- "alias": "documentMergeCheck";
5689
- "required": false;
5690
- "isSignal": true;
5691
- };
5692
- "documentEnvelope": {
5693
- "alias": "documentEnvelope";
5694
- "required": false;
5695
- "isSignal": true;
5696
- };
5697
- "documentSentMessage": {
5698
- "alias": "documentSentMessage";
5699
- "required": false;
5700
- "isSignal": true;
5701
- };
5702
- "emailEnabled": {
5703
- "alias": "emailEnabled";
5704
- "required": false;
5705
- "isSignal": true;
5706
- };
5707
- "sendLabel": {
5708
- "alias": "sendLabel";
5709
- "required": false;
5710
- "isSignal": true;
5711
- };
5712
- "wide": {
5713
- "alias": "wide";
5714
- "required": false;
5715
- "isSignal": true;
5716
- };
5717
- "documentSigningOptions": {
5718
- "alias": "documentSigningOptions";
5719
- "required": false;
5720
- "isSignal": true;
5721
- };
5722
- "docuSignConnected": {
5723
- "alias": "docuSignConnected";
5724
- "required": false;
5725
- "isSignal": true;
5726
- };
5727
- "documentPreview": {
5728
- "alias": "documentPreview";
5729
- "required": false;
5730
- "isSignal": true;
5731
- };
5732
- "videoDefaults": {
5733
- "alias": "videoDefaults";
5734
- "required": false;
5735
- "isSignal": true;
5736
- };
5737
- "showJobPicker": {
5738
- "alias": "showJobPicker";
5739
- "required": false;
5740
- "isSignal": true;
5741
- };
5742
- "jobLabel": {
5743
- "alias": "jobLabel";
5744
- "required": false;
5745
- "isSignal": true;
5746
- };
5747
- "jobHint": {
5748
- "alias": "jobHint";
5749
- "required": false;
5750
- "isSignal": true;
5751
- };
5752
- "jobSearch": {
5753
- "alias": "jobSearch";
5754
- "required": false;
5755
- "isSignal": true;
5756
- };
5757
- }, {
5758
- "jobSelected": "jobSelected";
5759
- "closed": "closed";
5760
- "sent": "sent";
5761
- "emailAdded": "emailAdded";
5762
- "rejected": "rejected";
5763
- "mapFieldsClick": "mapFieldsClick";
5764
- "phoneAdded": "phoneAdded";
5765
- }, never, never, true, never>;
5766
- }
5767
- /**
5768
- * ui-document-signers — the signer section of a document send: one required contact per customer signer role of the chosen document
5769
- * (Signer 1 is the recipient, shown read-only) in signing order, and the one read-only countersign line.
5770
- *
5771
- * Internal child of the message forms (`ui-send-message-panel` with `documentSigners`); hosts do not place it. Rows exist only for a
5772
- * document with MORE THAN ONE customer signer; a single-signer document shows nothing here except the countersign line. It emits the
5773
- * complete `signers` list (never a partial one: `null` until every role has a contact) and its validity (`UiFieldValidity`):
5774
- * a missing contact is `<Role label> is required.`, a contact without an email `<Name> has no email address.`, the same person in two
5775
- * roles `<Name> is already <Role label>.` (unless the config allows it).
5776
- */
5777
- export declare class DocumentSignersComponent implements UiFieldValidity {
5778
- /** The signer logic's conclusion for the chosen document(s) (`ui-document-send-options` value `signerInfo`). */
5779
- readonly info: import("@angular/core").InputSignal<DocumentSignerInfo | null>;
5780
- readonly config: import("@angular/core").InputSignal<DocumentSignersConfig | null>;
5781
- /** The recipient of the message = Signer 1. */
5782
- readonly recipient: import("@angular/core").InputSignal<SignerPick>;
5783
- /** Shows the "<Role> is required." messages now (otherwise after the first blur). */
5784
- readonly showErrors: import("@angular/core").InputSignal<boolean>;
5785
- /** The sender chose DocuSign: only the countersign line applies. */
5786
- readonly viaDocuSign: import("@angular/core").InputSignal<boolean>;
5787
- /** The complete signer list (recipient first) or null while a role has no contact. Emitted on every change. */
5788
- readonly signersChange: import("@angular/core").OutputEmitterRef<SendSigner[] | null>;
5789
- readonly invalidChange: import("@angular/core").OutputEmitterRef<boolean>;
5790
- /** The "Place your countersignature box" link was clicked: the document whose countersign box is not placed (the host opens Map Data Fields). */
5791
- readonly mapFieldsClick: import("@angular/core").OutputEmitterRef<{
5792
- id: string;
5793
- title: string;
5794
- }>;
5795
- readonly picks: import("@angular/core").WritableSignal<Partial<Record<SignerRole, ContactLookup | null>>>;
5796
- protected readonly rowsShown: import("@angular/core").Signal<boolean>;
5797
- protected readonly line: import("@angular/core").Signal<string>;
5798
- /** Documents the "place your box" link is offered for: native send only (DocuSign places its own fields) and only while the countersign line shows. */
5799
- protected readonly placeDocs: import("@angular/core").Signal<{
5800
- id: string;
5801
- title: string;
5802
- }[]>;
5803
- readonly problems: import("@angular/core").Signal<Partial<Record<SignerRole, string>>>;
5804
- readonly signers: import("@angular/core").Signal<SendSigner[] | null>;
5805
- readonly errorMessage: import("@angular/core").Signal<string>;
5806
- readonly invalid: import("@angular/core").Signal<boolean>;
5807
- constructor();
5808
- protected placeLabel(title: string): string;
5809
- /** Visible text: with several documents the title is part of it (label-in-name: it contains the start of the accessible name). */
5810
- protected placeText(title: string): string;
5811
- protected label(role: SignerRole): string;
5812
- /** Under a picker: the problems of a chosen contact (no email / same person twice); the empty-row message is the picker's own (`visibleErrorMessage`). */
5813
- protected visibleProblem(role: SignerRole): string;
5814
- pick(role: SignerRole, c: ContactLookup | null): void;
5815
- static ɵfac: i0.ɵɵFactoryDeclaration<DocumentSignersComponent, never>;
5816
- static ɵcmp: i0.ɵɵComponentDeclaration<DocumentSignersComponent, "ui-document-signers", never, {
5817
- "info": {
5818
- "alias": "info";
5819
- "required": false;
5820
- "isSignal": true;
5821
- };
5822
- "config": {
5823
- "alias": "config";
5824
- "required": false;
5825
- "isSignal": true;
5826
- };
5827
- "recipient": {
5828
- "alias": "recipient";
5829
- "required": false;
5830
- "isSignal": true;
5831
- };
5832
- "showErrors": {
5833
- "alias": "showErrors";
5834
- "required": false;
5835
- "isSignal": true;
5836
- };
5837
- "viaDocuSign": {
5838
- "alias": "viaDocuSign";
5839
- "required": false;
5840
- "isSignal": true;
5841
- };
5842
- }, {
5843
- "signersChange": "signersChange";
5844
- "invalidChange": "invalidChange";
5845
- "mapFieldsClick": "mapFieldsClick";
5846
- }, never, never, true, never>;
5847
- }
5848
- /** Quiet time after the last change before the check is requested. */
5849
- export declare const MERGE_CHECK_DEBOUNCE_MS = 300;
5850
- /**
5851
- * ui-document-merge-check — the pre-send "fields that will be empty" check (non-blocking), logic only (it renders nothing).
5852
- *
5853
- * Internal child of the message forms. While `enabled` is `true` (default route `POST <baseUrl>/documents/merge-check`) or a host
5854
- * function, and at least one chosen document has mapped data fields, it asks which data fields would be left empty for this recipient,
5855
- * these signers and this context, and emits the warning lines (`warningsChange`). Debounced, a newer request cancels an older one
5856
- * (`switchMap`), never cached. A failed or slow check emits no warning and never blocks Send. Documents with no mapped data fields
5857
- * are not sent to the check.
5858
- */
5859
- export declare class DocumentMergeCheckComponent {
5860
- private readonly http;
5861
- private readonly destroyRef;
5862
- private readonly apiBase;
5863
- /** `true` = the default route, a function = the host's own call, `false` / `null` = off. */
5864
- readonly enabled: import("@angular/core").InputSignal<boolean | MergeCheckFn | null>;
5865
- readonly documents: import("@angular/core").InputSignal<SignerDocLike[]>;
5866
- readonly customerId: import("@angular/core").InputSignal<string>;
5867
- readonly signers: import("@angular/core").InputSignal<SendSigner[] | null>;
5868
- readonly context: import("@angular/core").InputSignal<SendContext | undefined>;
5869
- /** The warning lines (empty = nothing to warn about). Emitted whenever they change. */
5870
- readonly warningsChange: import("@angular/core").OutputEmitterRef<string[]>;
5871
- private readonly request;
5872
- constructor();
5873
- private lastLines;
5874
- private call;
5875
- static ɵfac: i0.ɵɵFactoryDeclaration<DocumentMergeCheckComponent, never>;
5876
- static ɵcmp: i0.ɵɵComponentDeclaration<DocumentMergeCheckComponent, "ui-document-merge-check", never, {
5877
- "enabled": {
5878
- "alias": "enabled";
5879
- "required": false;
5880
- "isSignal": true;
5881
- };
5882
- "documents": {
5883
- "alias": "documents";
5884
- "required": false;
5885
- "isSignal": true;
5886
- };
5887
- "customerId": {
5888
- "alias": "customerId";
5889
- "required": false;
5890
- "isSignal": true;
5891
- };
5892
- "signers": {
5893
- "alias": "signers";
5894
- "required": false;
5895
- "isSignal": true;
5896
- };
5897
- "context": {
5898
- "alias": "context";
5899
- "required": false;
5900
- "isSignal": true;
5901
- };
5902
- }, {
5903
- "warningsChange": "warningsChange";
5904
- }, never, never, true, never>;
5905
- }
5906
- export interface BulkMessageContact {
5907
- id: string;
5908
- name: string;
5909
- email: string | null;
5910
- phone: string | null;
5911
- }
5912
- export interface BulkMessageSendEvent {
5913
- channel: 'email' | 'text';
5914
- subject: string;
5915
- body: string;
5916
- contacts: BulkMessageContact[];
5917
- }
5918
- export declare class BulkMessagePanelComponent {
5919
- readonly open: import("@angular/core").InputSignal<boolean>;
5920
- readonly contacts: import("@angular/core").InputSignal<BulkMessageContact[]>;
5921
- readonly textEnabled: import("@angular/core").InputSignal<boolean>;
5922
- readonly sending: import("@angular/core").InputSignal<boolean>;
5923
- readonly closed: import("@angular/core").OutputEmitterRef<void>;
5924
- readonly send: import("@angular/core").OutputEmitterRef<BulkMessageSendEvent>;
5925
- readonly channel: import("@angular/core").WritableSignal<"text" | "email">;
5926
- private readonly _subject;
5927
- private readonly _body;
5928
- get subject(): string;
5929
- set subject(v: string);
5930
- get body(): string;
5931
- set body(v: string);
5932
- readonly emailContacts: import("@angular/core").Signal<BulkMessageContact[]>;
5933
- readonly textContacts: import("@angular/core").Signal<BulkMessageContact[]>;
5934
- readonly activeContacts: import("@angular/core").Signal<BulkMessageContact[]>;
5935
- readonly skippedCount: import("@angular/core").Signal<number>;
5936
- readonly canSend: import("@angular/core").Signal<boolean>;
5937
- readonly primaryLabel: import("@angular/core").Signal<string>;
5938
- private _prevOpen;
5939
- constructor();
5940
- onChannelChange(ch: 'email' | 'text'): void;
5941
- onSend(): void;
5942
- static ɵfac: i0.ɵɵFactoryDeclaration<BulkMessagePanelComponent, never>;
5943
- static ɵcmp: i0.ɵɵComponentDeclaration<BulkMessagePanelComponent, "ui-bulk-message-panel", never, {
5944
- "open": {
5945
- "alias": "open";
5946
- "required": false;
5947
- "isSignal": true;
5948
- };
5949
- "contacts": {
5950
- "alias": "contacts";
5951
- "required": false;
5952
- "isSignal": true;
5953
- };
5954
- "textEnabled": {
5955
- "alias": "textEnabled";
5956
- "required": false;
5957
- "isSignal": true;
5958
- };
5959
- "sending": {
5960
- "alias": "sending";
5961
- "required": false;
5962
- "isSignal": true;
5963
- };
5964
- }, {
5965
- "closed": "closed";
5966
- "send": "send";
5967
- }, never, never, true, never>;
5968
- }
5969
- export interface ActiveConfirm {
5970
- title: string;
5971
- message: string;
5972
- confirmLabel: string;
5973
- cancelLabel: string;
5974
- variant: 'danger' | 'primary' | 'warning';
5975
- /** Optional bullet list rendered under the message (plain text). */
5976
- details: string[];
5977
- }
5978
- export declare class ConfirmService {
5979
- private _open;
5980
- private _active;
5981
- private _resolve;
5982
- readonly open: import("@angular/core").Signal<boolean>;
5983
- readonly active: import("@angular/core").Signal<ActiveConfirm | null>;
5984
- /**
5985
- * Live <ui-confirm-outlet> instances, oldest first. Every ui-data-table renders an outlet, so
5986
- * several can exist at once (e.g. during a route change the next page's table is created before
5987
- * the previous page's is destroyed). Only the oldest live outlet renders the dialog; when it is
5988
- * destroyed the next one takes over, so a confirm always has somewhere to render.
5989
- */
5990
- private readonly _outlets;
5991
- readonly primaryOutlet: import("@angular/core").Signal<object>;
5992
- registerOutlet(outlet: object): void;
5993
- unregisterOutlet(outlet: object): void;
5994
- confirm(config: {
5995
- title: string;
5996
- message: string;
5997
- confirmLabel?: string;
5998
- cancelLabel?: string;
5999
- variant?: 'danger' | 'primary' | 'warning';
6000
- details?: string[];
6001
- }): Promise<boolean>;
6002
- dismiss(confirmed: boolean): void;
6003
- static ɵfac: i0.ɵɵFactoryDeclaration<ConfirmService, never>;
6004
- static ɵprov: i0.ɵɵInjectableDeclaration<any>;
6005
- }
6006
- export declare class ConfirmOutletComponent implements OnInit, OnDestroy {
6007
- protected readonly svc: ConfirmService;
6008
- protected readonly _isPrimary: import("@angular/core").Signal<boolean>;
6009
- ngOnInit(): void;
6010
- ngOnDestroy(): void;
6011
- static ɵfac: i0.ɵɵFactoryDeclaration<ConfirmOutletComponent, never>;
6012
- static ɵcmp: i0.ɵɵComponentDeclaration<ConfirmOutletComponent, "ui-confirm-outlet", never, {}, {}, never, never, true, never>;
6013
- }
6014
- export declare class EmptyStateComponent {
6015
- readonly message: import("@angular/core").InputSignal<string>;
6016
- readonly title: import("@angular/core").InputSignal<string>;
6017
- readonly iconType: import("@angular/core").InputSignal<string>;
6018
- static ɵfac: i0.ɵɵFactoryDeclaration<EmptyStateComponent, never>;
6019
- static ɵcmp: i0.ɵɵComponentDeclaration<EmptyStateComponent, "ui-empty-state", never, {
6020
- "message": {
6021
- "alias": "message";
6022
- "required": false;
6023
- "isSignal": true;
6024
- };
6025
- "title": {
6026
- "alias": "title";
6027
- "required": false;
6028
- "isSignal": true;
6029
- };
6030
- "iconType": {
6031
- "alias": "iconType";
6032
- "required": false;
6033
- "isSignal": true;
6034
- };
6035
- }, {}, never, ["*"], true, never>;
6036
- }
6037
- export declare class ErrorStateComponent {
6038
- readonly message: import("@angular/core").InputSignal<string>;
6039
- readonly retryLabel: import("@angular/core").InputSignal<string>;
6040
- readonly retrying: import("@angular/core").InputSignal<boolean>;
6041
- readonly retry: import("@angular/core").OutputEmitterRef<void>;
6042
- static ɵfac: i0.ɵɵFactoryDeclaration<ErrorStateComponent, never>;
6043
- static ɵcmp: i0.ɵɵComponentDeclaration<ErrorStateComponent, "ui-error-state", never, {
6044
- "message": {
6045
- "alias": "message";
6046
- "required": false;
6047
- "isSignal": true;
6048
- };
6049
- "retryLabel": {
6050
- "alias": "retryLabel";
6051
- "required": false;
6052
- "isSignal": true;
6053
- };
6054
- "retrying": {
6055
- "alias": "retrying";
6056
- "required": false;
6057
- "isSignal": true;
6058
- };
6059
- }, {
6060
- "retry": "retry";
3756
+ "retry": "retry";
6061
3757
  }, never, never, true, never>;
6062
3758
  }
6063
3759
  export declare class TextInputComponent implements ControlValueAccessor, Validator, UiFieldValidity {
@@ -6074,7 +3770,7 @@ export declare class TextInputComponent implements ControlValueAccessor, Validat
6074
3770
  * `search`, `text`, `none`). Empty (default) = the browser's default for the field, except `type="tel"`, which keeps `tel`.
6075
3771
  * It only picks the keyboard; it does not restrict what can be typed or pasted.
6076
3772
  */
6077
- readonly inputmode: import("@angular/core").InputSignal<"" | "none" | "text" | "email" | "tel" | "search" | "url" | "decimal" | "numeric">;
3773
+ readonly inputmode: import("@angular/core").InputSignal<"" | "none" | "text" | "search" | "email" | "tel" | "url" | "decimal" | "numeric">;
6078
3774
  readonly readonly: import("@angular/core").InputSignal<boolean>;
6079
3775
  readonly hint: import("@angular/core").InputSignal<string>;
6080
3776
  readonly error: import("@angular/core").InputSignal<string>;
@@ -6086,6 +3782,12 @@ export declare class TextInputComponent implements ControlValueAccessor, Validat
6086
3782
  readonly max: import("@angular/core").InputSignal<number | undefined>;
6087
3783
  /** `type="number"` only: most digits allowed after the decimal point. */
6088
3784
  readonly maxDecimals: import("@angular/core").InputSignal<number | undefined>;
3785
+ /**
3786
+ * `type="number"` only: how much the browser's spinner arrows and the Up / Down keys change the value (e.g. `0.01` for money).
3787
+ * Leave it unset for the browser's default step of 1. A value that is not a number above 0 is ignored (also the default step).
3788
+ * It only picks the increment; it does not restrict what can be typed (use `maxDecimals` for that).
3789
+ */
3790
+ readonly step: import("@angular/core").InputSignal<number | undefined>;
6089
3791
  /**
6090
3792
  * What the control value is. `'string'` (default) = the typed text. `'number'` = `number | null`; requires `type="number"`
6091
3793
  * (otherwise a dev-mode warning is logged once and string behaviour is used).
@@ -6104,6 +3806,8 @@ export declare class TextInputComponent implements ControlValueAccessor, Validat
6104
3806
  private readonly _reveal;
6105
3807
  /** True when the control value is a number: `valueType="number"` on a `type="number"` field. */
6106
3808
  private readonly _numeric;
3809
+ /** The native `step` attribute: only for `type="number"` and only for a finite number above 0; otherwise none (the browser's step of 1). */
3810
+ protected readonly _stepAttr: import("@angular/core").Signal<string | null>;
6107
3811
  private _warned;
6108
3812
  private readonly _formatting;
6109
3813
  private readonly _issue;
@@ -6213,6 +3917,11 @@ export declare class TextInputComponent implements ControlValueAccessor, Validat
6213
3917
  "required": false;
6214
3918
  "isSignal": true;
6215
3919
  };
3920
+ "step": {
3921
+ "alias": "step";
3922
+ "required": false;
3923
+ "isSignal": true;
3924
+ };
6216
3925
  "valueType": {
6217
3926
  "alias": "valueType";
6218
3927
  "required": false;
@@ -6251,6 +3960,8 @@ export declare class TextareaInputComponent implements ControlValueAccessor, Val
6251
3960
  */
6252
3961
  readonly hintAsDescription: import("@angular/core").InputSignal<boolean>;
6253
3962
  readonly error: import("@angular/core").InputSignal<string>;
3963
+ /** Opt-in. `true` shows the text in a monospace font (HTML / code / merge-tag fields). Default `false` = unchanged. */
3964
+ readonly monospace: import("@angular/core").InputSignal<boolean>;
6254
3965
  /** Reveal the built-in error messages now (e.g. after a failed Save click), without waiting for blur. */
6255
3966
  readonly showErrors: import("@angular/core").InputSignal<boolean>;
6256
3967
  protected readonly _disabledInput: import("@angular/core").InputSignal<boolean>;
@@ -6341,6 +4052,11 @@ export declare class TextareaInputComponent implements ControlValueAccessor, Val
6341
4052
  "required": false;
6342
4053
  "isSignal": true;
6343
4054
  };
4055
+ "monospace": {
4056
+ "alias": "monospace";
4057
+ "required": false;
4058
+ "isSignal": true;
4059
+ };
6344
4060
  "showErrors": {
6345
4061
  "alias": "showErrors";
6346
4062
  "required": false;
@@ -6762,60 +4478,353 @@ export declare class DateInputComponent implements ControlValueAccessor, Validat
6762
4478
  export declare class DatetimeInputComponent implements ControlValueAccessor, Validator, UiFieldValidity {
6763
4479
  readonly label: import("@angular/core").InputSignal<string>;
6764
4480
  readonly required: import("@angular/core").InputSignal<boolean>;
6765
- readonly min: import("@angular/core").InputSignal<string>;
6766
- readonly max: import("@angular/core").InputSignal<string>;
4481
+ readonly min: import("@angular/core").InputSignal<string>;
4482
+ readonly max: import("@angular/core").InputSignal<string>;
4483
+ readonly hint: import("@angular/core").InputSignal<string>;
4484
+ readonly error: import("@angular/core").InputSignal<string>;
4485
+ /** Reveal the built-in error messages now (e.g. after a failed Save click), without waiting for blur. */
4486
+ readonly showErrors: import("@angular/core").InputSignal<boolean>;
4487
+ protected readonly _disabledInput: import("@angular/core").InputSignal<boolean>;
4488
+ private readonly _cvaDisabled;
4489
+ protected readonly disabled: import("@angular/core").Signal<boolean>;
4490
+ protected readonly _value: import("@angular/core").WritableSignal<string>;
4491
+ private readonly _reveal;
4492
+ private readonly _issue;
4493
+ /** True while the value breaks a built-in rule or the host passed an `[error]`. */
4494
+ readonly invalid: import("@angular/core").Signal<boolean>;
4495
+ /** Message of the first broken built-in rule ('' when valid), shown or not. */
4496
+ readonly errorMessage: import("@angular/core").Signal<string>;
4497
+ /** Emits whenever the field becomes invalid / valid. */
4498
+ readonly invalidChange: import("@angular/core").OutputEmitterRef<boolean>;
4499
+ protected readonly _activeError: import("@angular/core").Signal<string>;
4500
+ private _onValidatorChange;
4501
+ constructor();
4502
+ /** Re-run the form control's validation when a rule input (required, maxlength, min, options, ...) changes. */
4503
+ ngOnChanges(): void;
4504
+ validate(control: AbstractControl): ValidationErrors | null;
4505
+ registerOnValidatorChange(fn: () => void): void;
4506
+ protected readonly _inputId: string;
4507
+ private _onChange;
4508
+ private _onTouched;
4509
+ writeValue(val: string): void;
4510
+ registerOnChange(fn: (v: string) => void): void;
4511
+ registerOnTouched(fn: () => void): void;
4512
+ setDisabledState(d: boolean): void;
4513
+ protected onChange(event: Event): void;
4514
+ protected onBlur(): void;
4515
+ private _check;
4516
+ static ɵfac: i0.ɵɵFactoryDeclaration<DatetimeInputComponent, never>;
4517
+ static ɵcmp: i0.ɵɵComponentDeclaration<DatetimeInputComponent, "ui-datetime-input", never, {
4518
+ "label": {
4519
+ "alias": "label";
4520
+ "required": false;
4521
+ "isSignal": true;
4522
+ };
4523
+ "required": {
4524
+ "alias": "required";
4525
+ "required": false;
4526
+ "isSignal": true;
4527
+ };
4528
+ "min": {
4529
+ "alias": "min";
4530
+ "required": false;
4531
+ "isSignal": true;
4532
+ };
4533
+ "max": {
4534
+ "alias": "max";
4535
+ "required": false;
4536
+ "isSignal": true;
4537
+ };
4538
+ "hint": {
4539
+ "alias": "hint";
4540
+ "required": false;
4541
+ "isSignal": true;
4542
+ };
4543
+ "error": {
4544
+ "alias": "error";
4545
+ "required": false;
4546
+ "isSignal": true;
4547
+ };
4548
+ "showErrors": {
4549
+ "alias": "showErrors";
4550
+ "required": false;
4551
+ "isSignal": true;
4552
+ };
4553
+ "_disabledInput": {
4554
+ "alias": "disabled";
4555
+ "required": false;
4556
+ "isSignal": true;
4557
+ };
4558
+ }, {
4559
+ "invalidChange": "invalidChange";
4560
+ }, never, never, true, never>;
4561
+ }
4562
+ export declare class TimeInputComponent implements ControlValueAccessor, Validator, UiFieldValidity {
4563
+ readonly label: import("@angular/core").InputSignal<string>;
4564
+ /** Accessible name when there is no visible `label` (falls back to `label`). */
4565
+ readonly ariaLabel: import("@angular/core").InputSignal<string>;
4566
+ readonly required: import("@angular/core").InputSignal<boolean>;
4567
+ readonly min: import("@angular/core").InputSignal<string>;
4568
+ readonly max: import("@angular/core").InputSignal<string>;
4569
+ readonly hint: import("@angular/core").InputSignal<string>;
4570
+ readonly error: import("@angular/core").InputSignal<string>;
4571
+ /** Reveal the built-in error messages now (e.g. after a failed Save click), without waiting for blur. */
4572
+ readonly showErrors: import("@angular/core").InputSignal<boolean>;
4573
+ protected readonly _disabledInput: import("@angular/core").InputSignal<boolean>;
4574
+ private readonly _cvaDisabled;
4575
+ protected readonly disabled: import("@angular/core").Signal<boolean>;
4576
+ protected readonly _value: import("@angular/core").WritableSignal<string>;
4577
+ protected readonly _inputId: string;
4578
+ private readonly _reveal;
4579
+ private readonly _issue;
4580
+ /** True while the value breaks a built-in rule or the host passed an `[error]`. */
4581
+ readonly invalid: import("@angular/core").Signal<boolean>;
4582
+ /** Message of the first broken built-in rule ('' when valid), shown or not. */
4583
+ readonly errorMessage: import("@angular/core").Signal<string>;
4584
+ /** Emits whenever the field becomes invalid / valid. */
4585
+ readonly invalidChange: import("@angular/core").OutputEmitterRef<boolean>;
4586
+ protected readonly _activeError: import("@angular/core").Signal<string>;
4587
+ private _onValidatorChange;
4588
+ constructor();
4589
+ /** Re-run the form control's validation when a rule input (required, min, max) changes. */
4590
+ ngOnChanges(): void;
4591
+ validate(control: AbstractControl): ValidationErrors | null;
4592
+ registerOnValidatorChange(fn: () => void): void;
4593
+ private _onChange;
4594
+ private _onTouched;
4595
+ writeValue(val: string): void;
4596
+ registerOnChange(fn: (v: string) => void): void;
4597
+ registerOnTouched(fn: () => void): void;
4598
+ setDisabledState(d: boolean): void;
4599
+ protected onChange(event: Event): void;
4600
+ protected onBlur(): void;
4601
+ private _check;
4602
+ static ɵfac: i0.ɵɵFactoryDeclaration<TimeInputComponent, never>;
4603
+ static ɵcmp: i0.ɵɵComponentDeclaration<TimeInputComponent, "ui-time-input", never, {
4604
+ "label": {
4605
+ "alias": "label";
4606
+ "required": false;
4607
+ "isSignal": true;
4608
+ };
4609
+ "ariaLabel": {
4610
+ "alias": "ariaLabel";
4611
+ "required": false;
4612
+ "isSignal": true;
4613
+ };
4614
+ "required": {
4615
+ "alias": "required";
4616
+ "required": false;
4617
+ "isSignal": true;
4618
+ };
4619
+ "min": {
4620
+ "alias": "min";
4621
+ "required": false;
4622
+ "isSignal": true;
4623
+ };
4624
+ "max": {
4625
+ "alias": "max";
4626
+ "required": false;
4627
+ "isSignal": true;
4628
+ };
4629
+ "hint": {
4630
+ "alias": "hint";
4631
+ "required": false;
4632
+ "isSignal": true;
4633
+ };
4634
+ "error": {
4635
+ "alias": "error";
4636
+ "required": false;
4637
+ "isSignal": true;
4638
+ };
4639
+ "showErrors": {
4640
+ "alias": "showErrors";
4641
+ "required": false;
4642
+ "isSignal": true;
4643
+ };
4644
+ "_disabledInput": {
4645
+ "alias": "disabled";
4646
+ "required": false;
4647
+ "isSignal": true;
4648
+ };
4649
+ }, {
4650
+ "invalidChange": "invalidChange";
4651
+ }, never, never, true, never>;
4652
+ }
4653
+ /** One selectable row. `data` carries any host payload (a typed record, an id, ...) back through `(valueChange)`. */
4654
+ export interface ComboboxOption<T = unknown> {
4655
+ value: string;
4656
+ label: string;
4657
+ /** Secondary line under the label (trade, customer name, ...). */
4658
+ description?: string;
4659
+ disabled?: boolean;
4660
+ data?: T;
4661
+ }
4662
+ /** The selected value: what `[value]` and `ngModel` / `FormControl` hold. */
4663
+ export interface ComboboxSelection {
4664
+ value: string;
4665
+ label: string;
4666
+ }
4667
+ /**
4668
+ * Search-as-you-type single select (WAI-ARIA 1.2 combobox with listbox popup). The HOST fetches: the combobox emits
4669
+ * `(searchChange)` with the typed term (debounced) and renders whatever `[options]` currently is, so a host using
4670
+ * `switchMap` is race-safe and a stale array never "sticks" (the active option is re-validated on every change).
4671
+ *
4672
+ * ## API
4673
+ * - `[options]` `ComboboxOption[]` current results (`{ value, label, description?, disabled?, data? }`).
4674
+ * - `[value]` `{ value, label } | null` the selection. Also what `ngModel` / `formControl` hold (same shape).
4675
+ * - `[displayText]` text shown in the field instead of the selected label — use it for legacy / orphaned links:
4676
+ * `displayText="Not linked: Legacy Co"` (with `[value]="null"`) or `displayText="Acme (no longer exists)"`.
4677
+ * Pair it with `[displayWarning]="true"` for the amber "needs attention" style. A `displayText` with no `value` is
4678
+ * shown and has a clear button, but counts as EMPTY for `required`.
4679
+ * - `[loading]` shows "Searching…" and announces it. `[noResultsText]` (default "No results found").
4680
+ * - `[minChars]` (default 0): below it nothing is searched or listed ("Type at least N characters"). 0 = the list opens
4681
+ * on focus and `(searchChange)` fires with '' so the host can show its initial results.
4682
+ * - `[debounce]` ms between the last keystroke and `(searchChange)` (default 250). Focus / ArrowDown-open emit immediately.
4683
+ * - `[label] [ariaLabel] [placeholder] [required] [hint] [error] [disabled] [showErrors]` like `ui-text-input`
4684
+ * (host `[error]` wins over the built-in "<label> is required."; messages show after blur or `showErrors`).
4685
+ * - `(searchChange)` string, `(valueChange)` `ComboboxOption | null` (the full chosen option, null when cleared),
4686
+ * `(invalidChange)` boolean, `(focused)`, `(blurred)`. Validity: `UiFieldValidity` token + Angular `Validator`.
4687
+ *
4688
+ * ## Behaviour
4689
+ * - The field shows the selected label. Focusing it selects that text; typing starts a NEW search and the old value is
4690
+ * kept until another option is picked or the clear (x) button is pressed. Leaving the field (blur / Tab / Escape)
4691
+ * discards the typed text and shows the selection again.
4692
+ * - Escape: if the list is open it closes the list ONLY (stopPropagation, so a surrounding side panel / modal stays
4693
+ * open). If the list is already closed and text was typed, it discards the text (also stopped). Otherwise the key
4694
+ * passes through to the panel.
4695
+ * - Tab never selects: it closes the list and moves on.
4696
+ *
4697
+ * ## Keyboard
4698
+ * ArrowDown / ArrowUp open the list and move the active option (wraps, skips disabled). Home / End jump to the first /
4699
+ * last option while the list is open. Enter picks the active option (and does not submit a surrounding form while open).
4700
+ * Escape / Tab as above. Typing opens the list. Mouse: options are picked on mousedown so blur does not swallow it.
4701
+ *
4702
+ * ## ARIA
4703
+ * The inner `<input>` is `role="combobox"` with `aria-expanded`, `aria-controls` (the listbox, while open),
4704
+ * `aria-autocomplete="list"`, `aria-activedescendant`, `aria-invalid`, `aria-required`, `aria-describedby` (hint / error);
4705
+ * the `<label for>` names it. The popup is `role="listbox"` of `role="option"` rows (`aria-selected` = active row,
4706
+ * stable ids). A polite `role="status"` region announces "Searching", "N results available" or the no-results text.
4707
+ *
4708
+ * ## Example
4709
+ * ```html
4710
+ * <ui-combobox label="Subcontractor" [required]="true" [options]="opts()" [loading]="loading()"
4711
+ * [value]="sub()" [displayText]="legacyName() ? 'Not linked: ' + legacyName() : ''" [error]="err()"
4712
+ * (searchChange)="search$.next($event)" (valueChange)="onPick($event)" />
4713
+ * ```
4714
+ */
4715
+ export declare class ComboboxComponent<T = unknown> implements ControlValueAccessor, Validator, UiFieldValidity {
4716
+ readonly label: import("@angular/core").InputSignal<string>;
4717
+ /** Accessible name for a field with no visible label. */
4718
+ readonly ariaLabel: import("@angular/core").InputSignal<string>;
4719
+ readonly placeholder: import("@angular/core").InputSignal<string>;
4720
+ readonly required: import("@angular/core").InputSignal<boolean>;
6767
4721
  readonly hint: import("@angular/core").InputSignal<string>;
4722
+ /** Host error message; always wins over the built-in message. */
6768
4723
  readonly error: import("@angular/core").InputSignal<string>;
6769
- /** Reveal the built-in error messages now (e.g. after a failed Save click), without waiting for blur. */
6770
4724
  readonly showErrors: import("@angular/core").InputSignal<boolean>;
4725
+ /** Current results (host-owned). */
4726
+ readonly options: import("@angular/core").InputSignal<ComboboxOption<T>[]>;
4727
+ readonly loading: import("@angular/core").InputSignal<boolean>;
4728
+ readonly noResultsText: import("@angular/core").InputSignal<string>;
4729
+ /** Characters needed before searching / listing. 0 = open on focus. */
4730
+ readonly minChars: import("@angular/core").InputSignal<number>;
4731
+ /** Milliseconds between the last keystroke and `(searchChange)`. */
4732
+ readonly debounce: import("@angular/core").InputSignal<number>;
4733
+ /** The selection. */
4734
+ readonly value: import("@angular/core").InputSignal<ComboboxSelection | null>;
4735
+ /** Text shown instead of the selected label (legacy / orphaned links). */
4736
+ readonly displayText: import("@angular/core").InputSignal<string>;
4737
+ /** Amber style for a legacy / orphaned `displayText`. */
4738
+ readonly displayWarning: import("@angular/core").InputSignal<boolean>;
4739
+ /** Typed term, debounced (immediate on focus / open). */
4740
+ readonly searchChange: import("@angular/core").OutputEmitterRef<string>;
4741
+ /** The chosen option, or null when cleared. */
4742
+ readonly valueChange: import("@angular/core").OutputEmitterRef<ComboboxOption<T> | null>;
4743
+ readonly invalidChange: import("@angular/core").OutputEmitterRef<boolean>;
4744
+ readonly focused: import("@angular/core").OutputEmitterRef<void>;
4745
+ readonly blurred: import("@angular/core").OutputEmitterRef<void>;
6771
4746
  protected readonly _disabledInput: import("@angular/core").InputSignal<boolean>;
6772
4747
  private readonly _cvaDisabled;
6773
4748
  protected readonly disabled: import("@angular/core").Signal<boolean>;
6774
- protected readonly _value: import("@angular/core").WritableSignal<string>;
4749
+ private readonly _field;
4750
+ private readonly _host;
4751
+ private readonly _injector;
4752
+ private readonly _destroyRef;
4753
+ /** Follows `[value]`; ngModel / formControl writes and user picks override it until `[value]` changes. */
4754
+ protected readonly _selected: import("@angular/core").WritableSignal<ComboboxSelection | null>;
4755
+ private readonly _text;
4756
+ private readonly _editing;
4757
+ protected readonly _open: import("@angular/core").WritableSignal<boolean>;
4758
+ /** Reset to the first enabled option whenever `[options]` changes, so a stale index never survives new results. */
4759
+ protected readonly _activeIndex: import("@angular/core").WritableSignal<number>;
4760
+ protected readonly _uid: number;
4761
+ protected readonly _inputId: string;
4762
+ protected readonly _listId: string;
4763
+ protected readonly _descId: string;
6775
4764
  private readonly _reveal;
6776
4765
  private readonly _issue;
6777
- /** True while the value breaks a built-in rule or the host passed an `[error]`. */
6778
4766
  readonly invalid: import("@angular/core").Signal<boolean>;
6779
- /** Message of the first broken built-in rule ('' when valid), shown or not. */
6780
4767
  readonly errorMessage: import("@angular/core").Signal<string>;
6781
- /** Emits whenever the field becomes invalid / valid. */
6782
- readonly invalidChange: import("@angular/core").OutputEmitterRef<boolean>;
6783
4768
  protected readonly _activeError: import("@angular/core").Signal<string>;
4769
+ protected readonly _inputText: import("@angular/core").Signal<string>;
4770
+ protected readonly _showClear: import("@angular/core").Signal<boolean>;
4771
+ protected readonly _belowMin: import("@angular/core").Signal<boolean>;
4772
+ protected readonly _statusText: import("@angular/core").Signal<string>;
4773
+ protected readonly _liveText: import("@angular/core").Signal<string>;
4774
+ protected readonly _activeDescendant: import("@angular/core").Signal<string | null>;
4775
+ private _debounceTimer;
4776
+ private _onChange;
4777
+ private _onTouched;
6784
4778
  private _onValidatorChange;
6785
4779
  constructor();
6786
- /** Re-run the form control's validation when a rule input (required, maxlength, min, options, ...) changes. */
6787
4780
  ngOnChanges(): void;
4781
+ writeValue(val: ComboboxSelection | null): void;
6788
4782
  validate(control: AbstractControl): ValidationErrors | null;
6789
4783
  registerOnValidatorChange(fn: () => void): void;
6790
- protected readonly _inputId: string;
6791
- private _onChange;
6792
- private _onTouched;
6793
- writeValue(val: string): void;
6794
- registerOnChange(fn: (v: string) => void): void;
4784
+ registerOnChange(fn: (v: ComboboxSelection | null) => void): void;
6795
4785
  registerOnTouched(fn: () => void): void;
6796
4786
  setDisabledState(d: boolean): void;
6797
- protected onChange(event: Event): void;
6798
- protected onBlur(): void;
6799
4787
  private _check;
6800
- static ɵfac: i0.ɵɵFactoryDeclaration<DatetimeInputComponent, never>;
6801
- static ɵcmp: i0.ɵɵComponentDeclaration<DatetimeInputComponent, "ui-datetime-input", never, {
4788
+ /** What the user typed (trimmed); '' while not editing. */
4789
+ private _term;
4790
+ protected _optionId(i: number): string;
4791
+ private _firstEnabled;
4792
+ private _emitSearch;
4793
+ private _cancelTimer;
4794
+ private _revert;
4795
+ private _openList;
4796
+ private _move;
4797
+ private _setActive;
4798
+ protected onInput(event: Event): void;
4799
+ protected onFocus(event: FocusEvent): void;
4800
+ protected onClick(): void;
4801
+ protected onBlur(): void;
4802
+ protected onKeydown(e: KeyboardEvent): void;
4803
+ protected onOptionMouseDown(e: MouseEvent, o: ComboboxOption<T>): void;
4804
+ protected onOptionHover(i: number, o: ComboboxOption<T>): void;
4805
+ /** Select `o` (also callable by a host through a template ref). */
4806
+ choose(o: ComboboxOption<T>): void;
4807
+ /** Clear the selection (the x button). */
4808
+ clear(): void;
4809
+ static ɵfac: i0.ɵɵFactoryDeclaration<ComboboxComponent<any>, never>;
4810
+ static ɵcmp: i0.ɵɵComponentDeclaration<ComboboxComponent<any>, "ui-combobox", never, {
6802
4811
  "label": {
6803
4812
  "alias": "label";
6804
4813
  "required": false;
6805
4814
  "isSignal": true;
6806
4815
  };
6807
- "required": {
6808
- "alias": "required";
4816
+ "ariaLabel": {
4817
+ "alias": "ariaLabel";
6809
4818
  "required": false;
6810
4819
  "isSignal": true;
6811
4820
  };
6812
- "min": {
6813
- "alias": "min";
4821
+ "placeholder": {
4822
+ "alias": "placeholder";
6814
4823
  "required": false;
6815
4824
  "isSignal": true;
6816
4825
  };
6817
- "max": {
6818
- "alias": "max";
4826
+ "required": {
4827
+ "alias": "required";
6819
4828
  "required": false;
6820
4829
  "isSignal": true;
6821
4830
  };
@@ -6834,94 +4843,43 @@ export declare class DatetimeInputComponent implements ControlValueAccessor, Val
6834
4843
  "required": false;
6835
4844
  "isSignal": true;
6836
4845
  };
6837
- "_disabledInput": {
6838
- "alias": "disabled";
6839
- "required": false;
6840
- "isSignal": true;
6841
- };
6842
- }, {
6843
- "invalidChange": "invalidChange";
6844
- }, never, never, true, never>;
6845
- }
6846
- export declare class TimeInputComponent implements ControlValueAccessor, Validator, UiFieldValidity {
6847
- readonly label: import("@angular/core").InputSignal<string>;
6848
- /** Accessible name when there is no visible `label` (falls back to `label`). */
6849
- readonly ariaLabel: import("@angular/core").InputSignal<string>;
6850
- readonly required: import("@angular/core").InputSignal<boolean>;
6851
- readonly min: import("@angular/core").InputSignal<string>;
6852
- readonly max: import("@angular/core").InputSignal<string>;
6853
- readonly hint: import("@angular/core").InputSignal<string>;
6854
- readonly error: import("@angular/core").InputSignal<string>;
6855
- /** Reveal the built-in error messages now (e.g. after a failed Save click), without waiting for blur. */
6856
- readonly showErrors: import("@angular/core").InputSignal<boolean>;
6857
- protected readonly _disabledInput: import("@angular/core").InputSignal<boolean>;
6858
- private readonly _cvaDisabled;
6859
- protected readonly disabled: import("@angular/core").Signal<boolean>;
6860
- protected readonly _value: import("@angular/core").WritableSignal<string>;
6861
- protected readonly _inputId: string;
6862
- private readonly _reveal;
6863
- private readonly _issue;
6864
- /** True while the value breaks a built-in rule or the host passed an `[error]`. */
6865
- readonly invalid: import("@angular/core").Signal<boolean>;
6866
- /** Message of the first broken built-in rule ('' when valid), shown or not. */
6867
- readonly errorMessage: import("@angular/core").Signal<string>;
6868
- /** Emits whenever the field becomes invalid / valid. */
6869
- readonly invalidChange: import("@angular/core").OutputEmitterRef<boolean>;
6870
- protected readonly _activeError: import("@angular/core").Signal<string>;
6871
- private _onValidatorChange;
6872
- constructor();
6873
- /** Re-run the form control's validation when a rule input (required, min, max) changes. */
6874
- ngOnChanges(): void;
6875
- validate(control: AbstractControl): ValidationErrors | null;
6876
- registerOnValidatorChange(fn: () => void): void;
6877
- private _onChange;
6878
- private _onTouched;
6879
- writeValue(val: string): void;
6880
- registerOnChange(fn: (v: string) => void): void;
6881
- registerOnTouched(fn: () => void): void;
6882
- setDisabledState(d: boolean): void;
6883
- protected onChange(event: Event): void;
6884
- protected onBlur(): void;
6885
- private _check;
6886
- static ɵfac: i0.ɵɵFactoryDeclaration<TimeInputComponent, never>;
6887
- static ɵcmp: i0.ɵɵComponentDeclaration<TimeInputComponent, "ui-time-input", never, {
6888
- "label": {
6889
- "alias": "label";
4846
+ "options": {
4847
+ "alias": "options";
6890
4848
  "required": false;
6891
4849
  "isSignal": true;
6892
4850
  };
6893
- "ariaLabel": {
6894
- "alias": "ariaLabel";
4851
+ "loading": {
4852
+ "alias": "loading";
6895
4853
  "required": false;
6896
4854
  "isSignal": true;
6897
4855
  };
6898
- "required": {
6899
- "alias": "required";
4856
+ "noResultsText": {
4857
+ "alias": "noResultsText";
6900
4858
  "required": false;
6901
4859
  "isSignal": true;
6902
4860
  };
6903
- "min": {
6904
- "alias": "min";
4861
+ "minChars": {
4862
+ "alias": "minChars";
6905
4863
  "required": false;
6906
4864
  "isSignal": true;
6907
4865
  };
6908
- "max": {
6909
- "alias": "max";
4866
+ "debounce": {
4867
+ "alias": "debounce";
6910
4868
  "required": false;
6911
4869
  "isSignal": true;
6912
4870
  };
6913
- "hint": {
6914
- "alias": "hint";
4871
+ "value": {
4872
+ "alias": "value";
6915
4873
  "required": false;
6916
4874
  "isSignal": true;
6917
4875
  };
6918
- "error": {
6919
- "alias": "error";
4876
+ "displayText": {
4877
+ "alias": "displayText";
6920
4878
  "required": false;
6921
4879
  "isSignal": true;
6922
4880
  };
6923
- "showErrors": {
6924
- "alias": "showErrors";
4881
+ "displayWarning": {
4882
+ "alias": "displayWarning";
6925
4883
  "required": false;
6926
4884
  "isSignal": true;
6927
4885
  };
@@ -6931,7 +4889,11 @@ export declare class TimeInputComponent implements ControlValueAccessor, Validat
6931
4889
  "isSignal": true;
6932
4890
  };
6933
4891
  }, {
4892
+ "searchChange": "searchChange";
4893
+ "valueChange": "valueChange";
6934
4894
  "invalidChange": "invalidChange";
4895
+ "focused": "focused";
4896
+ "blurred": "blurred";
6935
4897
  }, never, never, true, never>;
6936
4898
  }
6937
4899
  /**
@@ -7211,7 +5173,7 @@ export declare class FormSectionComponent {
7211
5173
  }, {}, never, ["*"], true, never>;
7212
5174
  }
7213
5175
  export declare class FormRowComponent {
7214
- readonly cols: import("@angular/core").InputSignal<2 | 1 | 3>;
5176
+ readonly cols: import("@angular/core").InputSignal<1 | 2 | 3>;
7215
5177
  static ɵfac: i0.ɵɵFactoryDeclaration<FormRowComponent, never>;
7216
5178
  static ɵcmp: i0.ɵɵComponentDeclaration<FormRowComponent, "ui-form-row", never, {
7217
5179
  "cols": {
@@ -8405,7 +6367,8 @@ export declare class ErrorComponent {
8405
6367
  }, {}, never, never, true, never>;
8406
6368
  }
8407
6369
  export type KpiCardColor = 'green' | 'blue' | 'amber' | 'orange' | 'red' | 'slate';
8408
- export type KpiCardValueColor = 'default' | 'green' | 'blue';
6370
+ /** Colour of the big value: `default` (dark slate), `green`, `blue`, or `red` (for figures that need attention: overdue, outstanding, failed). */
6371
+ export type KpiCardValueColor = 'default' | 'green' | 'blue' | 'red';
8409
6372
  /**
8410
6373
  * Compact KPI summary card: optional icon, uppercase label, large value, optional subtitle.
8411
6374
  * Set `clickable` to show a hover state + chevron (bind `(click)` on the host). A clickable card is a keyboard button:
@@ -8537,167 +6500,6 @@ export declare class KpiCardComponent {
8537
6500
  };
8538
6501
  }, {}, never, ["[kpi-footer]"], true, never>;
8539
6502
  }
8540
- interface StateView {
8541
- id: string;
8542
- name: string;
8543
- path: string;
8544
- value: number;
8545
- /** "12 pickups" (or just "12"). */
8546
- valueText: string;
8547
- /** "Texas, 12 pickups": the accessible name, the tooltip text and the hidden-list entry. */
8548
- label: string;
8549
- fill: string;
8550
- }
8551
- /**
8552
- * US choropleth map: the 50 states plus Washington, DC, each coloured from `colorLow` (value 0) to `colorHigh` (the largest
8553
- * value) by its number in `data`.
8554
- *
8555
- * Interaction and accessibility
8556
- * - Every state is a button (`role="button"`, name "Texas, 12 pickups", `aria-pressed` for the selected one). The group has a
8557
- * single tab stop (roving tabindex: last focused state, else the selected one, else Alabama); arrow keys,
8558
- * Home and End move between states in alphabetical order, Enter / Space emit `stateClick` with the abbreviation.
8559
- * - The tooltip (state name + value) shows on hover AND on keyboard focus; it is real text, `aria-hidden` because the
8560
- * state's accessible name already says the same. Colour is never the only signal: values are in names, tooltip and the
8561
- * visually hidden list of all states.
8562
- * - A selected state gets an orange outline and the others are dimmed; the focus ring is drawn as an overlay outline
8563
- * (works the same in Chrome, Edge, Firefox and Safari) and only for keyboard focus.
8564
- * - `prefers-reduced-motion` turns the transitions off. Strokes use `vector-effect: non-scaling-stroke`, so outlines keep
8565
- * their pixel width when `focusState` zooms in.
8566
- *
8567
- * Known limitation: the very small states (CT, DC, DE, HI, MA, MD, NH, NJ, RI, VT) are tiny touch targets on a phone. They
8568
- * are reachable by keyboard and screen reader like any other; set `showSmallStateButtons` for a row of 44px buttons for them.
8569
- * Territories are not on the map.
8570
- */
8571
- export declare class UsStateMapComponent {
8572
- /** State abbreviation -> value. Keys are case-insensitive; unknown keys are ignored; numbers and numeric strings (`'5'`) are read as numbers, anything else (negative, NaN, Infinity, text, booleans, null) counts as 0; repeated keys (`tx` and `TX`) are added up. */
8573
- readonly data: import("@angular/core").InputSignal<Record<string, number>>;
8574
- /** Abbreviation of the selected state (orange outline, the others are dimmed). Unknown / null = none. */
8575
- readonly selectedState: import("@angular/core").InputSignal<string | null>;
8576
- /** Abbreviation of a state to zoom the map to (bounding box plus 15% padding). Unknown / null = the whole map. */
8577
- readonly focusState: import("@angular/core").InputSignal<string | null>;
8578
- /** Unit for one, e.g. "pickup": "Texas, 1 pickup". Empty = just the number. */
8579
- readonly unitSingular: import("@angular/core").InputSignal<string>;
8580
- /** Unit for other counts, e.g. "pickups". Empty = the singular text is used for every count. */
8581
- readonly unitPlural: import("@angular/core").InputSignal<string>;
8582
- /** Colour of a value of 0 (CSS hex or rgb()). Invalid values fall back to #e5e7eb. */
8583
- readonly colorLow: import("@angular/core").InputSignal<string>;
8584
- /** Colour of the largest value (CSS hex or rgb()). Invalid values fall back to #1e40af. */
8585
- readonly colorHigh: import("@angular/core").InputSignal<string>;
8586
- /** Shows the colour scale (0 to the largest value). */
8587
- readonly showLegend: import("@angular/core").InputSignal<boolean>;
8588
- /** Shows a row of buttons for the very small states (touch friendly, 44px). Off by default. */
8589
- readonly showSmallStateButtons: import("@angular/core").InputSignal<boolean>;
8590
- /** Accessible name of the whole map. */
8591
- readonly ariaLabel: import("@angular/core").InputSignal<string>;
8592
- /** CSS maximum width of the map (it always shrinks to its container). */
8593
- readonly maxWidth: import("@angular/core").InputSignal<string>;
8594
- /** Optional CSS height of the map, e.g. "420px". Empty = follows the width (aspect ratio of the map). */
8595
- readonly height: import("@angular/core").InputSignal<string>;
8596
- /** Emits the state's abbreviation (upper case) on click, tap, Enter or Space. */
8597
- readonly stateClick: import("@angular/core").OutputEmitterRef<string>;
8598
- private readonly host;
8599
- /** True between a pointer press and the click that follows: a mouse / touch focus must not draw the keyboard ring. */
8600
- protected pointerDown: boolean;
8601
- private readonly hoveredId;
8602
- private readonly focusedId;
8603
- private readonly lastFocusedId;
8604
- private readonly ringVisible;
8605
- protected readonly tipPos: import("@angular/core").WritableSignal<{
8606
- x: number;
8607
- y: number;
8608
- } | null>;
8609
- private readonly low;
8610
- private readonly high;
8611
- private readonly values;
8612
- private readonly max;
8613
- private unit;
8614
- private valueText;
8615
- protected readonly views: import("@angular/core").Signal<StateView[]>;
8616
- protected readonly smallViews: import("@angular/core").Signal<StateView[]>;
8617
- protected readonly selectedId: import("@angular/core").Signal<string | null>;
8618
- protected readonly selectedView: import("@angular/core").Signal<StateView | null>;
8619
- protected readonly focusRingView: import("@angular/core").Signal<StateView | null>;
8620
- protected readonly viewBox: import("@angular/core").Signal<string>;
8621
- /** The one state in the tab order: last focused, else selected, else the first. */
8622
- protected readonly tabStop: import("@angular/core").Signal<string>;
8623
- protected readonly tip: import("@angular/core").Signal<StateView | null>;
8624
- protected readonly gradient: import("@angular/core").Signal<string>;
8625
- protected readonly maxText: import("@angular/core").Signal<string>;
8626
- protected readonly legendLabel: import("@angular/core").Signal<string>;
8627
- protected opacityOf(id: string): string | null;
8628
- protected onHover(ev: PointerEvent, id: string): void;
8629
- protected onLeave(id: string): void;
8630
- protected clearHover(): void;
8631
- protected onClick(id: string): void;
8632
- protected onFocus(id: string): void;
8633
- protected onBlur(id: string): void;
8634
- protected onKey(ev: KeyboardEvent, id: string): void;
8635
- static ɵfac: i0.ɵɵFactoryDeclaration<UsStateMapComponent, never>;
8636
- static ɵcmp: i0.ɵɵComponentDeclaration<UsStateMapComponent, "ui-us-state-map", never, {
8637
- "data": {
8638
- "alias": "data";
8639
- "required": false;
8640
- "isSignal": true;
8641
- };
8642
- "selectedState": {
8643
- "alias": "selectedState";
8644
- "required": false;
8645
- "isSignal": true;
8646
- };
8647
- "focusState": {
8648
- "alias": "focusState";
8649
- "required": false;
8650
- "isSignal": true;
8651
- };
8652
- "unitSingular": {
8653
- "alias": "unitSingular";
8654
- "required": false;
8655
- "isSignal": true;
8656
- };
8657
- "unitPlural": {
8658
- "alias": "unitPlural";
8659
- "required": false;
8660
- "isSignal": true;
8661
- };
8662
- "colorLow": {
8663
- "alias": "colorLow";
8664
- "required": false;
8665
- "isSignal": true;
8666
- };
8667
- "colorHigh": {
8668
- "alias": "colorHigh";
8669
- "required": false;
8670
- "isSignal": true;
8671
- };
8672
- "showLegend": {
8673
- "alias": "showLegend";
8674
- "required": false;
8675
- "isSignal": true;
8676
- };
8677
- "showSmallStateButtons": {
8678
- "alias": "showSmallStateButtons";
8679
- "required": false;
8680
- "isSignal": true;
8681
- };
8682
- "ariaLabel": {
8683
- "alias": "ariaLabel";
8684
- "required": false;
8685
- "isSignal": true;
8686
- };
8687
- "maxWidth": {
8688
- "alias": "maxWidth";
8689
- "required": false;
8690
- "isSignal": true;
8691
- };
8692
- "height": {
8693
- "alias": "height";
8694
- "required": false;
8695
- "isSignal": true;
8696
- };
8697
- }, {
8698
- "stateClick": "stateClick";
8699
- }, never, never, true, never>;
8700
- }
8701
6503
  export type DatePreset = 'today' | '7days' | '30days' | 'month' | 'quarter' | 'ytd' | 'all' | 'custom';
8702
6504
  export interface DateRange {
8703
6505
  preset: DatePreset;
@@ -9162,7 +6964,7 @@ export declare class DetailCardComponent {
9162
6964
  /** Bold uppercase title. Empty = no title text. */
9163
6965
  readonly title: import("@angular/core").InputSignal<string>;
9164
6966
  /** 1-6 makes the title a real heading for screen readers (role=heading, aria-level); null keeps it plain text. */
9165
- readonly headingLevel: import("@angular/core").InputSignal<2 | 1 | 5 | 3 | 6 | 4 | null>;
6967
+ readonly headingLevel: import("@angular/core").InputSignal<1 | 2 | 3 | 4 | 5 | 6 | null>;
9166
6968
  /** Optional id for the title text; the card is then labelled by it. Without it the title is the card's aria-label. */
9167
6969
  readonly titleId: import("@angular/core").InputSignal<string>;
9168
6970
  /** Accessible name of the card when the header gives none (no header, or no title). A visible title wins; blank = no name. */
@@ -9844,5 +7646,4 @@ export declare class ActionBarComponent {
9844
7646
  "isSignal": true;
9845
7647
  };
9846
7648
  }, {}, never, ["*"], true, never>;
9847
- }
9848
- export type { CreateDocumentRequestBody, DocuSignSendBody, DocumentSentInfo, DocumentSentMessage, DocumentsPayloadExtras, ExistingEnvelopeSendBody, SendDocumentsPayload, SendEmailPayload, SendTextPayload, VideoDefaults, VideoLinkOptions };
7649
+ }