@forgeroute/ui 0.4.2 → 0.4.4

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,9 +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
3
  import { UrlTree } from "@angular/router";
4
4
  import { AbstractControl, ControlValueAccessor, FormControl, ValidationErrors, Validator } from "@angular/forms";
5
- import { Observable, Subject } from "rxjs";
6
- import { HttpClient, HttpInterceptorFn } from "@angular/common/http";
5
+ import { Observable } from "rxjs";
6
+ import { HttpInterceptorFn } from "@angular/common/http";
7
7
  import { SafeHtml } from "@angular/platform-browser";
8
8
  export interface ForgerouteConfig {
9
9
  baseUrl: string;
@@ -3439,9 +3439,9 @@ export interface ContactLookup {
3439
3439
  email: string | null;
3440
3440
  smsOptedIn: boolean;
3441
3441
  }
3442
- declare function formatPhone$1(raw: string | null | undefined): string;
3442
+ declare function formatPhone(raw: string | null | undefined): string;
3443
3443
  export declare class ContactPickerComponent {
3444
- readonly formatPhone: typeof formatPhone$1;
3444
+ readonly formatPhone: typeof formatPhone;
3445
3445
  readonly label: import("@angular/core").InputSignal<string>;
3446
3446
  readonly placeholder: import("@angular/core").InputSignal<string>;
3447
3447
  /** Helper text under the picker (linked to the search input via aria-describedby). */
@@ -3558,2450 +3558,45 @@ export declare class ContactPickerComponent {
3558
3558
  "required": false;
3559
3559
  "isSignal": true;
3560
3560
  };
3561
- "errorId": {
3562
- "alias": "errorId";
3563
- "required": false;
3564
- "isSignal": true;
3565
- };
3566
- "invalid": {
3567
- "alias": "invalid";
3568
- "required": false;
3569
- "isSignal": true;
3570
- };
3571
- "showErrors": {
3572
- "alias": "showErrors";
3573
- "required": false;
3574
- "isSignal": true;
3575
- };
3576
- "showDetails": {
3577
- "alias": "showDetails";
3578
- "required": false;
3579
- "isSignal": true;
3580
- };
3581
- "isMultiSelect": {
3582
- "alias": "isMultiSelect";
3583
- "required": false;
3584
- "isSignal": true;
3585
- };
3586
- "showChips": {
3587
- "alias": "showChips";
3588
- "required": false;
3589
- "isSignal": true;
3590
- };
3591
- "initialContact": {
3592
- "alias": "initialContact";
3593
- "required": false;
3594
- "isSignal": true;
3595
- };
3596
- }, {
3597
- "contactSelected": "contactSelected";
3598
- "contactsSelected": "contactsSelected";
3599
- "invalidChange": "invalidChange";
3600
- }, never, never, true, never>;
3601
- }
3602
- export interface VideoMessage {
3603
- id: string;
3604
- title: string;
3605
- category: string;
3606
- shareLink: string | null;
3607
- }
3608
- export declare class VideoPickerComponent implements UiFieldValidity {
3609
- readonly videoSelected: import("@angular/core").OutputEmitterRef<VideoMessage>;
3610
- /** Optional visible label (names the search field and the selected-video group). Without it the field is named "Search videos". */
3611
- readonly label: import("@angular/core").InputSignal<string>;
3612
- /** Shows the red required marker; the picker is then invalid until a video is picked. */
3613
- readonly required: import("@angular/core").InputSignal<boolean>;
3614
- /** Reveal the built-in "<label> is required." message now (e.g. after a failed Save click); otherwise it shows after the field was blurred. */
3615
- readonly showErrors: import("@angular/core").InputSignal<boolean>;
3616
- /** Emits whenever `invalid` flips. */
3617
- readonly invalidChange: import("@angular/core").OutputEmitterRef<boolean>;
3618
- private readonly http;
3619
- private readonly destroyRef;
3620
- private readonly host;
3621
- private readonly injector;
3622
- /** API root from FORGEROUTE_CONFIG (e.g. a cross-origin prod API); falls back to same-origin `/api`. */
3623
- private readonly apiBase;
3624
- private readonly uid;
3625
- readonly inputId: string;
3626
- readonly labelId: string;
3627
- readonly listboxId: string;
3628
- readonly errorId: string;
3629
- optionId(i: number): string;
3630
- query: string;
3631
- readonly selected: import("@angular/core").WritableSignal<VideoMessage | null>;
3632
- readonly results: import("@angular/core").WritableSignal<VideoMessage[]>;
3633
- readonly loading: import("@angular/core").WritableSignal<boolean>;
3634
- readonly showResults: import("@angular/core").WritableSignal<boolean>;
3635
- /** True from the first keystroke of a >=2-char query until its results arrive (covers the debounce). */
3636
- readonly pending: import("@angular/core").WritableSignal<boolean>;
3637
- /** Index of the keyboard-highlighted option; -1 = none (aria-activedescendant unset). */
3638
- readonly activeIndex: import("@angular/core").WritableSignal<number>;
3639
- private readonly reveal;
3640
- /** `UiFieldValidity`: true while `required` and no video is picked. */
3641
- readonly invalid: import("@angular/core").Signal<boolean>;
3642
- /** "<label> is required." while invalid ('' otherwise), shown or not. */
3643
- readonly errorMessage: import("@angular/core").Signal<string>;
3644
- /** `errorMessage` once the field was blurred or `showErrors` is set. */
3645
- readonly visibleError: import("@angular/core").Signal<string>;
3646
- readonly activeDescendant: import("@angular/core").Signal<string | null>;
3647
- /** Polite announcement for screen readers: searching, the result count, or no results (only while the list is open). */
3648
- readonly liveText: import("@angular/core").Signal<string>;
3649
- private readonly search$;
3650
- private blurTimer;
3651
- private lastMouseActivation;
3652
- constructor();
3653
- onInput(): void;
3654
- onFocus(): void;
3655
- /** Delayed so a click on an option still lands; cancelled if focus returns (or the user types) first. */
3656
- onBlur(): void;
3657
- private clearBlurTimer;
3658
- /**
3659
- * ARIA combobox keys: ArrowDown/ArrowUp open the list and move the highlight (wrapping), Home/End jump to the first /
3660
- * last option, Enter picks the highlighted option, Escape closes the list only (so a surrounding side panel / modal
3661
- * stays open; with the list closed it passes through). Tab selects nothing.
3662
- */
3663
- onKeydown(e: KeyboardEvent): void;
3664
- private setActive;
3665
- onOptionMouseDown(): void;
3666
- /** Activation by assistive tech / a virtual cursor arrives as a click without a preceding mousedown. */
3667
- onOptionClick(v: VideoMessage): void;
3668
- select(v: VideoMessage): void;
3669
- clear(): void;
3670
- private focusAfterRender;
3671
- static ɵfac: i0.ɵɵFactoryDeclaration<VideoPickerComponent, never>;
3672
- static ɵcmp: i0.ɵɵComponentDeclaration<VideoPickerComponent, "ui-video-picker", never, {
3673
- "label": {
3674
- "alias": "label";
3675
- "required": false;
3676
- "isSignal": true;
3677
- };
3678
- "required": {
3679
- "alias": "required";
3680
- "required": false;
3681
- "isSignal": true;
3682
- };
3683
- "showErrors": {
3684
- "alias": "showErrors";
3685
- "required": false;
3686
- "isSignal": true;
3687
- };
3688
- }, {
3689
- "videoSelected": "videoSelected";
3690
- "invalidChange": "invalidChange";
3691
- }, never, never, true, never>;
3692
- }
3693
- export interface TemplateItem {
3694
- id: string;
3695
- name: string;
3696
- subject: string | null;
3697
- body: string;
3698
- isActive?: boolean;
3699
- /** 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. */
3700
- isSystem?: boolean;
3701
- activeFrom?: string | null;
3702
- activeTo?: string | null;
3703
- useAllYear?: boolean;
3704
- }
3705
- export declare class TemplatePickerComponent {
3706
- private readonly http;
3707
- /** API root from FORGEROUTE_CONFIG (e.g. a cross-origin prod API); falls back to same-origin `/api`. */
3708
- private readonly apiBase;
3709
- private readonly destroyRef;
3710
- private readonly toast;
3711
- private readonly host;
3712
- private readonly search$;
3713
- /** Filter results to a specific channel: 'email', 'text', or omit for all. */
3714
- readonly channel: import("@angular/core").InputSignal<"" | "text" | "email">;
3715
- readonly selectedId: import("@angular/core").InputSignal<string | null>;
3716
- readonly label: import("@angular/core").InputSignal<string>;
3717
- /** Shows the red required asterisk (same as the library inputs) — e.g. when a template must be picked to send. */
3718
- readonly required: import("@angular/core").InputSignal<boolean>;
3719
- /** Reveal the built-in "<label> is required." message now (e.g. after a failed Send click); otherwise it shows after the field was blurred. */
3720
- readonly showErrors: import("@angular/core").InputSignal<boolean>;
3721
- readonly templateSelected: import("@angular/core").OutputEmitterRef<TemplateItem>;
3722
- readonly previewClick: import("@angular/core").OutputEmitterRef<{
3723
- subject: string;
3724
- body: string;
3725
- }>;
3726
- /** Emits whenever `invalid` flips (required and no template picked). */
3727
- readonly invalidChange: import("@angular/core").OutputEmitterRef<boolean>;
3728
- readonly search: import("@angular/core").WritableSignal<string>;
3729
- readonly results: import("@angular/core").WritableSignal<TemplateItem[]>;
3730
- readonly loading: import("@angular/core").WritableSignal<boolean>;
3731
- /** Dropdown open state — like ui-contact-picker: open while focused with 2+ characters typed. */
3732
- readonly showResults: import("@angular/core").WritableSignal<boolean>;
3733
- /** Keyboard-highlighted option index (-1 = none). */
3734
- readonly activeIndex: import("@angular/core").WritableSignal<number>;
3735
- /** The picked template id: follows `[selectedId]`; a pick made in the picker overrides it until the host changes `[selectedId]`. */
3736
- private readonly picked;
3737
- private readonly reveal;
3738
- /** `UiFieldValidity`: true while `required` and no template is picked. */
3739
- readonly invalid: import("@angular/core").Signal<boolean>;
3740
- /** "<label> is required." while invalid ('' otherwise), shown or not. */
3741
- readonly errorMessage: import("@angular/core").Signal<string>;
3742
- /** `errorMessage` once the field was blurred or `showErrors` is set. */
3743
- readonly visibleError: import("@angular/core").Signal<string>;
3744
- /** Polite announcement for screen readers: searching, the result count, or no results (only while the list is open). */
3745
- readonly liveText: import("@angular/core").Signal<string>;
3746
- private static nextId;
3747
- private readonly uid;
3748
- readonly inputId: string;
3749
- readonly listId: string;
3750
- readonly errorId: string;
3751
- optionId(i: number): string;
3752
- private blurTimer;
3753
- constructor();
3754
- onInput(q: string): void;
3755
- onFocus(): void;
3756
- onBlur(): void;
3757
- private clearBlurTimer;
3758
- /**
3759
- * ARIA combobox keys: ArrowDown/ArrowUp open the list and move the highlight (wrapping), Home/End jump to the first /
3760
- * last option, Enter picks the highlighted option, Escape closes the list only (so a surrounding side panel / modal
3761
- * stays open; with the list closed it passes through). Tab selects nothing.
3762
- */
3763
- onKeydown(e: KeyboardEvent): void;
3764
- /** Highlights option `i` and scrolls it into view inside the dropdown. */
3765
- private setActive;
3766
- /** Timestamps of the last mousedown activation: the click that follows it is the same gesture, not a second action. */
3767
- private lastOptionMouse;
3768
- private lastPreviewMouse;
3769
- onOptionMouseDown(): void;
3770
- /** Activation by assistive tech / a virtual cursor arrives as a click without a preceding mousedown. */
3771
- onOptionClick(tpl: TemplateItem): void;
3772
- onPreviewMouseDown(tpl: TemplateItem): void;
3773
- onPreviewClick(tpl: TemplateItem): void;
3774
- select(tpl: TemplateItem): void;
3775
- preview(tpl: TemplateItem): void;
3776
- private readonly sampleVars;
3777
- previewText(raw: string): string;
3778
- isCurrentlyActive(tpl: TemplateItem): boolean;
3779
- activeDateLabel(tpl: TemplateItem): string;
3780
- static ɵfac: i0.ɵɵFactoryDeclaration<TemplatePickerComponent, never>;
3781
- static ɵcmp: i0.ɵɵComponentDeclaration<TemplatePickerComponent, "ui-template-picker", never, {
3782
- "channel": {
3783
- "alias": "channel";
3784
- "required": false;
3785
- "isSignal": true;
3786
- };
3787
- "selectedId": {
3788
- "alias": "selectedId";
3789
- "required": false;
3790
- "isSignal": true;
3791
- };
3792
- "label": {
3793
- "alias": "label";
3794
- "required": false;
3795
- "isSignal": true;
3796
- };
3797
- "required": {
3798
- "alias": "required";
3799
- "required": false;
3800
- "isSignal": true;
3801
- };
3802
- "showErrors": {
3803
- "alias": "showErrors";
3804
- "required": false;
3805
- "isSignal": true;
3806
- };
3807
- }, {
3808
- "templateSelected": "templateSelected";
3809
- "previewClick": "previewClick";
3810
- "invalidChange": "invalidChange";
3811
- }, never, never, true, never>;
3812
- }
3813
- /** One selectable row. `data` carries any host payload (a typed record, an id, ...) back through `(valueChange)`. */
3814
- export interface ComboboxOption<T = unknown> {
3815
- value: string;
3816
- label: string;
3817
- /** Secondary line under the label (trade, customer name, ...). */
3818
- description?: string;
3819
- disabled?: boolean;
3820
- data?: T;
3821
- }
3822
- /** The selected value: what `[value]` and `ngModel` / `FormControl` hold. */
3823
- export interface ComboboxSelection {
3824
- value: string;
3825
- label: string;
3826
- }
3827
- /**
3828
- * Search-as-you-type single select (WAI-ARIA 1.2 combobox with listbox popup). The HOST fetches: the combobox emits
3829
- * `(searchChange)` with the typed term (debounced) and renders whatever `[options]` currently is, so a host using
3830
- * `switchMap` is race-safe and a stale array never "sticks" (the active option is re-validated on every change).
3831
- *
3832
- * ## API
3833
- * - `[options]` `ComboboxOption[]` current results (`{ value, label, description?, disabled?, data? }`).
3834
- * - `[value]` `{ value, label } | null` the selection. Also what `ngModel` / `formControl` hold (same shape).
3835
- * - `[displayText]` text shown in the field instead of the selected label — use it for legacy / orphaned links:
3836
- * `displayText="Not linked: Legacy Co"` (with `[value]="null"`) or `displayText="Acme (no longer exists)"`.
3837
- * Pair it with `[displayWarning]="true"` for the amber "needs attention" style. A `displayText` with no `value` is
3838
- * shown and has a clear button, but counts as EMPTY for `required`.
3839
- * - `[loading]` shows "Searching…" and announces it. `[noResultsText]` (default "No results found").
3840
- * - `[minChars]` (default 0): below it nothing is searched or listed ("Type at least N characters"). 0 = the list opens
3841
- * on focus and `(searchChange)` fires with '' so the host can show its initial results.
3842
- * - `[debounce]` ms between the last keystroke and `(searchChange)` (default 250). Focus / ArrowDown-open emit immediately.
3843
- * - `[label] [ariaLabel] [placeholder] [required] [hint] [error] [disabled] [showErrors]` like `ui-text-input`
3844
- * (host `[error]` wins over the built-in "<label> is required."; messages show after blur or `showErrors`).
3845
- * - `(searchChange)` string, `(valueChange)` `ComboboxOption | null` (the full chosen option, null when cleared),
3846
- * `(invalidChange)` boolean, `(focused)`, `(blurred)`. Validity: `UiFieldValidity` token + Angular `Validator`.
3847
- *
3848
- * ## Behaviour
3849
- * - The field shows the selected label. Focusing it selects that text; typing starts a NEW search and the old value is
3850
- * kept until another option is picked or the clear (x) button is pressed. Leaving the field (blur / Tab / Escape)
3851
- * discards the typed text and shows the selection again.
3852
- * - Escape: if the list is open it closes the list ONLY (stopPropagation, so a surrounding side panel / modal stays
3853
- * open). If the list is already closed and text was typed, it discards the text (also stopped). Otherwise the key
3854
- * passes through to the panel.
3855
- * - Tab never selects: it closes the list and moves on.
3856
- *
3857
- * ## Keyboard
3858
- * ArrowDown / ArrowUp open the list and move the active option (wraps, skips disabled). Home / End jump to the first /
3859
- * last option while the list is open. Enter picks the active option (and does not submit a surrounding form while open).
3860
- * Escape / Tab as above. Typing opens the list. Mouse: options are picked on mousedown so blur does not swallow it.
3861
- *
3862
- * ## ARIA
3863
- * The inner `<input>` is `role="combobox"` with `aria-expanded`, `aria-controls` (the listbox, while open),
3864
- * `aria-autocomplete="list"`, `aria-activedescendant`, `aria-invalid`, `aria-required`, `aria-describedby` (hint / error);
3865
- * the `<label for>` names it. The popup is `role="listbox"` of `role="option"` rows (`aria-selected` = active row,
3866
- * stable ids). A polite `role="status"` region announces "Searching", "N results available" or the no-results text.
3867
- *
3868
- * ## Example
3869
- * ```html
3870
- * <ui-combobox label="Subcontractor" [required]="true" [options]="opts()" [loading]="loading()"
3871
- * [value]="sub()" [displayText]="legacyName() ? 'Not linked: ' + legacyName() : ''" [error]="err()"
3872
- * (searchChange)="search$.next($event)" (valueChange)="onPick($event)" />
3873
- * ```
3874
- */
3875
- export declare class ComboboxComponent<T = unknown> implements ControlValueAccessor, Validator, UiFieldValidity {
3876
- readonly label: import("@angular/core").InputSignal<string>;
3877
- /** Accessible name for a field with no visible label. */
3878
- readonly ariaLabel: import("@angular/core").InputSignal<string>;
3879
- readonly placeholder: import("@angular/core").InputSignal<string>;
3880
- readonly required: import("@angular/core").InputSignal<boolean>;
3881
- readonly hint: import("@angular/core").InputSignal<string>;
3882
- /** Host error message; always wins over the built-in message. */
3883
- readonly error: import("@angular/core").InputSignal<string>;
3884
- readonly showErrors: import("@angular/core").InputSignal<boolean>;
3885
- /** Current results (host-owned). */
3886
- readonly options: import("@angular/core").InputSignal<ComboboxOption<T>[]>;
3887
- readonly loading: import("@angular/core").InputSignal<boolean>;
3888
- readonly noResultsText: import("@angular/core").InputSignal<string>;
3889
- /** Characters needed before searching / listing. 0 = open on focus. */
3890
- readonly minChars: import("@angular/core").InputSignal<number>;
3891
- /** Milliseconds between the last keystroke and `(searchChange)`. */
3892
- readonly debounce: import("@angular/core").InputSignal<number>;
3893
- /** The selection. */
3894
- readonly value: import("@angular/core").InputSignal<ComboboxSelection | null>;
3895
- /** Text shown instead of the selected label (legacy / orphaned links). */
3896
- readonly displayText: import("@angular/core").InputSignal<string>;
3897
- /** Amber style for a legacy / orphaned `displayText`. */
3898
- readonly displayWarning: import("@angular/core").InputSignal<boolean>;
3899
- /** Typed term, debounced (immediate on focus / open). */
3900
- readonly searchChange: import("@angular/core").OutputEmitterRef<string>;
3901
- /** The chosen option, or null when cleared. */
3902
- readonly valueChange: import("@angular/core").OutputEmitterRef<ComboboxOption<T> | null>;
3903
- readonly invalidChange: import("@angular/core").OutputEmitterRef<boolean>;
3904
- readonly focused: import("@angular/core").OutputEmitterRef<void>;
3905
- readonly blurred: import("@angular/core").OutputEmitterRef<void>;
3906
- protected readonly _disabledInput: import("@angular/core").InputSignal<boolean>;
3907
- private readonly _cvaDisabled;
3908
- protected readonly disabled: import("@angular/core").Signal<boolean>;
3909
- private readonly _field;
3910
- private readonly _host;
3911
- private readonly _injector;
3912
- private readonly _destroyRef;
3913
- /** Follows `[value]`; ngModel / formControl writes and user picks override it until `[value]` changes. */
3914
- protected readonly _selected: import("@angular/core").WritableSignal<ComboboxSelection | null>;
3915
- private readonly _text;
3916
- private readonly _editing;
3917
- protected readonly _open: import("@angular/core").WritableSignal<boolean>;
3918
- /** Reset to the first enabled option whenever `[options]` changes, so a stale index never survives new results. */
3919
- protected readonly _activeIndex: import("@angular/core").WritableSignal<number>;
3920
- protected readonly _uid: number;
3921
- protected readonly _inputId: string;
3922
- protected readonly _listId: string;
3923
- protected readonly _descId: string;
3924
- private readonly _reveal;
3925
- private readonly _issue;
3926
- readonly invalid: import("@angular/core").Signal<boolean>;
3927
- readonly errorMessage: import("@angular/core").Signal<string>;
3928
- protected readonly _activeError: import("@angular/core").Signal<string>;
3929
- protected readonly _inputText: import("@angular/core").Signal<string>;
3930
- protected readonly _showClear: import("@angular/core").Signal<boolean>;
3931
- protected readonly _belowMin: import("@angular/core").Signal<boolean>;
3932
- protected readonly _statusText: import("@angular/core").Signal<string>;
3933
- protected readonly _liveText: import("@angular/core").Signal<string>;
3934
- protected readonly _activeDescendant: import("@angular/core").Signal<string | null>;
3935
- private _debounceTimer;
3936
- private _onChange;
3937
- private _onTouched;
3938
- private _onValidatorChange;
3939
- constructor();
3940
- ngOnChanges(): void;
3941
- writeValue(val: ComboboxSelection | null): void;
3942
- validate(control: AbstractControl): ValidationErrors | null;
3943
- registerOnValidatorChange(fn: () => void): void;
3944
- registerOnChange(fn: (v: ComboboxSelection | null) => void): void;
3945
- registerOnTouched(fn: () => void): void;
3946
- setDisabledState(d: boolean): void;
3947
- private _check;
3948
- /** What the user typed (trimmed); '' while not editing. */
3949
- private _term;
3950
- protected _optionId(i: number): string;
3951
- private _firstEnabled;
3952
- private _emitSearch;
3953
- private _cancelTimer;
3954
- private _revert;
3955
- private _openList;
3956
- private _move;
3957
- private _setActive;
3958
- protected onInput(event: Event): void;
3959
- protected onFocus(event: FocusEvent): void;
3960
- protected onClick(): void;
3961
- protected onBlur(): void;
3962
- protected onKeydown(e: KeyboardEvent): void;
3963
- protected onOptionMouseDown(e: MouseEvent, o: ComboboxOption<T>): void;
3964
- protected onOptionHover(i: number, o: ComboboxOption<T>): void;
3965
- /** Select `o` (also callable by a host through a template ref). */
3966
- choose(o: ComboboxOption<T>): void;
3967
- /** Clear the selection (the x button). */
3968
- clear(): void;
3969
- static ɵfac: i0.ɵɵFactoryDeclaration<ComboboxComponent<any>, never>;
3970
- static ɵcmp: i0.ɵɵComponentDeclaration<ComboboxComponent<any>, "ui-combobox", never, {
3971
- "label": {
3972
- "alias": "label";
3973
- "required": false;
3974
- "isSignal": true;
3975
- };
3976
- "ariaLabel": {
3977
- "alias": "ariaLabel";
3978
- "required": false;
3979
- "isSignal": true;
3980
- };
3981
- "placeholder": {
3982
- "alias": "placeholder";
3983
- "required": false;
3984
- "isSignal": true;
3985
- };
3986
- "required": {
3987
- "alias": "required";
3988
- "required": false;
3989
- "isSignal": true;
3990
- };
3991
- "hint": {
3992
- "alias": "hint";
3993
- "required": false;
3994
- "isSignal": true;
3995
- };
3996
- "error": {
3997
- "alias": "error";
3998
- "required": false;
3999
- "isSignal": true;
4000
- };
4001
- "showErrors": {
4002
- "alias": "showErrors";
4003
- "required": false;
4004
- "isSignal": true;
4005
- };
4006
- "options": {
4007
- "alias": "options";
4008
- "required": false;
4009
- "isSignal": true;
4010
- };
4011
- "loading": {
4012
- "alias": "loading";
4013
- "required": false;
4014
- "isSignal": true;
4015
- };
4016
- "noResultsText": {
4017
- "alias": "noResultsText";
4018
- "required": false;
4019
- "isSignal": true;
4020
- };
4021
- "minChars": {
4022
- "alias": "minChars";
4023
- "required": false;
4024
- "isSignal": true;
4025
- };
4026
- "debounce": {
4027
- "alias": "debounce";
4028
- "required": false;
4029
- "isSignal": true;
4030
- };
4031
- "value": {
4032
- "alias": "value";
4033
- "required": false;
4034
- "isSignal": true;
4035
- };
4036
- "displayText": {
4037
- "alias": "displayText";
4038
- "required": false;
4039
- "isSignal": true;
4040
- };
4041
- "displayWarning": {
4042
- "alias": "displayWarning";
4043
- "required": false;
4044
- "isSignal": true;
4045
- };
4046
- "_disabledInput": {
4047
- "alias": "disabled";
4048
- "required": false;
4049
- "isSignal": true;
4050
- };
4051
- }, {
4052
- "searchChange": "searchChange";
4053
- "valueChange": "valueChange";
4054
- "invalidChange": "invalidChange";
4055
- "focused": "focused";
4056
- "blurred": "blurred";
4057
- }, never, never, true, never>;
4058
- }
4059
- /**
4060
- * Types and pure helpers for the signer side of sending documents (docs/send-documents-contract.md, Addendum 2026-10-19).
4061
- * Everything here is app-agnostic: the roles are `signer1 .. signer4`, labels / names come from the host.
4062
- */
4063
- /** A CUSTOMER signer role. The countersigner (the sending user) is never a role: it is the document's own setting. */
4064
- export type SignerRole = 'signer1' | 'signer2' | 'signer3' | 'signer4';
4065
- /** All roles, in signing order (the order is strictly sequential by role number). */
4066
- export declare const SIGNER_ROLES: readonly SignerRole[];
4067
- /** The part of a document the host's `resolveRoles` callback is called with. */
4068
- export interface DocumentRolesTarget {
4069
- id: string;
4070
- title: string;
4071
- fileName: string | null;
4072
- }
4073
- /**
4074
- * Turns the signer section on (`documentSigners` of `ui-send-message-panel`). `null` / not passed = the panel is the plain single-recipient
4075
- * panel and nothing about signers is shown or sent.
4076
- */
4077
- export interface DocumentSignersConfig {
4078
- /** Largest number of customer signers the panel accepts (roles above it are ignored). Default 4. */
4079
- maxSigners?: number;
4080
- /** Labels per role. Default `Signer 1` .. `Signer 4`. */
4081
- roleLabels?: Partial<Record<SignerRole, string>>;
4082
- /** May one person fill two roles? Default false. */
4083
- allowSameContactInRoles?: boolean;
4084
- /** 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). */
4085
- requireSignerEmail?: boolean;
4086
- /** Name shown in the read-only countersign line ("Countersigned by <name> after all signers."). Default `you`. */
4087
- countersignerName?: string;
4088
- /**
4089
- * Reads the customer roles a document defines when its `GET /documents` row has no `signerRoles` key (an app that keeps its
4090
- * placements elsewhere). Called once per chosen document, and again on "Retry". A failure blocks Send and offers a retry. An empty
4091
- * list = the document has no signature fields (informational).
4092
- */
4093
- resolveRoles?: (doc: DocumentRolesTarget) => Observable<SignerRole[]>;
4094
- }
4095
- /** One entry of `documents.signers` (present only for a document with MORE THAN ONE customer signer, always complete). */
4096
- export interface SendSigner {
4097
- role: SignerRole;
4098
- contactId: string;
4099
- name: string;
4100
- email: string | null;
4101
- /** 1..N, equal to the role number (strictly sequential). */
4102
- order: number;
4103
- }
4104
- /** Values the host has for THIS send, keyed by the keys it declares in `documentContextTypes` (e.g. `{ propertyId: '…' }`). */
4105
- export type SendContext = Record<string, string>;
4106
- /** One context key the app's backend accepts. */
4107
- export interface ContextTypeDef {
4108
- key: string;
4109
- label: string;
4110
- }
4111
- /** What `documentMergeCheck` sends (default route `POST <baseUrl>/documents/merge-check`). */
4112
- export interface MergeCheckRequest {
4113
- documentIds: string[];
4114
- customerId?: string;
4115
- signers?: SendSigner[];
4116
- context?: SendContext;
4117
- }
4118
- /** One data field that would be left empty. */
4119
- export interface MergeCheckEmptyField {
4120
- key: string;
4121
- label: string;
4122
- page?: number;
4123
- /** `NO_CONTEXT` | `NO_DATA` | `UNKNOWN_PATH` (other values are shown generically). */
4124
- reason?: string;
4125
- /** Optional plain-language reason from the server ("no property selected"); wins over the generic text of `reason`. */
4126
- detail?: string;
4127
- }
4128
- export interface MergeCheckResult {
4129
- documents: {
4130
- documentId: string;
4131
- title?: string;
4132
- empty: MergeCheckEmptyField[];
4133
- }[];
4134
- }
4135
- /** A host function that runs the merge check itself (instead of the default route). */
4136
- export type MergeCheckFn = (req: MergeCheckRequest) => Observable<MergeCheckResult>;
4137
- /** The structural part of a chosen document the helpers below read. */
4138
- export interface SignerDocLike {
4139
- id: string;
4140
- title: string;
4141
- requiresCountersign?: boolean;
4142
- /** 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. */
4143
- hasCountersignPlacement?: boolean;
4144
- signerRoles?: SignerRole[];
4145
- hasMapping?: boolean;
4146
- hasDataFields?: boolean;
4147
- }
4148
- /** Where the roles of a document without a `signerRoles` key stand when the host resolves them. */
4149
- export interface RoleState {
4150
- status: 'loading' | 'ready' | 'error';
4151
- roles: SignerRole[];
4152
- }
4153
- /** What the signer logic concluded for the chosen documents (only on the value when `documentSigners` is on). */
4154
- export interface DocumentSignerInfo {
4155
- /** `ready` once every document's roles are known; `loading` / `error` block Send. */
4156
- status: 'loading' | 'ready' | 'error';
4157
- /** Every chosen document has no signature fields: the send is informational (view-only). */
4158
- informational: boolean;
4159
- /** Customer roles of the ONE chosen document (always starting at signer1, no gaps). Empty for several documents / informational. */
4160
- roles: SignerRole[];
4161
- /** Exactly one document, with more than one customer signer. */
4162
- multiSigner: boolean;
4163
- /** A document that is sent for signing requires the sender's countersignature. */
4164
- countersign: boolean;
4165
- /**
4166
- * Only present (and non-empty) when a signable chosen document requires the countersignature and its row says the countersign box is NOT
4167
- * placed (`hasCountersignPlacement === false`): the documents the "Place your countersignature box" link is offered for.
4168
- */
4169
- countersignUnplaced?: {
4170
- id: string;
4171
- title: string;
4172
- }[];
4173
- /** Several documents are chosen and one of them has several signers (it still goes to the one recipient). */
4174
- multiDocumentNote: boolean;
4175
- /** Under the document chip: what the mapping covers ('' when unknown). */
4176
- fieldsLine: string;
4177
- }
4178
- export declare const SIGNER_ROLE_LABEL_DEFAULT: (role: SignerRole) => string;
4179
- export declare function roleNumber(role: SignerRole): number;
4180
- /** The label of a role: the host's `roleLabels` entry, else `Signer N`. */
4181
- export declare function signerRoleLabel(role: SignerRole, cfg?: DocumentSignersConfig | null): string;
4182
- /** Valid roles only (`signer1..N`, N ≤ maxSigners), unique, sorted. Anything else is dropped. */
4183
- export declare function normalizeRoles(raw: unknown, maxSigners?: number): SignerRole[];
4184
- /**
4185
- * 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
4186
- * the highest saved one (a partial list is never sent). `[]` stays `[]` (no signature fields).
4187
- */
4188
- export declare function effectiveRoles(saved: SignerRole[]): SignerRole[];
4189
- /** True when the document has mapped data fields (the pre-send "fields that will be empty" check applies to it only). */
4190
- export declare function hasMappedDataFields(doc: SignerDocLike): boolean;
4191
- /** What the signer logic concludes for the chosen documents. `null` = `documentSigners` is off or nothing is chosen. */
4192
- export declare function describeDocumentSigners(docs: SignerDocLike[], states: Record<string, RoleState>, cfg: DocumentSignersConfig | null | undefined): DocumentSignerInfo | null;
4193
- /** The read-only countersign line ('' = not shown). */
4194
- export declare function countersignLine(info: DocumentSignerInfo | null, cfg: DocumentSignersConfig | null | undefined, viaDocuSign: boolean): string;
4195
- export interface SignerPick {
4196
- id: string;
4197
- name: string;
4198
- email?: string | null;
4199
- }
4200
- /** The complete `signers` list (recipient first), or null while any role has no contact. */
4201
- export declare function buildSigners(roles: SignerRole[], recipient: SignerPick, picks: Partial<Record<SignerRole, SignerPick | null>>): SendSigner[] | null;
4202
- /**
4203
- * The first problem per role (`''` = fine) in signing order: empty → `<Role label> is required.`, no email → `<Name> has no email address.`,
4204
- * the same person twice (unless allowed) → `<Name> is already <Earlier role label>.` on the later row.
4205
- */
4206
- export declare function signerProblems(roles: SignerRole[], recipient: SignerPick, picks: Partial<Record<SignerRole, SignerPick | null>>, cfg: DocumentSignersConfig | null | undefined): Partial<Record<SignerRole, string>>;
4207
- /** Only the declared context keys, with non-blank values; `undefined` when nothing is left. */
4208
- export declare function forwardContext(ctx: SendContext | null | undefined, types: readonly ContextTypeDef[]): {
4209
- context?: SendContext;
4210
- dropped: string[];
4211
- };
4212
- /** One merge-check field as text: `Property Address (no property selected)`. */
4213
- export declare function mergeFieldText(f: MergeCheckEmptyField): string;
4214
- /** The warning lines of a merge-check answer: one line for one document, `<title>: …` per document for several. Nothing when nothing is empty. */
4215
- export declare function mergeWarningLines(res: MergeCheckResult | null | undefined, docTitles: Record<string, string>): string[];
4216
- /** The accessible name of the "Place your countersignature box" link of a document. */
4217
- export declare function countersignPlaceLabel(title: string): string;
4218
- /** What the sender wants done with the chosen documents. Same values as the backend (`ESIGN` | `ATTACH` | `BOTH`). */
4219
- export type DocumentSendPurpose = 'ESIGN' | 'ATTACH' | 'BOTH';
4220
- /** How the request reaches the recipient — derived from the channel: the Email tab sends `EMAIL`, the Text tab `TEXT`. */
4221
- export type DocumentSendDelivery = 'EMAIL' | 'TEXT';
4222
- /** Who sends a signature request: the app's own e-signature (`NATIVE`) or DocuSign. */
4223
- export type DocumentSignatureProvider = 'NATIVE' | 'DOCUSIGN';
4224
- /** One document from `GET <baseUrl>/documents`, reduced to what the picker needs. */
4225
- export interface DocumentOption {
4226
- id: string;
4227
- title: string;
4228
- fileName: string | null;
4229
- /** True when the document has a stored file (so it can be attached to an email). */
4230
- hasFile: boolean;
4231
- /** 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". */
4232
- requiresCountersign?: boolean;
4233
- /** 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. */
4234
- hasCountersignPlacement?: boolean;
4235
- /** Only with `documentSigners`: the document's customer roles from the `GET /documents` row (`signerRoles`). `[]` = no signature fields (informational). */
4236
- signerRoles?: SignerRole[];
4237
- /** The row says the document has saved placements of any kind (drives the "Fields placed for N signers" line and the merge check). */
4238
- hasMapping?: boolean;
4239
- /** The row says the document has mapped DATA fields (the pre-send merge check applies to it); when absent, `hasMapping` stands in. */
4240
- hasDataFields?: boolean;
4241
- /** Only for an envelope's document (`DocumentSeed.status`). */
4242
- status?: string;
4243
- }
4244
- /** A document the form starts with (`initialDocuments`). `hasFile` defaults to true. */
4245
- export interface DocumentSeed {
4246
- id: string;
4247
- title: string;
4248
- fileName?: string | null;
4249
- hasFile?: boolean;
4250
- requiresCountersign?: boolean;
4251
- hasCountersignPlacement?: boolean;
4252
- signerRoles?: SignerRole[];
4253
- hasMapping?: boolean;
4254
- hasDataFields?: boolean;
4255
- /** An envelope's document that is not `ACTIVE` (e.g. `ARCHIVED`) blocks the send: "<title> is archived, so this envelope can't be sent. …". */
4256
- status?: string;
4257
- }
4258
- /**
4259
- * An existing envelope the panel sends (`documentEnvelope`): its documents are fixed (no search, no remove) and the request is sent, not
4260
- * created. Give `documents` when the host has read them already, or `loadDocuments` to let the panel read them (it shows the wait, and a
4261
- * failure blocks Send with a Retry button). With neither, the envelope has no documents and cannot be sent.
4262
- */
4263
- export interface DocumentEnvelopeTarget {
4264
- id: string;
4265
- /** Shown in the subject suggestion ("Signature required: <name>") and in the success toast. */
4266
- name: string;
4267
- documents?: DocumentSeed[];
4268
- loadDocuments?: () => Observable<DocumentSeed[]>;
4269
- }
4270
- /** The document a host's `documentPreview` handler is called with. */
4271
- export interface DocumentPreviewTarget {
4272
- id: string;
4273
- title: string;
4274
- fileName: string | null;
4275
- }
4276
- /** The recipient the panel currently holds (as the panel's `contactId` / `contactName` / `contactEmail` / `contactPhone` inputs). */
4277
- export interface DocumentPreviewContact {
4278
- id: string;
4279
- name: string;
4280
- email: string;
4281
- phone: string;
4282
- }
4283
- /**
4284
- * Second argument of `documentPreview`: who the document is being sent to, so the host can preview it filled for that recipient.
4285
- * `contact` is `null` when the panel has no recipient (all four contact inputs blank); `sendContext` is the panel's `sendContext` input
4286
- * as given (not filtered by `documentContextTypes`) or `null`.
4287
- */
4288
- export interface DocumentPreviewContext {
4289
- contact: DocumentPreviewContact | null;
4290
- sendContext: SendContext | null;
4291
- }
4292
- /**
4293
- * Opens a document for preview (the host knows its own route / viewer). Called synchronously inside the click. The second argument
4294
- * is new and optional to use: a handler that only declares `doc` keeps working.
4295
- */
4296
- export type DocumentPreviewHandler = (doc: DocumentPreviewTarget, context: DocumentPreviewContext) => void;
4297
- /**
4298
- * Turns on the "Expiry and Reminders" settings of the document section and sets their starting values (the keys you leave out start at
4299
- * the defaults below). `null` / not passed = the settings are not shown and nothing about them is sent.
4300
- */
4301
- export interface DocumentSigningOptions {
4302
- /** Days until an unsigned request expires: whole number 1-90 (default 7). */
4303
- expiryDays?: number;
4304
- /** Days between reminders: whole number 1-30 (default 2). */
4305
- reminderIntervalDays?: number;
4306
- /** How many reminders at most: whole number 0-10 (default 3). */
4307
- maxReminders?: number;
4308
- }
4309
- /** Defaults and limits of the signing settings (the same limits the servers enforce). */
4310
- export declare const DEFAULT_SIGNING_OPTIONS: {
4311
- readonly expiryDays: 7;
4312
- readonly reminderIntervalDays: 2;
4313
- readonly maxReminders: 3;
4314
- };
4315
- export declare const SIGNING_LIMITS: {
4316
- readonly expiryDays: {
4317
- readonly min: 1;
4318
- readonly max: 90;
4319
- readonly label: "Expiry (days)";
4320
- };
4321
- readonly reminderIntervalDays: {
4322
- readonly min: 1;
4323
- readonly max: 30;
4324
- readonly label: "Reminder Interval (days)";
4325
- };
4326
- readonly maxReminders: {
4327
- readonly min: 0;
4328
- readonly max: 10;
4329
- readonly label: "Max Reminders";
4330
- };
4331
- };
4332
- export declare const DOCUMENT_PROVIDER_OPTIONS: RadioOption[];
4333
- /** The value `ui-document-send-options` emits and the message forms turn into `SendEmailPayload.documents` / `SendTextPayload.documents`. */
4334
- export interface DocumentSendValue {
4335
- documentIds: string[];
4336
- documents: DocumentOption[];
4337
- purpose: DocumentSendPurpose;
4338
- delivery: DocumentSendDelivery;
4339
- /** Only when the signing settings are shown (host `signing` input), valid and the request is a native e-signature one. */
4340
- expiryDays?: number;
4341
- reminderIntervalDays?: number;
4342
- maxReminders?: number;
4343
- /** Only when the provider choice is offered (`docuSignConnected` and exactly one document on the email channel). */
4344
- provider?: DocumentSignatureProvider;
4345
- /** Only with `provider: 'DOCUSIGN'`. */
4346
- docuSign?: {
4347
- countersign: boolean;
4348
- };
4349
- /** Only when `signers` (the host's `documentSigners`) is on and a document is chosen: what the signer logic concluded. Never part of the payload. */
4350
- signerInfo?: DocumentSignerInfo;
4351
- }
4352
- export declare const DOCUMENT_PURPOSE_OPTIONS: SelectOption[];
4353
- /**
4354
- * ui-document-send-options — choose the documents that go out with an email or a text.
4355
- *
4356
- * Search-as-you-type over `GET <baseUrl>/documents?search=&size=20` (nothing is requested before 2 characters, the combobox
4357
- * debounces 250 ms, a newer search cancels an older one), the chosen documents shown as removable chips, and — on the email channel — a
4358
- * "What should the recipient do?" select (e-signature / attachment / both). On the text channel documents can only go as a
4359
- * link, so the purpose is fixed to e-signature and the select is not shown.
4360
- *
4361
- * Optional parts, all off by default (hosts reach them through the same-named inputs of `ui-send-message-panel`):
4362
- * - `signing` — "Expiry and Reminders" (expiry days, reminder interval, max reminders) for native e-signature requests;
4363
- * - `docuSignConnected` — "Native E-Sign / Send via DocuSign" choice (email channel, exactly one document);
4364
- * - `documentPreview` — "Preview Document" button(s) that call the host's handler.
4365
- * - `signers` — the signer logic of the panel's `documentSigners` (a document's customer roles, informational documents, the
4366
- * one-signer DocuSign rule, the document's own countersign setting); the value then carries `signerInfo`;
4367
- * - `envelope` — an existing envelope: its documents are the fixed list (given, or read through `loadDocuments`).
4368
- *
4369
- * The signing settings are ONE collapsed summary line ("Signing options: expires in 7 days, ...") with a Change / Hide button.
4370
- *
4371
- * It is embedded by `ui-send-message-panel` (`[documents]="true"`); it can also be used on its own.
4372
- *
4373
- * ```html
4374
- * <ui-document-send-options channel="email" [showErrors]="touched()" (valueChange)="docs.set($event)" (invalidChange)="docsInvalid.set($event)" />
4375
- * ```
4376
- *
4377
- * Validity: provides `UiFieldValidity` (`invalid` / `errorMessage`) and the `invalidChange` output. Invalid when `required`
4378
- * and nothing is chosen, when the purpose is "Send as attachment" and a chosen document has no stored file, or when a shown signing
4379
- * setting is blank / out of range. Messages
4380
- * show only while `showErrors` is true.
4381
- */
4382
- export declare class DocumentSendOptionsComponent implements UiFieldValidity {
4383
- private readonly http;
4384
- private readonly destroyRef;
4385
- /** API root from FORGEROUTE_CONFIG (e.g. a cross-origin prod API); falls back to same-origin `/api`. */
4386
- private readonly apiBase;
4387
- /** `email` → purpose select + attachment allowed; `text` → link only (purpose fixed to e-signature). */
4388
- readonly channel: import("@angular/core").InputSignal<"text" | "email">;
4389
- readonly label: import("@angular/core").InputSignal<string>;
4390
- /** When true, at least one document must be chosen. The message forms leave it false: documents are optional there. */
4391
- readonly required: import("@angular/core").InputSignal<boolean>;
4392
- /** Shows the validation message (bind it to the host's "tried to submit" flag). */
4393
- readonly showErrors: import("@angular/core").InputSignal<boolean>;
4394
- readonly valueChange: import("@angular/core").OutputEmitterRef<DocumentSendValue>;
4395
- readonly invalidChange: import("@angular/core").OutputEmitterRef<boolean>;
4396
- /**
4397
- * Which purposes the app's backend supports (default: all three). With a single purpose the select is hidden and that
4398
- * purpose is always sent — e.g. `['ESIGN']` for an app that only does e-signature.
4399
- */
4400
- readonly purposes: import("@angular/core").InputSignal<DocumentSendPurpose[]>;
4401
- /**
4402
- * Documents already chosen when the form opens (e.g. the row the user clicked "Send Document" on): shown as chips and part
4403
- * of the value straight away; the user can remove them or add more. Read once — later changes to the input are ignored.
4404
- * `hasFile` defaults to true (an attachment check then relies on the server's answer).
4405
- */
4406
- readonly initialDocuments: import("@angular/core").InputSignal<DocumentSeed[]>;
4407
- /**
4408
- * Shows the "Expiry and Reminders" settings (Expiry 1-90 days, Reminder Interval 1-30 days, Max Reminders 0-10, all required whole
4409
- * numbers; starting at 7 / 2 / 3 unless this object says otherwise) while at least one document is chosen and the request is a native
4410
- * e-signature one (purpose e-signature or both; always on the text channel). `null` (default) = not shown, nothing sent. Read once.
4411
- */
4412
- readonly signing: import("@angular/core").InputSignal<DocumentSigningOptions | null | undefined>;
4413
- /**
4414
- * The host knows whether DocuSign is connected (the library never calls `/docusign/status`). `true` offers "Native E-Sign / Send via
4415
- * DocuSign" on the email channel while exactly one document is chosen; `false` (default) = no choice, native only.
4416
- */
4417
- readonly docuSignConnected: import("@angular/core").InputSignal<boolean>;
4418
- /**
4419
- * "Preview Document": called with the document when its button is clicked (one button for one document, one per document for several).
4420
- * `null` (default) hides the buttons. The host opens its own viewer; to open a new tab do it synchronously inside this call
4421
- * (`window.open` after an await is blocked as a popup in Safari).
4422
- */
4423
- readonly documentPreview: import("@angular/core").InputSignal<DocumentPreviewHandler | null>;
4424
- /** The recipient passed to `documentPreview` as `context.contact` (the send panel sets it from its contact inputs). `null` = none. */
4425
- readonly previewContact: import("@angular/core").InputSignal<DocumentPreviewContact | null>;
4426
- /** The send context passed to `documentPreview` as `context.sendContext` (the send panel sets it from its `sendContext`). `null` = none. */
4427
- readonly previewSendContext: import("@angular/core").InputSignal<SendContext | null>;
4428
- /**
4429
- * Turns on the signer logic (`documentSigners` of the panel): a document's customer roles (from its row's `signerRoles`, or the config's
4430
- * `resolveRoles`), informational documents (no signature fields), the one-signer DocuSign rule and the read-only countersign rule.
4431
- * The value then carries `signerInfo`. `null` (default) = none of it; nothing changes.
4432
- */
4433
- readonly signers: import("@angular/core").InputSignal<DocumentSignersConfig | null | undefined>;
4434
- /**
4435
- * An existing envelope (`documentEnvelope` of the panel): its documents are the list, fixed (no search, no remove buttons). Read when it
4436
- * is set; `null` (default) = the sender chooses the documents.
4437
- */
4438
- readonly envelope: import("@angular/core").InputSignal<DocumentEnvelopeTarget | null>;
4439
- /** The document list is fixed: an existing envelope's. */
4440
- readonly locked: import("@angular/core").Signal<boolean>;
4441
- protected readonly purposeOptions: import("@angular/core").Signal<SelectOption<string>[]>;
4442
- readonly search$: Subject<string>;
4443
- readonly options: import("@angular/core").WritableSignal<ComboboxOption<DocumentOption>[]>;
4444
- readonly loading: import("@angular/core").WritableSignal<boolean>;
4445
- readonly selected: import("@angular/core").WritableSignal<DocumentOption[]>;
4446
- readonly purposeChoice: import("@angular/core").WritableSignal<DocumentSendPurpose>;
4447
- /** What the sender picked in the provider choice (only effective while the choice is offered). */
4448
- readonly providerChoice: import("@angular/core").WritableSignal<DocumentSignatureProvider>;
4449
- readonly countersignChoice: import("@angular/core").WritableSignal<boolean>;
4450
- /** Roles of documents whose row had no `signerRoles` and that the host resolves (`signers().resolveRoles`). */
4451
- readonly roleStates: import("@angular/core").WritableSignal<Record<string, RoleState>>;
4452
- /** The envelope's documents: `loading` / `error` while the panel reads them (`loadDocuments`), `ready` once known. */
4453
- readonly envelopeStatus: import("@angular/core").WritableSignal<"error" | "loading" | "ready" | "idle">;
4454
- private envelopeSub;
4455
- private readonly roleSubs;
4456
- /** The sender opened the collapsed "Signing options" line. */
4457
- readonly signingOpen: import("@angular/core").WritableSignal<boolean>;
4458
- readonly expiryDays: import("@angular/core").WritableSignal<string>;
4459
- readonly reminderIntervalDays: import("@angular/core").WritableSignal<string>;
4460
- readonly maxReminders: import("@angular/core").WritableSignal<string>;
4461
- protected readonly providerOptions: RadioOption[];
4462
- /** The search box; cleared (and kept focused) after each pick so the next search starts empty. */
4463
- private readonly combo;
4464
- /** True when the last search request failed (shown inline instead of "No matching documents"). */
4465
- readonly searchFailed: import("@angular/core").WritableSignal<boolean>;
4466
- /** 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). */
4467
- protected readonly searchFailedMessage = "Couldn't search your documents. Check your connection and try again.";
4468
- /**
4469
- * False when the section can't be used: the text channel only sends an e-signature link, so an app whose `purposes` excludes
4470
- * `ESIGN` has nothing to offer there. The section then shows a short note instead of a picker (it never silently sends another purpose).
4471
- */
4472
- readonly available: import("@angular/core").Signal<boolean>;
4473
- /** 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. */
4474
- readonly providerChoiceShown: import("@angular/core").Signal<boolean>;
4475
- /** The provider that is actually used: DocuSign only while the choice is offered. */
4476
- readonly provider: import("@angular/core").Signal<DocumentSignatureProvider>;
4477
- /** The countersignature checkbox: a DocuSign send of a document flagged `requiresCountersign`. */
4478
- readonly showCountersign: import("@angular/core").Signal<boolean>;
4479
- /** The checkbox (no `signers`) or, with `signers` on, the document's own setting: the document says whether it is countersigned. */
4480
- readonly countersign: import("@angular/core").Signal<boolean>;
4481
- /** 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). */
4482
- readonly signingVisible: import("@angular/core").Signal<boolean>;
4483
- /** What the signer logic concluded for the chosen documents (`null` when `signers` is off or nothing is chosen). */
4484
- readonly signerInfo: import("@angular/core").Signal<DocumentSignerInfo | null>;
4485
- /** Why an envelope cannot be sent ('' = it can): nothing to send, or a document that is no longer active. Shown under the section. */
4486
- readonly envelopeProblem: import("@angular/core").Signal<string>;
4487
- /** Why Send waits for the envelope's documents ('' when they are known). */
4488
- 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.">;
4489
- /** Why Send waits for the document's signers ('' when they are known). */
4490
- 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.">;
4491
- /** The collapsed line: "Signing options: expires in 7 days, reminders every 2 days, up to 3". */
4492
- readonly signingSummary: import("@angular/core").Signal<string>;
4493
- /** Open when the sender opened it, or while a value is broken (the error must be visible). */
4494
- readonly signingExpanded: import("@angular/core").Signal<boolean>;
4495
- /** The purpose that is actually sent: the text channel and DocuSign can only do e-signature. */
4496
- readonly purpose: import("@angular/core").Signal<DocumentSendPurpose>;
4497
- readonly delivery: import("@angular/core").Signal<DocumentSendDelivery>;
4498
- readonly value: import("@angular/core").Signal<DocumentSendValue>;
4499
- /** The first broken signing setting ('' when fine or not shown) — the inputs show their own messages. */
4500
- readonly signingError: import("@angular/core").Signal<string>;
4501
- /** The first broken document rule ('' when fine) — shown under the section. */
4502
- readonly documentError: import("@angular/core").Signal<string>;
4503
- /** The first broken rule ('' when valid): the document rules, the wait for the signers, then the signing settings. */
4504
- readonly errorMessage: import("@angular/core").Signal<string>;
4505
- readonly invalid: import("@angular/core").Signal<boolean>;
4506
- constructor();
4507
- private static seedToOption;
4508
- /** Sets the envelope's documents as the list; reads them first when the host gave a loader. */
4509
- private loadEnvelope;
4510
- /** "Retry" after the envelope's documents could not be read. */
4511
- retryEnvelope(): void;
4512
- private static toOption;
4513
- /** Asks the host for the roles of every chosen document that needs it; forgets documents that were removed. */
4514
- private syncRoleRequests;
4515
- private requestRoles;
4516
- /** "Retry" after the roles of a document could not be read. */
4517
- retryRoles(): void;
4518
- /** 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). */
4519
- toggleSigning(): void;
4520
- private seedSigning;
4521
- /** `ui-text-input` hands the typed text back as a string (or a number from a programmatic write). */
4522
- protected asText(v: unknown): string;
4523
- setProvider(p: string): void;
4524
- /** Calls the host's preview handler straight from the click (no await in between: Safari blocks a tab opened later). */
4525
- preview(doc: DocumentOption): void;
4526
- onPick(opt: ComboboxOption<DocumentOption> | null): void;
4527
- remove(id: string): void;
4528
- setPurpose(p: string): void;
4529
- /** Empties the selection (the host calls it after a successful send). */
4530
- reset(): void;
4531
- static ɵfac: i0.ɵɵFactoryDeclaration<DocumentSendOptionsComponent, never>;
4532
- static ɵcmp: i0.ɵɵComponentDeclaration<DocumentSendOptionsComponent, "ui-document-send-options", never, {
4533
- "channel": {
4534
- "alias": "channel";
4535
- "required": false;
4536
- "isSignal": true;
4537
- };
4538
- "label": {
4539
- "alias": "label";
4540
- "required": false;
4541
- "isSignal": true;
4542
- };
4543
- "required": {
4544
- "alias": "required";
4545
- "required": false;
4546
- "isSignal": true;
4547
- };
4548
- "showErrors": {
4549
- "alias": "showErrors";
4550
- "required": false;
4551
- "isSignal": true;
4552
- };
4553
- "purposes": {
4554
- "alias": "purposes";
4555
- "required": false;
4556
- "isSignal": true;
4557
- };
4558
- "initialDocuments": {
4559
- "alias": "initialDocuments";
4560
- "required": false;
4561
- "isSignal": true;
4562
- };
4563
- "signing": {
4564
- "alias": "signing";
4565
- "required": false;
4566
- "isSignal": true;
4567
- };
4568
- "docuSignConnected": {
4569
- "alias": "docuSignConnected";
4570
- "required": false;
4571
- "isSignal": true;
4572
- };
4573
- "documentPreview": {
4574
- "alias": "documentPreview";
4575
- "required": false;
4576
- "isSignal": true;
4577
- };
4578
- "previewContact": {
4579
- "alias": "previewContact";
4580
- "required": false;
4581
- "isSignal": true;
4582
- };
4583
- "previewSendContext": {
4584
- "alias": "previewSendContext";
4585
- "required": false;
4586
- "isSignal": true;
4587
- };
4588
- "signers": {
4589
- "alias": "signers";
4590
- "required": false;
4591
- "isSignal": true;
4592
- };
4593
- "envelope": {
4594
- "alias": "envelope";
4595
- "required": false;
4596
- "isSignal": true;
4597
- };
4598
- }, {
4599
- "valueChange": "valueChange";
4600
- "invalidChange": "invalidChange";
4601
- }, never, never, true, never>;
4602
- }
4603
- /**
4604
- * Video share-link helpers shared by every app (they replace the apps' own copies, e.g. real-estate `video-link.utils.ts`).
4605
- *
4606
- * The share link of a video (`VideoMessage.shareLink`) carries the playback settings as query parameters:
4607
- * autoplay=1 · ref=<contact id> · ctaType · ctaUrl · ctaLabel · hideReactions=1 (in exactly that order).
4608
- */
4609
- interface VideoLinkOptions {
4610
- autoplay?: boolean;
4611
- /** The recipient: lets the video page track who watched (`ref`). */
4612
- contactId?: string;
4613
- /** '' / undefined = none (the video's own default); `schedule` | `contact` | `custom`. */
4614
- ctaType?: string;
4615
- ctaUrl?: string;
4616
- ctaLabel?: string;
4617
- hideReactions?: boolean;
4618
- }
4619
- /**
4620
- * Default video settings the host reads from its Communication settings (same keys as `/comm-settings` without the `videoDefault`
4621
- * prefix): `videoDefaultAutoplay` → `autoplay`, `videoDefaultCtaType` → `ctaType`, … Missing keys mean "off" / "none".
4622
- */
4623
- interface VideoDefaults {
4624
- autoplay?: boolean;
4625
- ctaType?: string;
4626
- ctaUrl?: string;
4627
- ctaLabel?: string;
4628
- hideReactions?: boolean;
4629
- }
4630
- /** `baseLink` + the settings as query parameters (unchanged when no setting is on). A base that already has a query gets `&`. */
4631
- export declare function buildVideoLink(baseLink: string, options?: VideoLinkOptions): string;
4632
- /**
4633
- * The share link of a freshly attached video: `baseLink` with the host's defaults and the recipient applied — exactly the link
4634
- * `ui-video-link-settings` shows before the sender changes anything.
4635
- */
4636
- declare function videoLinkWithDefaults(baseLink: string, defaults?: VideoDefaults, contactId?: string): string;
4637
- /** Strips any "🎬 Watch video: <url>" line previously inserted into a message body (the line format the apps' own composers use). */
4638
- export declare function stripVideoLink(text: string): string;
4639
- /** Appends a "🎬 Watch video: <link>" line to a message body (replacing one that is already there). */
4640
- export declare function appendVideoLink(text: string, link: string): string;
4641
- /** The line `ui-send-message-panel` puts in the message for an attached video: `Watch "<title>": <link>`. */
4642
- export declare function videoMessageLine(title: string, link: string): string;
4643
- /**
4644
- * Puts `next` into `body` in place of `prev` (the line inserted earlier), so changing a video setting rewrites the link without
4645
- * touching the rest of the message:
4646
- * - no `prev` yet → appended after a blank line (no separator for an empty body);
4647
- * - `prev` is in the body → replaced in place; with an empty `next` it is removed together with its separator;
4648
- * - `prev` was edited away by the sender → the body is left as the sender wrote it.
4649
- */
4650
- export declare function applyVideoLine(body: string, prev: string, next: string): string;
4651
- /** The `documents` key of `SendEmailPayload` / `SendTextPayload`: present only when at least one document was chosen. */
4652
- interface SendDocumentsPayload {
4653
- documentIds: string[];
4654
- /** `ESIGN` | `ATTACH` | `BOTH` (always `ESIGN` for texts). */
4655
- purpose: DocumentSendPurpose;
4656
- /** `EMAIL` for the email form, `TEXT` for the text form. */
4657
- delivery: DocumentSendDelivery;
4658
- /** 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). */
4659
- expiryDays?: number;
4660
- /** Same condition as `expiryDays`: days between reminders (1-30). */
4661
- reminderIntervalDays?: number;
4662
- /** Same condition as `expiryDays`: how many reminders at most (0-10). */
4663
- maxReminders?: number;
4664
- /** Only when the host passed `docuSignConnected` and the sender can choose (email, exactly one document): which e-signature provider sends the request. */
4665
- provider?: DocumentSignatureProvider;
4666
- /** Only with `provider: 'DOCUSIGN'`: `countersign` is true when the sender ticked "Require my countersignature after client signs" (only offered for a document flagged `requiresCountersign`). */
4667
- docuSign?: {
4668
- countersign: boolean;
4669
- };
4670
- /**
4671
- * 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
4672
- * customer signer: all N signers including signer1 (= the recipient), ordered by role, never partial. A single-signer send has no such key.
4673
- */
4674
- signers?: SendSigner[];
4675
- /** Only when the host passed `sendContext` and at least one key it declared in `documentContextTypes` has a value (other keys are dropped). */
4676
- context?: SendContext;
4677
- /** Only when the send is of an existing envelope (`documentEnvelope`): its id; the request is not created again, it is sent. */
4678
- envelopeId?: string;
4679
- /** 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). */
4680
- informational?: true;
4681
- }
4682
- /** What the success toast of a document send can say (`documentSentMessage` of the panel). */
4683
- interface DocumentSentInfo {
4684
- titles: string[];
4685
- /** Only when an existing envelope was sent (`documentEnvelope`). */
4686
- envelopeName?: string;
4687
- channel: 'email' | 'text';
4688
- provider?: DocumentSignatureProvider;
4689
- /** Every chosen document has no signature fields (a view link was sent). */
4690
- informational: boolean;
4691
- }
4692
- /** Builds the success toast of a document send (default: `Email sent` / `Text message sent` / `"<title>" sent via DocuSign` / `Envelope "<name>" sent`). */
4693
- type DocumentSentMessage = (info: DocumentSentInfo) => string;
4694
- /** The optional parts the form adds to the `documents` payload besides what the document section holds. */
4695
- interface DocumentsPayloadExtras {
4696
- signers?: SendSigner[] | null;
4697
- context?: SendContext;
4698
- envelopeId?: string;
4699
- }
4700
- /**
4701
- * The `documents` part of a payload from what the document section holds. The optional keys (signing settings, provider, DocuSign
4702
- * options) are present only when the section produced them, so a host that turned none of them on gets exactly
4703
- * `{ documentIds, purpose, delivery }`.
4704
- */
4705
- declare function buildDocumentsPayload(v: DocumentSendValue, delivery: DocumentSendDelivery, purpose?: DocumentSendPurpose, extras?: DocumentsPayloadExtras): SendDocumentsPayload;
4706
- /**
4707
- * Subject of the signature request when the sender has none (texts have no subject). The server treats exactly this
4708
- * text as a placeholder and builds the real subject from the document names.
4709
- */
4710
- export declare const DEFAULT_DOCUMENT_SUBJECT = "Document Signature Required";
4711
- /**
4712
- * The subject the library suggests once documents are chosen on the email form — the same text the servers build when the
4713
- * sender leaves the subject out: signing (ESIGN / BOTH) → "Signature required: <title>" (several: "<N> documents to sign: <first>…");
4714
- * attachment only → "Document attached: <title>" (several: "<N> documents attached: <first>…"). '' for no documents.
4715
- */
4716
- export declare function suggestDocumentSubject(titles: string[], purpose: DocumentSendPurpose, informational?: boolean): string;
4717
- /** Most people that can be copied on one email (same limit as the server). */
4718
- export declare const MAX_CC = 10;
4719
- /** CC addresses typed as text: comma / semicolon / whitespace separated, trimmed, de-duplicated (case-insensitive). */
4720
- export declare function parseCcList(raw: string): string[];
4721
- /** The first problem with a CC list, '' when fine — the same rules the server enforces (valid addresses, at most 10, fits the column). */
4722
- declare function ccError(list: string[]): string;
4723
- /** What the library sends to create a document request (`POST <baseUrl>/documents/envelopes`). See docs/send-documents-contract.md. */
4724
- interface CreateDocumentRequestBody {
4725
- subject: string;
4726
- message: string;
4727
- customerId?: string;
4728
- customerName: string;
4729
- customerEmail?: string;
4730
- customerPhone?: string;
4731
- documentIds: string[];
4732
- purpose: DocumentSendPurpose;
4733
- delivery: DocumentSendDelivery;
4734
- ccEmails?: string[];
4735
- /** Native e-signature requests only, and only when the host turned on `documentSigningOptions`. */
4736
- expiryDays?: number;
4737
- reminderIntervalDays?: number;
4738
- maxReminders?: number;
4739
- /** Only with `documentSigners` and a document with several customer signers (complete, ordered). */
4740
- signers?: SendSigner[];
4741
- /** Only with `sendContext` / `documentContextTypes`. */
4742
- context?: SendContext;
4743
- }
4744
- /** The signing settings of a `documents` payload as optional keys of the create-request body (nothing when there are none). */
4745
- declare function signingBodyFields(d: SendDocumentsPayload): Pick<CreateDocumentRequestBody, 'expiryDays' | 'reminderIntervalDays' | 'maxReminders'>;
4746
- /** 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). */
4747
- type ExistingEnvelopeSendBody = Omit<CreateDocumentRequestBody, 'documentIds'> & {
4748
- templateId?: string;
4749
- };
4750
- /**
4751
- * Sends an envelope that already exists (`documentEnvelope`): `POST <baseUrl>/documents/envelopes/{id}/send` with the recipient, message and
4752
- * options in the body (nothing is created first). The host can replace it with `[sendEmail]` / `[sendText]` (payload `documents.envelopeId`).
4753
- */
4754
- export declare function sendExistingEnvelope(http: HttpClient, apiBase: string, envelopeId: string, body: ExistingEnvelopeSendBody): Observable<unknown>;
4755
- /** The `signers` / `context` of a `documents` payload as optional keys of the create-request body (nothing when there are none). */
4756
- declare function signersContextBodyFields(d: SendDocumentsPayload): Pick<CreateDocumentRequestBody, 'signers' | 'context'>;
4757
- /** What the library sends to send ONE document through DocuSign (`POST <baseUrl>/docusign/send`). See docs/send-documents-contract.md. */
4758
- interface DocuSignSendBody {
4759
- documentId: string;
4760
- contactId: string;
4761
- subject?: string;
4762
- message?: string;
4763
- countersignRequired: boolean;
4764
- }
4765
- /** The default DocuSign send: `POST <baseUrl>/docusign/send` → 200. The host can replace it with `[sendEmail]`. */
4766
- declare function sendDocuSignRequest(http: HttpClient, apiBase: string, body: DocuSignSendBody): Observable<unknown>;
4767
- /**
4768
- * The default way a message form sends documents: create the request, then send it.
4769
- * 1. POST <baseUrl>/documents/envelopes → 201 { id, ... }
4770
- * 2. POST <baseUrl>/documents/envelopes/{id}/send → 200 (body { templateId } only when the message came from a template)
4771
- * A failure in step 2 leaves the created request as a draft on the server; the error is surfaced like any send error.
4772
- */
4773
- declare function sendDocumentRequest(http: HttpClient, apiBase: string, body: CreateDocumentRequestBody, templateId?: string): Observable<unknown>;
4774
- /** What the email form sends — the default `POST <baseUrl>/email-messages` body, or the host's `sendFn` argument. */
4775
- interface SendEmailPayload {
4776
- contactName: string;
4777
- contactEmail: string;
4778
- subject: string;
4779
- body: string;
4780
- contactId?: string;
4781
- scheduledAt?: string;
4782
- attachments?: {
4783
- filename: string;
4784
- content: string;
4785
- contentType: string;
4786
- }[];
4787
- /** Only present when the host enabled `showReceiptOption`: whether the sender ticked the receipt checkbox. */
4788
- includeReceipt?: boolean;
4789
- /** Only present when the email was sent from a saved template (still set after editing its text); lets the server count the template use. */
4790
- templateId?: string;
4791
- /** Only present when the host enabled `showCc` and the sender typed addresses: the people copied on the email (valid, deduplicated, at most 10). */
4792
- cc?: string[];
4793
- /** Only present when the host enabled `documents` and the sender chose at least one document (then `attachments` and `scheduledAt` are never set). */
4794
- documents?: SendDocumentsPayload;
4795
- }
4796
- /**
4797
- * HTML for the Preview pane, the "View Send Preview" modal AND the sent email body — the server converts the sent
4798
- * body with the same rules (contractor `messagePreviewHtml` in EmailTemplateService.kt), so what is previewed is
4799
- * exactly what is sent:
4800
- * - empty → ''
4801
- * - a body containing an HTML tag (`/<[a-z][\s\S]*>/i`) is HTML and is used untouched
4802
- * - otherwise it is plain text: `&`, `<`, `>`, `"` and `'` are escaped (`&amp;` `&lt;` `&gt;` `&quot;` `&#39;`)
4803
- * and every line break (`\r\n`, `\r`, `\n`) becomes `<br>`.
4804
- */
4805
- export declare function messagePreviewHtml(body: string): string;
4806
- declare class SendEmailComponent implements OnInit {
4807
- private readonly destroyRef;
4808
- private readonly http;
4809
- /** API root from FORGEROUTE_CONFIG (e.g. a cross-origin prod API); falls back to same-origin `/api`. */
4810
- private readonly apiBase;
4811
- private readonly toast;
4812
- readonly cdr: ChangeDetectorRef;
4813
- readonly contactName: import("@angular/core").InputSignal<string>;
4814
- readonly contactEmail: import("@angular/core").InputSignal<string>;
4815
- /** The contact's phone — fills `{{phone}}` (a blank phone makes `{{phone}}` a prompted field). */
4816
- readonly contactPhone: import("@angular/core").InputSignal<string>;
4817
- readonly contactId: import("@angular/core").InputSignal<string>;
4818
- /** Prefills Subject in "Create Message" mode (e.g. "Estimate #1042 — Kitchen Remodel"). */
4819
- readonly defaultSubject: import("@angular/core").InputSignal<string>;
4820
- /** Prefills Message in "Create Message" mode. */
4821
- readonly defaultBody: import("@angular/core").InputSignal<string>;
4822
- /** Extra merge variables (e.g. `estimate_number`, `estimate_total`) used in templates and the preview. */
4823
- readonly context: import("@angular/core").InputSignal<Record<string, string>>;
4824
- /**
4825
- * Sends through the host instead of `POST <baseUrl>/email-messages` — e.g. a page-specific endpoint that
4826
- * also marks a record Sent. Loading, toasts, `sent` and the double-send guard behave the same.
4827
- */
4828
- readonly sendFn: import("@angular/core").InputSignal<((payload: SendEmailPayload) => Observable<unknown>) | null>;
4829
- /** Shows an "include receipt" checkbox; the choice is sent as `includeReceipt`. Off = payload has no such key. */
4830
- readonly showReceiptOption: import("@angular/core").InputSignal<boolean>;
4831
- readonly receiptLabel: import("@angular/core").InputSignal<string>;
4832
- /** Initial state of the receipt checkbox (and the state it returns to after a send). */
4833
- readonly receiptDefault: import("@angular/core").InputSignal<boolean>;
4834
- /** Shows the "Documents" section (search your documents, choose what the recipient does with them). Off = the form is unchanged. */
4835
- readonly documents: import("@angular/core").InputSignal<boolean>;
4836
- /** Purposes the app's backend supports for documents (default all); a single entry hides the purpose select. */
4837
- readonly documentPurposes: import("@angular/core").InputSignal<DocumentSendPurpose[]>;
4838
- /** Documents already chosen in the Documents section when the form opens. */
4839
- readonly initialDocuments: import("@angular/core").InputSignal<DocumentSeed[]>;
4840
- /**
4841
- * Turns on the signer logic: one required contact per customer signer role of the chosen document, the read-only countersign line,
4842
- * informational documents (no signature fields) and the one-signer DocuSign rule. `null` (default) = the single recipient, unchanged.
4843
- */
4844
- readonly documentSigners: import("@angular/core").InputSignal<DocumentSignersConfig | null>;
4845
- /** Values the host has for THIS send; only the keys declared in `documentContextTypes` are sent, as `documents.context`. */
4846
- readonly sendContext: import("@angular/core").InputSignal<SendContext | null>;
4847
- /** The context keys the app's backend accepts. */
4848
- readonly documentContextTypes: import("@angular/core").InputSignal<ContextTypeDef[]>;
4849
- /** `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. */
4850
- readonly documentMergeCheck: import("@angular/core").InputSignal<boolean | MergeCheckFn>;
4851
- /** 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. */
4852
- readonly documentEnvelope: import("@angular/core").InputSignal<DocumentEnvelopeTarget | null>;
4853
- /** false = the app's email sending is switched off (Communication settings): Send stays off and the form says why. */
4854
- readonly emailEnabled: import("@angular/core").InputSignal<boolean>;
4855
- /** Builds the success toast of a document send (default texts otherwise). */
4856
- readonly documentSentMessage: import("@angular/core").InputSignal<DocumentSentMessage | null>;
4857
- /** Shows a CC field; the typed addresses are sent as `cc`. Off = payload has no such key. */
4858
- readonly showCc: import("@angular/core").InputSignal<boolean>;
4859
- /** Shows "Expiry and Reminders" for e-signature requests (see `DocumentSigningOptions`); sent as `documents.expiryDays` / `reminderIntervalDays` / `maxReminders`. `null` = off. */
4860
- readonly documentSigningOptions: import("@angular/core").InputSignal<DocumentSigningOptions | null | undefined>;
4861
- /** The host says DocuSign is connected: offers "Native E-Sign / Send via DocuSign" for a single document. Off = native only. */
4862
- readonly docuSignConnected: import("@angular/core").InputSignal<boolean>;
4863
- /** "Preview Document" button(s) in the Documents section call this; `null` hides them. */
4864
- readonly documentPreview: import("@angular/core").InputSignal<DocumentPreviewHandler | null>;
4865
- /** The recipient handed to `documentPreview` (second argument): the panel's contact inputs, `null` while all four are blank. */
4866
- readonly previewContact: import("@angular/core").Signal<DocumentPreviewContact | null>;
4867
- /**
4868
- * Turns on the video settings (Playback, Call-to-Action, Hide reactions, Watch Preview, Remove Video) once a video is attached, starting
4869
- * from these defaults, and makes the video link carry them. `null` (default) = the attached video's plain share link is inserted, as before.
4870
- */
4871
- readonly videoDefaults: import("@angular/core").InputSignal<VideoDefaults | null>;
4872
- /** false hides Attach Files and "Schedule for later" (for a host whose send function can't deliver them). */
4873
- readonly attachmentsAndScheduling: import("@angular/core").InputSignal<boolean>;
4874
- readonly sent: import("@angular/core").OutputEmitterRef<void>;
4875
- readonly emailAdded: import("@angular/core").OutputEmitterRef<string>;
4876
- readonly validChange: import("@angular/core").OutputEmitterRef<boolean>;
4877
- /** A document send was refused because the document / envelope changed meanwhile (404 / 409): the host refreshes its list. */
4878
- readonly rejected: import("@angular/core").OutputEmitterRef<void>;
4879
- /** The "Place your countersignature box" link under the countersign line was clicked (document row `hasCountersignPlacement: false`). */
4880
- readonly mapFieldsClick: import("@angular/core").OutputEmitterRef<{
4881
- id: string;
4882
- title: string;
4883
- }>;
4884
- readonly EMAIL_DISABLED_MESSAGE = "Email sending is disabled, so this can't be sent. Enable it in Communication Settings.";
4885
- mode: 'compose' | 'template';
4886
- subject: string;
4887
- body: string;
4888
- templateId: string | null;
4889
- previewFormat: 'preview' | 'raw';
4890
- showSendPreview: boolean;
4891
- previewingTemplate: {
4892
- subject: string;
4893
- body: string;
4894
- } | null;
4895
- customVars: Record<string, string>;
4896
- pendingInputs: Record<string, string>;
4897
- loading: boolean;
4898
- includeReceipt: boolean;
4899
- showSchedule: boolean;
4900
- scheduledAt: string;
4901
- attachments: {
4902
- filename: string;
4903
- content: string;
4904
- contentType: string;
4905
- sizeLabel: string;
4906
- }[];
4907
- pendingEmail: string;
4908
- ccText: string;
4909
- /** What the document section holds (null / empty = no documents) and whether it currently breaks a rule. */
4910
- documentsValue: DocumentSendValue | null;
4911
- documentsInvalid: boolean;
4912
- /** The complete signer list of the signer rows (null while a role has no contact) and whether they break a rule. */
4913
- signersValue: SendSigner[] | null;
4914
- signersInvalid: boolean;
4915
- /** Lines of the merge check ("These fields will be left empty: …"). */
4916
- mergeWarnings: string[];
4917
- readonly savingEmail: import("@angular/core").WritableSignal<boolean>;
4918
- readonly modeTabs: PillTab[];
4919
- /** Market values (`area`, `median_price`, `dom`, `new_listings`) — only the ones `/service-areas` returned. */
4920
- private marketVars;
4921
- ngOnInit(): void;
4922
- /** Defaults last applied to compose mode — a default only replaces text the user hasn't edited. */
4923
- private _appliedDefaults;
4924
- constructor();
4925
- /** The Subject last filled from the chosen documents — it is replaced only while the Subject still equals it (the user hasn't edited it). */
4926
- private _suggestedSubject;
4927
- /** Fills / updates / clears the document-based Subject suggestion (compose mode only; never touches text the user or the host wrote). */
4928
- private syncSuggestedSubject;
4929
- /** Puts the host's defaults into compose mode unless the user already changed that field. */
4930
- private applyDefaults;
4931
- protected readonly previewHtml: typeof messagePreviewHtml;
4932
- setPreviewFormat(f: 'preview' | 'raw'): void;
4933
- get pendingEmailValid(): boolean;
4934
- /** True when the sender chose at least one document (only possible when the `documents` input is on). */
4935
- get hasDocuments(): boolean;
4936
- /** 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. */
4937
- get viaDocuSign(): boolean;
4938
- /** The recipient as Signer 1 (a stable object: it feeds a child input). */
4939
- readonly recipientPick: import("@angular/core").Signal<{
4940
- id: string;
4941
- name: string;
4942
- email: string;
4943
- }>;
4944
- /** The declared context keys with a value (`documents.context`); keys the app did not declare are dropped (with a development warning). */
4945
- readonly forwardedContext: import("@angular/core").Signal<SendContext | undefined>;
4946
- /** What the signer logic concluded for the chosen documents (null when `documentSigners` is off or nothing is chosen). */
4947
- get signerInfo(): DocumentSignerInfo | null;
4948
- /** The chosen documents the merge check looks at. */
4949
- get mergeDocuments(): DocumentOption[];
4950
- /** True when a native e-signature request for ONE document with several customer signers is being built: the signer rows are required. */
4951
- get signersActive(): boolean;
4952
- /** The signer section is shown: signer rows, and/or the countersign line (a signed document that is not just attached). */
4953
- get signersSectionShown(): boolean;
4954
- /** The signer rows restart whenever the chosen document changes. */
4955
- get signersKey(): string;
4956
- onSigners(v: SendSigner[] | null): void;
4957
- onSignersInvalid(bad: boolean): void;
4958
- onMergeWarnings(lines: string[]): void;
4959
- /** The lines of the ONE warning banner: what choosing a document removed, a multi-signer document among several, the merge check. */
4960
- get warningLines(): {
4961
- key: string;
4962
- text: string;
4963
- testId: string | null;
4964
- }[];
4965
- /** The people copied on the email, as typed (empty unless `showCc` is on, and not used by a DocuSign send). */
4966
- get ccList(): string[];
4967
- /** The first problem with the CC field ('' when fine). */
4968
- get ccError(): string;
4969
- /** Set when choosing the first document removed something the sender had already added - said out loud (aria-live), never silently. */
4970
- docsRemovedNote: string;
4971
- onDocumentsChange(v: DocumentSendValue): void;
4972
- onDocumentsInvalid(bad: boolean): void;
4973
- /** Server limits (400 "Subject must be 255 characters or fewer." / "Body must be 10000 characters or fewer."). */
4974
- readonly MAX_SUBJECT = 255;
4975
- readonly MAX_BODY = 10000;
4976
- /** Inline error when the message, as it will be sent, is over the server limit ('' when fine). */
4977
- get bodyLengthError(): string;
4978
- /** Inline error when the subject, as it will be sent, is over the server limit ('' when fine). */
4979
- get subjectLengthError(): string;
4980
- /** The length problem shown under the form in every mode; compose mode shows the message one on the editor instead. */
4981
- get sendLengthError(): string;
4982
- get canSend(): boolean;
4983
- get minScheduleTime(): string;
4984
- /**
4985
- * Values every tag can resolve from before the user types anything: the contact (name, first / last name, email,
4986
- * phone), the date, the market values `/service-areas` returned and the host's `context` — non-blank values only,
4987
- * later sources winning.
4988
- */
4989
- private get knownVars();
4990
- /** Merges `text` with every known value plus what the user typed — the ONE merge the pane, modal and payload use. */
4991
- resolveMergeTags(text: string): string;
4992
- /** Applied values plus anything typed into a missing-field input — so the preview updates as the user types. */
4993
- private get liveVars();
4994
- /** The subject / body exactly as they will be sent (live: recomputed on every read, never cached). */
4995
- get resolvedSubject(): string;
4996
- get resolvedBody(): string;
4997
- /** The Preview pane's HTML — the same HTML the server sends (see messagePreviewHtml). */
4998
- get previewBodyHtml(): string;
4999
- /** The send-preview modal: the eye-button template when one is being previewed, otherwise the selected one. */
5000
- get sendPreviewSubject(): string;
5001
- get sendPreviewHtml(): string;
5002
- /** Template fields the user still has to fill — tags with no non-blank known value and nothing applied. */
5003
- get missingVars(): string[];
5004
- /** Compose mode: a `{{…}}` the form can't fill blocks sending (the server would refuse it). */
5005
- get composeTagError(): string;
5006
- /** Missing fields with nothing typed yet — Send stays disabled until this is empty. */
5007
- get unresolvedVars(): string[];
5008
- /**
5009
- * Applies every typed missing-field value (what the preview already shows) before sending. Never saves
5010
- * to the contact — only the explicit "+" / Enter apply does that.
5011
- */
5012
- private applyPendingVars;
5013
- formatVarLabel(key: string): string;
5014
- /** Applies a typed missing-field value. The explicit "+" / Enter apply (`persist`) also saves phone / address to the contact. */
5015
- applyVar(key: string, persist?: boolean): void;
5016
- stripBlockWrappers(html: string): string;
5017
- /** "View Send Preview": always the SELECTED template (never a template last opened with the eye button). */
5018
- openSendPreview(): void;
5019
- /** The picker's eye button: previews that template without selecting it. */
5020
- openQuickPreview(tpl: {
5021
- subject: string;
5022
- body: string;
5023
- }): void;
5024
- closeSendPreview(): void;
5025
- notifyValid(): void;
5026
- setMode(key: string): void;
5027
- saveEmail(): void;
5028
- clearTemplate(): void;
5029
- onTemplateSelected(tpl: TemplateItem): void;
5030
- onFilesSelected(event: Event): void;
5031
- removeAttachment(index: number): void;
5032
- insertVideo(v: VideoMessage): void;
5033
- /** The body of the default DocuSign send: Subject / Message only when the sender has them (DocuSign has its own defaults otherwise). */
5034
- private docuSignBody;
5035
- /** The video attached through the settings flow (null = none) and the line it put into the message. */
5036
- videoPicked: VideoMessage | null;
5037
- /** Bumped to re-create the video picker (it keeps its own selection and has no clear output). */
5038
- videoPickerKey: number;
5039
- private _videoLine;
5040
- /** The picker's output: with `videoDefaults` the video gets its settings section, otherwise the plain link is inserted as before. */
5041
- onVideoSelected(v: VideoMessage): void;
5042
- /** The settings section's output: rewrites the video line of the message with the current link (the rest of the message is untouched). */
5043
- onVideoLink(link: string): void;
5044
- /** "Remove Video": takes the video line out of the message and brings the picker back. */
5045
- removeVideo(): void;
5046
- private discardVideo;
5047
- submit(): void;
5048
- static ɵfac: i0.ɵɵFactoryDeclaration<SendEmailComponent, never>;
5049
- static ɵcmp: i0.ɵɵComponentDeclaration<SendEmailComponent, "ui-send-email", never, {
5050
- "contactName": {
5051
- "alias": "contactName";
5052
- "required": false;
5053
- "isSignal": true;
5054
- };
5055
- "contactEmail": {
5056
- "alias": "contactEmail";
5057
- "required": false;
5058
- "isSignal": true;
5059
- };
5060
- "contactPhone": {
5061
- "alias": "contactPhone";
5062
- "required": false;
5063
- "isSignal": true;
5064
- };
5065
- "contactId": {
5066
- "alias": "contactId";
5067
- "required": false;
5068
- "isSignal": true;
5069
- };
5070
- "defaultSubject": {
5071
- "alias": "defaultSubject";
5072
- "required": false;
5073
- "isSignal": true;
5074
- };
5075
- "defaultBody": {
5076
- "alias": "defaultBody";
5077
- "required": false;
5078
- "isSignal": true;
5079
- };
5080
- "context": {
5081
- "alias": "context";
5082
- "required": false;
5083
- "isSignal": true;
5084
- };
5085
- "sendFn": {
5086
- "alias": "sendFn";
5087
- "required": false;
5088
- "isSignal": true;
5089
- };
5090
- "showReceiptOption": {
5091
- "alias": "showReceiptOption";
5092
- "required": false;
5093
- "isSignal": true;
5094
- };
5095
- "receiptLabel": {
5096
- "alias": "receiptLabel";
5097
- "required": false;
5098
- "isSignal": true;
5099
- };
5100
- "receiptDefault": {
5101
- "alias": "receiptDefault";
5102
- "required": false;
5103
- "isSignal": true;
5104
- };
5105
- "documents": {
5106
- "alias": "documents";
5107
- "required": false;
5108
- "isSignal": true;
5109
- };
5110
- "documentPurposes": {
5111
- "alias": "documentPurposes";
5112
- "required": false;
5113
- "isSignal": true;
5114
- };
5115
- "initialDocuments": {
5116
- "alias": "initialDocuments";
5117
- "required": false;
5118
- "isSignal": true;
5119
- };
5120
- "documentSigners": {
5121
- "alias": "documentSigners";
5122
- "required": false;
5123
- "isSignal": true;
5124
- };
5125
- "sendContext": {
5126
- "alias": "sendContext";
5127
- "required": false;
5128
- "isSignal": true;
5129
- };
5130
- "documentContextTypes": {
5131
- "alias": "documentContextTypes";
5132
- "required": false;
5133
- "isSignal": true;
5134
- };
5135
- "documentMergeCheck": {
5136
- "alias": "documentMergeCheck";
5137
- "required": false;
5138
- "isSignal": true;
5139
- };
5140
- "documentEnvelope": {
5141
- "alias": "documentEnvelope";
5142
- "required": false;
5143
- "isSignal": true;
5144
- };
5145
- "emailEnabled": {
5146
- "alias": "emailEnabled";
5147
- "required": false;
5148
- "isSignal": true;
5149
- };
5150
- "documentSentMessage": {
5151
- "alias": "documentSentMessage";
5152
- "required": false;
5153
- "isSignal": true;
5154
- };
5155
- "showCc": {
5156
- "alias": "showCc";
5157
- "required": false;
5158
- "isSignal": true;
5159
- };
5160
- "documentSigningOptions": {
5161
- "alias": "documentSigningOptions";
5162
- "required": false;
5163
- "isSignal": true;
5164
- };
5165
- "docuSignConnected": {
5166
- "alias": "docuSignConnected";
5167
- "required": false;
5168
- "isSignal": true;
5169
- };
5170
- "documentPreview": {
5171
- "alias": "documentPreview";
5172
- "required": false;
5173
- "isSignal": true;
5174
- };
5175
- "videoDefaults": {
5176
- "alias": "videoDefaults";
5177
- "required": false;
5178
- "isSignal": true;
5179
- };
5180
- "attachmentsAndScheduling": {
5181
- "alias": "attachmentsAndScheduling";
5182
- "required": false;
5183
- "isSignal": true;
5184
- };
5185
- }, {
5186
- "sent": "sent";
5187
- "emailAdded": "emailAdded";
5188
- "validChange": "validChange";
5189
- "rejected": "rejected";
5190
- "mapFieldsClick": "mapFieldsClick";
5191
- }, never, never, true, never>;
5192
- }
5193
- /** What the text form sends — the default `POST <baseUrl>/text-messages` body, or the host's `sendFn` argument. */
5194
- interface SendTextPayload {
5195
- contactName: string;
5196
- contactPhone: string;
5197
- body: string;
5198
- contactId?: string;
5199
- scheduledAt?: string;
5200
- mediaUrl?: string;
5201
- mediaType?: string;
5202
- mediaFileName?: string;
5203
- /** The template the message was made from (template mode only) — the backend counts it toward the template's Sent total. */
5204
- templateId?: string;
5205
- /** 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`. */
5206
- documents?: SendDocumentsPayload;
5207
- }
5208
- declare function formatPhone(raw: string | null | undefined): string;
5209
- declare class SendTextComponent implements OnInit {
5210
- protected readonly formatPhone: typeof formatPhone;
5211
- private readonly destroyRef;
5212
- private readonly http;
5213
- /** API root from FORGEROUTE_CONFIG (e.g. a cross-origin prod API); falls back to same-origin `/api`. */
5214
- private readonly apiBase;
5215
- private readonly toast;
5216
- readonly cdr: ChangeDetectorRef;
5217
- readonly contactName: import("@angular/core").InputSignal<string>;
5218
- readonly contactPhone: import("@angular/core").InputSignal<string>;
5219
- /** The contact's email — fills `{{email}}` (a blank email makes `{{email}}` a prompted field). */
5220
- readonly contactEmail: import("@angular/core").InputSignal<string>;
5221
- readonly contactId: import("@angular/core").InputSignal<string>;
5222
- /** Prefills Message in "Create Message" mode. */
5223
- readonly defaultBody: import("@angular/core").InputSignal<string>;
5224
- /** Extra merge variables (e.g. `estimate_number`) used in templates and the preview. */
5225
- readonly context: import("@angular/core").InputSignal<Record<string, string>>;
5226
- /**
5227
- * Sends through the host instead of `POST <baseUrl>/text-messages` — e.g. a page-specific endpoint that
5228
- * also marks a record Sent. Loading, toasts, `sent` and the double-send guard behave the same.
5229
- */
5230
- readonly sendFn: import("@angular/core").InputSignal<((payload: SendTextPayload) => Observable<unknown>) | null>;
5231
- /** Builds the success toast of a document send (default texts otherwise). */
5232
- readonly documentSentMessage: import("@angular/core").InputSignal<DocumentSentMessage | null>;
5233
- /** Shows the "Documents" section (search your documents; they are texted as a link). Off = the form is unchanged. */
5234
- readonly documents: import("@angular/core").InputSignal<boolean>;
5235
- /** false hides Attach Image and "Schedule for later" (for a host whose send function can't deliver them). */
5236
- readonly attachmentsAndScheduling: import("@angular/core").InputSignal<boolean>;
5237
- /** Purposes the app's backend supports for documents (default all). The text form only sends `ESIGN`; without it the section is unavailable. */
5238
- readonly documentPurposes: import("@angular/core").InputSignal<DocumentSendPurpose[]>;
5239
- /** Documents already chosen in the Documents section when the form opens. */
5240
- readonly initialDocuments: import("@angular/core").InputSignal<DocumentSeed[]>;
5241
- /**
5242
- * Turns on the signer logic for documents (informational documents, the multi-signer rule). A document with several customer signers
5243
- * 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.
5244
- */
5245
- readonly documentSigners: import("@angular/core").InputSignal<DocumentSignersConfig | null>;
5246
- /** Values the host has for THIS send; only the keys declared in `documentContextTypes` are sent, as `documents.context`. */
5247
- readonly sendContext: import("@angular/core").InputSignal<SendContext | null>;
5248
- /** The context keys the app's backend accepts. */
5249
- readonly documentContextTypes: import("@angular/core").InputSignal<ContextTypeDef[]>;
5250
- /** `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. */
5251
- readonly documentMergeCheck: import("@angular/core").InputSignal<boolean | MergeCheckFn>;
5252
- /** An existing envelope to text: its documents are fixed and it is sent (not created). Payload `documents.envelopeId`. */
5253
- readonly documentEnvelope: import("@angular/core").InputSignal<DocumentEnvelopeTarget | null>;
5254
- /** Shows "Expiry and Reminders" for the texted signing link (see `DocumentSigningOptions`); sent as `documents.expiryDays` / `reminderIntervalDays` / `maxReminders`. `null` = off. */
5255
- readonly documentSigningOptions: import("@angular/core").InputSignal<DocumentSigningOptions | null | undefined>;
5256
- /** "Preview Document" button(s) in the Documents section call this; `null` hides them. */
5257
- readonly documentPreview: import("@angular/core").InputSignal<DocumentPreviewHandler | null>;
5258
- /** The recipient handed to `documentPreview` (second argument): the panel's contact inputs, `null` while all four are blank. */
5259
- readonly previewContact: import("@angular/core").Signal<DocumentPreviewContact | null>;
5260
- /**
5261
- * Turns on the video settings (Playback, Call-to-Action, Hide reactions, Watch Preview, Remove Video) once a video is attached, starting
5262
- * from these defaults, and makes the video link carry them. `null` (default) = the plain share link is inserted, as before.
5263
- * A text is limited to 320 characters: a link with settings is longer, and Send stays off while the message is over the limit.
5264
- */
5265
- readonly videoDefaults: import("@angular/core").InputSignal<VideoDefaults | null>;
5266
- readonly sent: import("@angular/core").OutputEmitterRef<void>;
5267
- readonly phoneAdded: import("@angular/core").OutputEmitterRef<string>;
5268
- readonly validChange: import("@angular/core").OutputEmitterRef<boolean>;
5269
- /** A document send was refused because the document / envelope changed meanwhile (404 / 409): the host refreshes its list. */
5270
- readonly rejected: import("@angular/core").OutputEmitterRef<void>;
5271
- readonly MAX_LENGTH = 320;
5272
- mode: 'compose' | 'template';
5273
- body: string;
5274
- templateId: string | null;
5275
- previewFormat: 'preview' | 'raw';
5276
- previewingTemplate: {
5277
- subject: string | null;
5278
- body: string;
5279
- } | null;
5280
- showQuickPreview: boolean;
5281
- /** "View Send Preview" for the selected template. */
5282
- showSendPreview: boolean;
5283
- customVars: Record<string, string>;
5284
- pendingInputs: Record<string, string>;
5285
- loading: boolean;
5286
- showSchedule: boolean;
5287
- scheduledAt: string;
5288
- pendingPhone: string;
5289
- /** What the document section holds (null / empty = no documents) and whether it currently breaks a rule. */
5290
- documentsValue: DocumentSendValue | null;
5291
- documentsInvalid: boolean;
5292
- /** Lines of the merge check ("These fields will be left empty: …"). */
5293
- mergeWarnings: string[];
5294
- readonly mediaAttachment: import("@angular/core").WritableSignal<{
5295
- url: string;
5296
- mediaType: string;
5297
- mediaFileName: string;
5298
- sizeLabel: string;
5299
- } | null>;
5300
- readonly mediaUploading: import("@angular/core").WritableSignal<boolean>;
5301
- readonly savingPhone: import("@angular/core").WritableSignal<boolean>;
5302
- readonly modeTabs: PillTab[];
5303
- /** Market values (`area`, `median_price`, `dom`, `new_listings`) — only the ones `/service-areas` returned. */
5304
- private marketVars;
5305
- ngOnInit(): void;
5306
- /** Default last applied to compose mode — it only replaces text the user hasn't edited. */
5307
- private _appliedDefaultBody;
5308
- constructor();
5309
- setPreviewFormat(f: 'preview' | 'raw'): void;
5310
- get pendingPhoneValid(): boolean;
5311
- /** True when the sender chose at least one document (only possible when the `documents` input is on). */
5312
- get hasDocuments(): boolean;
5313
- /** The declared context keys with a value (`documents.context`). */
5314
- readonly forwardedContext: import("@angular/core").Signal<SendContext | undefined>;
5315
- /** The chosen documents the merge check looks at. */
5316
- get mergeDocuments(): DocumentOption[];
5317
- onMergeWarnings(lines: string[]): void;
5318
- /** The lines of the ONE warning banner: what choosing a document removed, the merge check. */
5319
- get warningLines(): {
5320
- key: string;
5321
- text: string;
5322
- testId: string | null;
5323
- }[];
5324
- /** Set when choosing the first document removed something the sender had already added - said out loud (aria-live), never silently. */
5325
- docsRemovedNote: string;
5326
- onDocumentsChange(v: DocumentSendValue): void;
5327
- onDocumentsInvalid(bad: boolean): void;
5328
- get canSend(): boolean;
5329
- get minScheduleTime(): string;
5330
- /**
5331
- * Values every tag can resolve from before the user types anything: the contact (name, first / last name, phone,
5332
- * email), the date, the market values `/service-areas` returned and the host's `context` — non-blank values only,
5333
- * later sources winning.
5334
- */
5335
- private get knownVars();
5336
- /** Merges `text` with every known value plus what the user typed — the ONE merge the pane, modal and payload use. */
5337
- resolveMergeTags(text: string): string;
5338
- /** Applied values plus anything typed into a missing-field input — so the preview updates as the user types. */
5339
- private get liveVars();
5340
- /** The body exactly as it will be sent (live: recomputed on every read, never cached). */
5341
- get resolvedBody(): string;
5342
- /** Template fields the user still has to fill — tags with no non-blank known value and nothing applied. */
5343
- get missingVars(): string[];
5344
- /** Why Send is off when the video link pushes the text over the SMS limit ('' otherwise). */
5345
- get videoLengthError(): string;
5346
- /** Compose mode: a `{{…}}` the form can't fill blocks sending (the server would refuse it). */
5347
- get composeTagError(): string;
5348
- /** Missing fields with nothing typed yet — Send stays disabled until this is empty. */
5349
- get unresolvedVars(): string[];
5350
- /**
5351
- * Applies every typed missing-field value (what the preview already shows) before sending. Never saves
5352
- * to the contact — only the explicit "+" / Enter apply does that.
5353
- */
5354
- private applyPendingVars;
5355
- formatVarLabel(key: string): string;
5356
- /** "View Send Preview": the selected template, merged exactly as it will be sent. */
5357
- openSendPreview(): void;
5358
- closeSendPreview(): void;
5359
- /** The picker's eye button: previews that template without selecting it. */
5360
- openQuickPreview(tpl: {
5361
- subject: string | null;
5362
- body: string;
5363
- }): void;
5364
- /** Applies a typed missing-field value. The explicit "+" / Enter apply (`persist`) also saves phone / address to the contact. */
5365
- applyVar(key: string, persist?: boolean): void;
5366
- clearTemplate(): void;
5367
- notifyValid(): void;
5368
- setMode(key: string): void;
5369
- savePhone(): void;
5370
- onTemplateSelected(tpl: TemplateItem): void;
5371
- onFileSelected(event: Event): void;
5372
- removeMedia(): void;
5373
- insertVideo(v: VideoMessage): void;
5374
- /** The video attached through the settings flow (null = none) and the line it put into the message. */
5375
- videoPicked: VideoMessage | null;
5376
- /** Bumped to re-create the video picker (it keeps its own selection and has no clear output). */
5377
- videoPickerKey: number;
5378
- private _videoLine;
5379
- /** The picker's output: with `videoDefaults` the video gets its settings section, otherwise the plain link is inserted as before. */
5380
- onVideoSelected(v: VideoMessage): void;
5381
- /** The settings section's output: rewrites the video line of the message with the current link (the rest of the message is untouched). */
5382
- onVideoLink(link: string): void;
5383
- /** "Remove Video": takes the video line out of the message and brings the picker back. */
5384
- removeVideo(): void;
5385
- private discardVideo;
5386
- submit(): void;
5387
- static ɵfac: i0.ɵɵFactoryDeclaration<SendTextComponent, never>;
5388
- static ɵcmp: i0.ɵɵComponentDeclaration<SendTextComponent, "ui-send-text", never, {
5389
- "contactName": {
5390
- "alias": "contactName";
5391
- "required": false;
5392
- "isSignal": true;
5393
- };
5394
- "contactPhone": {
5395
- "alias": "contactPhone";
5396
- "required": false;
5397
- "isSignal": true;
5398
- };
5399
- "contactEmail": {
5400
- "alias": "contactEmail";
5401
- "required": false;
5402
- "isSignal": true;
5403
- };
5404
- "contactId": {
5405
- "alias": "contactId";
5406
- "required": false;
5407
- "isSignal": true;
5408
- };
5409
- "defaultBody": {
5410
- "alias": "defaultBody";
5411
- "required": false;
5412
- "isSignal": true;
5413
- };
5414
- "context": {
5415
- "alias": "context";
5416
- "required": false;
5417
- "isSignal": true;
5418
- };
5419
- "sendFn": {
5420
- "alias": "sendFn";
5421
- "required": false;
5422
- "isSignal": true;
5423
- };
5424
- "documentSentMessage": {
5425
- "alias": "documentSentMessage";
5426
- "required": false;
5427
- "isSignal": true;
5428
- };
5429
- "documents": {
5430
- "alias": "documents";
5431
- "required": false;
5432
- "isSignal": true;
5433
- };
5434
- "attachmentsAndScheduling": {
5435
- "alias": "attachmentsAndScheduling";
5436
- "required": false;
5437
- "isSignal": true;
5438
- };
5439
- "documentPurposes": {
5440
- "alias": "documentPurposes";
5441
- "required": false;
5442
- "isSignal": true;
5443
- };
5444
- "initialDocuments": {
5445
- "alias": "initialDocuments";
5446
- "required": false;
5447
- "isSignal": true;
5448
- };
5449
- "documentSigners": {
5450
- "alias": "documentSigners";
5451
- "required": false;
5452
- "isSignal": true;
5453
- };
5454
- "sendContext": {
5455
- "alias": "sendContext";
5456
- "required": false;
5457
- "isSignal": true;
5458
- };
5459
- "documentContextTypes": {
5460
- "alias": "documentContextTypes";
5461
- "required": false;
5462
- "isSignal": true;
5463
- };
5464
- "documentMergeCheck": {
5465
- "alias": "documentMergeCheck";
5466
- "required": false;
5467
- "isSignal": true;
5468
- };
5469
- "documentEnvelope": {
5470
- "alias": "documentEnvelope";
5471
- "required": false;
5472
- "isSignal": true;
5473
- };
5474
- "documentSigningOptions": {
5475
- "alias": "documentSigningOptions";
5476
- "required": false;
5477
- "isSignal": true;
5478
- };
5479
- "documentPreview": {
5480
- "alias": "documentPreview";
5481
- "required": false;
5482
- "isSignal": true;
5483
- };
5484
- "videoDefaults": {
5485
- "alias": "videoDefaults";
5486
- "required": false;
5487
- "isSignal": true;
5488
- };
5489
- }, {
5490
- "sent": "sent";
5491
- "phoneAdded": "phoneAdded";
5492
- "validChange": "validChange";
5493
- "rejected": "rejected";
5494
- }, never, never, true, never>;
5495
- }
5496
- /** One match of the host's `jobSearch` function; `description` is the small second line (e.g. the customer). */
5497
- export interface JobSearchResult {
5498
- id: string;
5499
- name: string;
5500
- description?: string | null;
5501
- }
5502
- export interface MessageContact {
5503
- id: string;
5504
- name: string;
5505
- email?: string | null;
5506
- phone?: string | null;
5507
- smsOptedIn?: boolean | null;
5508
- }
5509
- export declare class SendMessagePanelComponent {
5510
- readonly open: import("@angular/core").InputSignal<boolean>;
5511
- readonly contact: import("@angular/core").InputSignal<MessageContact | null>;
5512
- readonly loading: import("@angular/core").InputSignal<boolean>;
5513
- /** Pass true when Twilio / SMS is enabled in the consuming app's settings. */
5514
- readonly textEnabled: import("@angular/core").InputSignal<boolean>;
5515
- /** Panel header. */
5516
- readonly title: import("@angular/core").InputSignal<string>;
5517
- /** Prefill for the email Subject / Message and the text Message in "Create Message" mode. */
5518
- readonly defaultSubject: import("@angular/core").InputSignal<string>;
5519
- readonly defaultBody: import("@angular/core").InputSignal<string>;
5520
- readonly defaultMessage: import("@angular/core").InputSignal<string>;
5521
- /** Extra merge variables (e.g. `estimate_number`, `estimate_total`) for templates and the preview. */
5522
- readonly context: import("@angular/core").InputSignal<Record<string, string>>;
5523
- /**
5524
- * Page-specific sending: when set, the email / text form calls this instead of POSTing to the default
5525
- * `/email-messages` / `/text-messages` endpoint (e.g. an endpoint that also marks an estimate Sent).
5526
- */
5527
- readonly sendEmail: import("@angular/core").InputSignal<((payload: SendEmailPayload) => Observable<unknown>) | null>;
5528
- readonly sendText: import("@angular/core").InputSignal<((payload: SendTextPayload) => Observable<unknown>) | null>;
5529
- /** Email tab only: shows an "include receipt" checkbox; the choice is sent as `SendEmailPayload.includeReceipt`. */
5530
- readonly showReceiptOption: import("@angular/core").InputSignal<boolean>;
5531
- readonly receiptLabel: import("@angular/core").InputSignal<string>;
5532
- readonly receiptDefault: import("@angular/core").InputSignal<boolean>;
5533
- /**
5534
- * Adds a "Documents" section to the email and text forms: the sender searches the company's documents and sends them
5535
- * with the message (e-signature link, attachment or both on email; a link on text). Needs the standard documents routes —
5536
- * see docs/send-documents-contract.md. Off (default) = both forms are exactly as before.
5537
- */
5538
- readonly documents: import("@angular/core").InputSignal<boolean>;
5539
- /** Pass false for a user who may not send documents (e.g. read-only): the Documents section is hidden even when `documents` is on. */
5540
- readonly documentsEnabled: import("@angular/core").InputSignal<boolean>;
5541
- /** Email tab only: adds a CC field; the addresses are sent as `SendEmailPayload.cc`. */
5542
- readonly showCc: import("@angular/core").InputSignal<boolean>;
5543
- /** false hides Attach Files / Attach Image and "Schedule for later" in both forms (a host `sendEmail` / `sendText` that can't deliver them). */
5544
- readonly attachmentsAndScheduling: import("@angular/core").InputSignal<boolean>;
5545
- /** Purposes the app's backend supports for documents (default all three); `['ESIGN']` hides the purpose select. */
5546
- readonly documentPurposes: import("@angular/core").InputSignal<DocumentSendPurpose[]>;
5547
- /** Documents already chosen when the panel opens (e.g. the row "Send Document" was clicked on); the user can change them. */
5548
- readonly initialDocuments: import("@angular/core").InputSignal<DocumentSeed[]>;
5549
- /**
5550
- * Turns on the signer logic of the Documents section (docs/send-documents-contract.md, Addendum 2026-10-19), all off when `null` (default):
5551
- * - a document with MORE THAN ONE customer signer shows one required contact picker per further role (Signer 1 is the recipient), Send
5552
- * stays off until every role has a contact, and `documents.signers` (complete, ordered by role) is added to the payload;
5553
- * - a document that requires the sender's countersignature shows one read-only line ("Countersigned by <name> after all signers.");
5554
- * - a document with no signature fields (`signerRoles: []`) is informational: no signers, countersign line, DocuSign or signing options -
5555
- * the recipient gets a view link;
5556
- * - DocuSign is offered only for a signed document with one customer signer, and the countersign checkbox is replaced by the document's setting.
5557
- * The roles come from the `GET /documents` row (`signerRoles`) or from `resolveRoles`. A multi-signer document can't be texted.
5558
- */
5559
- readonly documentSigners: import("@angular/core").InputSignal<DocumentSignersConfig | null>;
5560
- /** Values the host has for THIS send (e.g. `{ propertyId }`); only keys listed in `documentContextTypes` are sent, as `documents.context`. */
5561
- readonly sendContext: import("@angular/core").InputSignal<SendContext | null>;
5562
- /** The context keys the app's backend accepts. */
5563
- readonly documentContextTypes: import("@angular/core").InputSignal<ContextTypeDef[]>;
5564
- /**
5565
- * The pre-send "fields that will be empty" check, for documents with mapped data fields only (non-blocking warning): `true` = default route
5566
- * `POST <baseUrl>/documents/merge-check`, a function = your own call, `false` (default) = off.
5567
- */
5568
- readonly documentMergeCheck: import("@angular/core").InputSignal<boolean | MergeCheckFn>;
5569
- /**
5570
- * Sends an EXISTING envelope: its documents are fixed (no search, no remove), the recipient is chosen in the panel, and the request is sent
5571
- * (`POST <baseUrl>/documents/envelopes/{id}/send`, or your `sendEmail` / `sendText` with `documents.envelopeId`) instead of created.
5572
- * Turns the Documents section on by itself. `null` (default) = a new request from the chosen documents.
5573
- */
5574
- readonly documentEnvelope: import("@angular/core").InputSignal<DocumentEnvelopeTarget | null>;
5575
- /** Builds the success toast of a document send (`"<title>" sent for signature`, `Envelope "<name>" sent` …); the default texts apply when unset. */
5576
- readonly documentSentMessage: import("@angular/core").InputSignal<DocumentSentMessage | null>;
5577
- /** false = the app's email sending is switched off (Communication settings): the Email tab says so and Send stays off. Default true. */
5578
- readonly emailEnabled: import("@angular/core").InputSignal<boolean>;
5579
- /** The footer button text instead of `Send Email` / `Send Text` (e.g. `Send Document`, `Send Envelope`). */
5580
- readonly sendLabel: import("@angular/core").InputSignal<string>;
5581
- /** The 620px wide panel (a long form with signers). Default false. */
5582
- readonly wide: import("@angular/core").InputSignal<boolean>;
5583
- /**
5584
- * Shows "Expiry and Reminders" in the Documents section (Expiry 1-90 days, Reminder Interval 1-30 days, Max Reminders 0-10; required
5585
- * whole numbers) for native e-signature requests, on the Email tab (purpose e-signature or both) and the Text tab. Pass `{}` for the
5586
- * defaults 7 / 2 / 3 or set any of `expiryDays`, `reminderIntervalDays`, `maxReminders`. The values are sent as
5587
- * `documents.expiryDays` / `reminderIntervalDays` / `maxReminders`. `null` (default) = not shown, nothing sent.
5588
- */
5589
- readonly documentSigningOptions: import("@angular/core").InputSignal<DocumentSigningOptions | null | undefined>;
5590
- /**
5591
- * Email tab: the host says DocuSign is connected (the library never calls `/docusign/status`). Offers "Native E-Sign / Send via DocuSign"
5592
- * while exactly one document is chosen; DocuSign sends through `POST <baseUrl>/docusign/send` (or your `sendEmail`, which then gets
5593
- * `documents.provider === 'DOCUSIGN'`). A document row/`initialDocuments` entry with `requiresCountersign: true` also offers "Require my
5594
- * countersignature after client signs". Default `false` = native only.
5595
- */
5596
- readonly docuSignConnected: import("@angular/core").InputSignal<boolean>;
5597
- /**
5598
- * "Preview Document" in the Documents section: called with the chosen document when its button is clicked. The library has no route
5599
- * of its own — the host opens its viewer. Open a tab synchronously inside this function (Safari blocks `window.open` after an await).
5600
- * `null` (default) = no preview button.
5601
- */
5602
- readonly documentPreview: import("@angular/core").InputSignal<DocumentPreviewHandler | null>;
5603
- /**
5604
- * The "Video" section (always the last section of the Email and Text forms): once a video is attached it shows Playback, Call-to-Action
5605
- * (+ URL / label), Hide reactions, Watch Preview and Remove Video, starting from these defaults (your Communication settings), and the
5606
- * link in the message carries them (`buildVideoLink`). `null` (default) = the plain share link is inserted, with no settings.
5607
- */
5608
- readonly videoDefaults: import("@angular/core").InputSignal<VideoDefaults | null>;
5609
- /** The Documents section is shown only when the host turned it on AND the user may send documents. */
5610
- protected readonly documentsOn: import("@angular/core").Signal<boolean>;
5611
- /**
5612
- * Shows an optional "Job" search under the contact (off by default): the sender may link the message to one of the
5613
- * company's jobs (found with the host's `jobSearch` function). The pick is reported through `jobSelected`; it is cleared whenever the
5614
- * panel opens or another contact is chosen. The panel itself sends nothing about it — the host's `sendEmail` / `sendText`
5615
- * function adds it to its request.
5616
- */
5617
- readonly showJobPicker: import("@angular/core").InputSignal<boolean>;
5618
- readonly jobLabel: import("@angular/core").InputSignal<string>;
5619
- readonly jobHint: import("@angular/core").InputSignal<string>;
5620
- /**
5621
- * Looks jobs up for the Job field (the panel knows nothing about the app's API): called with the typed text (2+ characters,
5622
- * debounced); returns the matches. Required for `showJobPicker` to find anything.
5623
- */
5624
- readonly jobSearch: import("@angular/core").InputSignal<((query: string) => Observable<JobSearchResult[]>) | null>;
5625
- readonly jobSelected: import("@angular/core").OutputEmitterRef<{
5626
- id: string;
5627
- name: string;
5628
- } | null>;
5629
- readonly closed: import("@angular/core").OutputEmitterRef<void>;
5630
- readonly sent: import("@angular/core").OutputEmitterRef<void>;
5631
- readonly emailAdded: import("@angular/core").OutputEmitterRef<string>;
5632
- /** A document / envelope send was refused because it changed meanwhile (404 / 409): the host refreshes its list. */
5633
- readonly rejected: import("@angular/core").OutputEmitterRef<void>;
5634
- /**
5635
- * With `documentSigners` on: the user clicked "Place your countersignature box" under the countersign line of a document that requires a
5636
- * countersignature but whose row says `hasCountersignPlacement: false` (docs/send-documents-contract.md, Addendum 2026-10-19 (b)).
5637
- * Payload = that document `{ id, title }`; the host navigates to Map Data Fields. Never emitted when the flag is true / absent.
5638
- */
5639
- readonly mapFieldsClick: import("@angular/core").OutputEmitterRef<{
5640
- id: string;
5641
- title: string;
5642
- }>;
5643
- readonly phoneAdded: import("@angular/core").OutputEmitterRef<string>;
5644
- readonly sendEmailRef: import("@angular/core").Signal<SendEmailComponent | undefined>;
5645
- readonly sendTextRef: import("@angular/core").Signal<SendTextComponent | undefined>;
5646
- private readonly destroyRef;
5647
- readonly jobSearch$: Subject<string>;
5648
- readonly jobOptions: import("@angular/core").WritableSignal<ComboboxOption<unknown>[]>;
5649
- readonly jobLoading: import("@angular/core").WritableSignal<boolean>;
5650
- private readonly pickedJob;
5651
- readonly jobValue: import("@angular/core").Signal<ComboboxSelection | null>;
5652
- onJobPick(o: ComboboxOption | null): void;
5653
- /** A new form (fresh open / another contact) starts without a linked job. */
5654
- private resetJob;
5655
- readonly activeContact: import("@angular/core").WritableSignal<MessageContact | null>;
5656
- /** What the sender should know about the picked contact before sending (why a channel is missing, what to add). */
5657
- readonly contactNotices: import("@angular/core").Signal<string[]>;
5658
- readonly channel: import("@angular/core").WritableSignal<"text" | "email">;
5659
- readonly valid: import("@angular/core").WritableSignal<boolean>;
5660
- /** Bumped on every fresh open / new contact — re-creates the email and text forms so no draft carries over. */
5661
- readonly formEpoch: import("@angular/core").WritableSignal<number>;
5662
- private _prevOpen;
5663
- constructor();
5664
- onContactSelected(c: ContactLookup | null): void;
5665
- onChannelChange(ch: 'email' | 'text'): void;
5666
- onEmailAdded(email: string): void;
5667
- onPhoneAdded(phone: string): void;
5668
- submit(): void;
5669
- onSent(): void;
5670
- onClose(): void;
5671
- static ɵfac: i0.ɵɵFactoryDeclaration<SendMessagePanelComponent, never>;
5672
- static ɵcmp: i0.ɵɵComponentDeclaration<SendMessagePanelComponent, "ui-send-message-panel", never, {
5673
- "open": {
5674
- "alias": "open";
5675
- "required": false;
5676
- "isSignal": true;
5677
- };
5678
- "contact": {
5679
- "alias": "contact";
5680
- "required": false;
5681
- "isSignal": true;
5682
- };
5683
- "loading": {
5684
- "alias": "loading";
5685
- "required": false;
5686
- "isSignal": true;
5687
- };
5688
- "textEnabled": {
5689
- "alias": "textEnabled";
5690
- "required": false;
5691
- "isSignal": true;
5692
- };
5693
- "title": {
5694
- "alias": "title";
5695
- "required": false;
5696
- "isSignal": true;
5697
- };
5698
- "defaultSubject": {
5699
- "alias": "defaultSubject";
5700
- "required": false;
5701
- "isSignal": true;
5702
- };
5703
- "defaultBody": {
5704
- "alias": "defaultBody";
5705
- "required": false;
5706
- "isSignal": true;
5707
- };
5708
- "defaultMessage": {
5709
- "alias": "defaultMessage";
5710
- "required": false;
5711
- "isSignal": true;
5712
- };
5713
- "context": {
5714
- "alias": "context";
5715
- "required": false;
5716
- "isSignal": true;
5717
- };
5718
- "sendEmail": {
5719
- "alias": "sendEmail";
5720
- "required": false;
5721
- "isSignal": true;
5722
- };
5723
- "sendText": {
5724
- "alias": "sendText";
5725
- "required": false;
5726
- "isSignal": true;
5727
- };
5728
- "showReceiptOption": {
5729
- "alias": "showReceiptOption";
5730
- "required": false;
5731
- "isSignal": true;
5732
- };
5733
- "receiptLabel": {
5734
- "alias": "receiptLabel";
5735
- "required": false;
5736
- "isSignal": true;
5737
- };
5738
- "receiptDefault": {
5739
- "alias": "receiptDefault";
5740
- "required": false;
5741
- "isSignal": true;
5742
- };
5743
- "documents": {
5744
- "alias": "documents";
5745
- "required": false;
5746
- "isSignal": true;
5747
- };
5748
- "documentsEnabled": {
5749
- "alias": "documentsEnabled";
5750
- "required": false;
5751
- "isSignal": true;
5752
- };
5753
- "showCc": {
5754
- "alias": "showCc";
5755
- "required": false;
5756
- "isSignal": true;
5757
- };
5758
- "attachmentsAndScheduling": {
5759
- "alias": "attachmentsAndScheduling";
5760
- "required": false;
5761
- "isSignal": true;
5762
- };
5763
- "documentPurposes": {
5764
- "alias": "documentPurposes";
5765
- "required": false;
5766
- "isSignal": true;
5767
- };
5768
- "initialDocuments": {
5769
- "alias": "initialDocuments";
5770
- "required": false;
5771
- "isSignal": true;
5772
- };
5773
- "documentSigners": {
5774
- "alias": "documentSigners";
5775
- "required": false;
5776
- "isSignal": true;
5777
- };
5778
- "sendContext": {
5779
- "alias": "sendContext";
5780
- "required": false;
5781
- "isSignal": true;
5782
- };
5783
- "documentContextTypes": {
5784
- "alias": "documentContextTypes";
5785
- "required": false;
5786
- "isSignal": true;
5787
- };
5788
- "documentMergeCheck": {
5789
- "alias": "documentMergeCheck";
5790
- "required": false;
5791
- "isSignal": true;
5792
- };
5793
- "documentEnvelope": {
5794
- "alias": "documentEnvelope";
5795
- "required": false;
5796
- "isSignal": true;
5797
- };
5798
- "documentSentMessage": {
5799
- "alias": "documentSentMessage";
5800
- "required": false;
5801
- "isSignal": true;
5802
- };
5803
- "emailEnabled": {
5804
- "alias": "emailEnabled";
5805
- "required": false;
5806
- "isSignal": true;
5807
- };
5808
- "sendLabel": {
5809
- "alias": "sendLabel";
5810
- "required": false;
5811
- "isSignal": true;
5812
- };
5813
- "wide": {
5814
- "alias": "wide";
5815
- "required": false;
5816
- "isSignal": true;
5817
- };
5818
- "documentSigningOptions": {
5819
- "alias": "documentSigningOptions";
5820
- "required": false;
5821
- "isSignal": true;
5822
- };
5823
- "docuSignConnected": {
5824
- "alias": "docuSignConnected";
5825
- "required": false;
5826
- "isSignal": true;
5827
- };
5828
- "documentPreview": {
5829
- "alias": "documentPreview";
5830
- "required": false;
5831
- "isSignal": true;
5832
- };
5833
- "videoDefaults": {
5834
- "alias": "videoDefaults";
5835
- "required": false;
5836
- "isSignal": true;
5837
- };
5838
- "showJobPicker": {
5839
- "alias": "showJobPicker";
5840
- "required": false;
5841
- "isSignal": true;
5842
- };
5843
- "jobLabel": {
5844
- "alias": "jobLabel";
5845
- "required": false;
5846
- "isSignal": true;
5847
- };
5848
- "jobHint": {
5849
- "alias": "jobHint";
5850
- "required": false;
5851
- "isSignal": true;
5852
- };
5853
- "jobSearch": {
5854
- "alias": "jobSearch";
5855
- "required": false;
5856
- "isSignal": true;
5857
- };
5858
- }, {
5859
- "jobSelected": "jobSelected";
5860
- "closed": "closed";
5861
- "sent": "sent";
5862
- "emailAdded": "emailAdded";
5863
- "rejected": "rejected";
5864
- "mapFieldsClick": "mapFieldsClick";
5865
- "phoneAdded": "phoneAdded";
5866
- }, never, never, true, never>;
5867
- }
5868
- /**
5869
- * ui-document-signers — the signer section of a document send: one required contact per customer signer role of the chosen document
5870
- * (Signer 1 is the recipient, shown read-only) in signing order, and the one read-only countersign line.
5871
- *
5872
- * Internal child of the message forms (`ui-send-message-panel` with `documentSigners`); hosts do not place it. Rows exist only for a
5873
- * document with MORE THAN ONE customer signer; a single-signer document shows nothing here except the countersign line. It emits the
5874
- * complete `signers` list (never a partial one: `null` until every role has a contact) and its validity (`UiFieldValidity`):
5875
- * a missing contact is `<Role label> is required.`, a contact without an email `<Name> has no email address.`, the same person in two
5876
- * roles `<Name> is already <Role label>.` (unless the config allows it).
5877
- */
5878
- export declare class DocumentSignersComponent implements UiFieldValidity {
5879
- /** The signer logic's conclusion for the chosen document(s) (`ui-document-send-options` value `signerInfo`). */
5880
- readonly info: import("@angular/core").InputSignal<DocumentSignerInfo | null>;
5881
- readonly config: import("@angular/core").InputSignal<DocumentSignersConfig | null>;
5882
- /** The recipient of the message = Signer 1. */
5883
- readonly recipient: import("@angular/core").InputSignal<SignerPick>;
5884
- /** Shows the "<Role> is required." messages now (otherwise after the first blur). */
5885
- readonly showErrors: import("@angular/core").InputSignal<boolean>;
5886
- /** The sender chose DocuSign: only the countersign line applies. */
5887
- readonly viaDocuSign: import("@angular/core").InputSignal<boolean>;
5888
- /** The complete signer list (recipient first) or null while a role has no contact. Emitted on every change. */
5889
- readonly signersChange: import("@angular/core").OutputEmitterRef<SendSigner[] | null>;
5890
- readonly invalidChange: import("@angular/core").OutputEmitterRef<boolean>;
5891
- /** The "Place your countersignature box" link was clicked: the document whose countersign box is not placed (the host opens Map Data Fields). */
5892
- readonly mapFieldsClick: import("@angular/core").OutputEmitterRef<{
5893
- id: string;
5894
- title: string;
5895
- }>;
5896
- readonly picks: import("@angular/core").WritableSignal<Partial<Record<SignerRole, ContactLookup | null>>>;
5897
- protected readonly rowsShown: import("@angular/core").Signal<boolean>;
5898
- protected readonly line: import("@angular/core").Signal<string>;
5899
- /** Documents the "place your box" link is offered for: native send only (DocuSign places its own fields) and only while the countersign line shows. */
5900
- protected readonly placeDocs: import("@angular/core").Signal<{
5901
- id: string;
5902
- title: string;
5903
- }[]>;
5904
- readonly problems: import("@angular/core").Signal<Partial<Record<SignerRole, string>>>;
5905
- readonly signers: import("@angular/core").Signal<SendSigner[] | null>;
5906
- readonly errorMessage: import("@angular/core").Signal<string>;
5907
- readonly invalid: import("@angular/core").Signal<boolean>;
5908
- constructor();
5909
- protected placeLabel(title: string): string;
5910
- /** Visible text: with several documents the title is part of it (label-in-name: it contains the start of the accessible name). */
5911
- protected placeText(title: string): string;
5912
- protected label(role: SignerRole): string;
5913
- /** Under a picker: the problems of a chosen contact (no email / same person twice); the empty-row message is the picker's own (`visibleErrorMessage`). */
5914
- protected visibleProblem(role: SignerRole): string;
5915
- pick(role: SignerRole, c: ContactLookup | null): void;
5916
- static ɵfac: i0.ɵɵFactoryDeclaration<DocumentSignersComponent, never>;
5917
- static ɵcmp: i0.ɵɵComponentDeclaration<DocumentSignersComponent, "ui-document-signers", never, {
5918
- "info": {
5919
- "alias": "info";
5920
- "required": false;
5921
- "isSignal": true;
5922
- };
5923
- "config": {
5924
- "alias": "config";
5925
- "required": false;
5926
- "isSignal": true;
5927
- };
5928
- "recipient": {
5929
- "alias": "recipient";
5930
- "required": false;
5931
- "isSignal": true;
5932
- };
5933
- "showErrors": {
5934
- "alias": "showErrors";
5935
- "required": false;
5936
- "isSignal": true;
5937
- };
5938
- "viaDocuSign": {
5939
- "alias": "viaDocuSign";
5940
- "required": false;
5941
- "isSignal": true;
5942
- };
5943
- }, {
5944
- "signersChange": "signersChange";
5945
- "invalidChange": "invalidChange";
5946
- "mapFieldsClick": "mapFieldsClick";
5947
- }, never, never, true, never>;
5948
- }
5949
- /** Quiet time after the last change before the check is requested. */
5950
- export declare const MERGE_CHECK_DEBOUNCE_MS = 300;
5951
- /**
5952
- * ui-document-merge-check — the pre-send "fields that will be empty" check (non-blocking), logic only (it renders nothing).
5953
- *
5954
- * Internal child of the message forms. While `enabled` is `true` (default route `POST <baseUrl>/documents/merge-check`) or a host
5955
- * function, and at least one chosen document has mapped data fields, it asks which data fields would be left empty for this recipient,
5956
- * these signers and this context, and emits the warning lines (`warningsChange`). Debounced, a newer request cancels an older one
5957
- * (`switchMap`), never cached. A failed or slow check emits no warning and never blocks Send. Documents with no mapped data fields
5958
- * are not sent to the check.
5959
- */
5960
- export declare class DocumentMergeCheckComponent {
5961
- private readonly http;
5962
- private readonly destroyRef;
5963
- private readonly apiBase;
5964
- /** `true` = the default route, a function = the host's own call, `false` / `null` = off. */
5965
- readonly enabled: import("@angular/core").InputSignal<boolean | MergeCheckFn | null>;
5966
- readonly documents: import("@angular/core").InputSignal<SignerDocLike[]>;
5967
- readonly customerId: import("@angular/core").InputSignal<string>;
5968
- readonly signers: import("@angular/core").InputSignal<SendSigner[] | null>;
5969
- readonly context: import("@angular/core").InputSignal<SendContext | undefined>;
5970
- /** The warning lines (empty = nothing to warn about). Emitted whenever they change. */
5971
- readonly warningsChange: import("@angular/core").OutputEmitterRef<string[]>;
5972
- private readonly request;
5973
- constructor();
5974
- private lastLines;
5975
- private call;
5976
- static ɵfac: i0.ɵɵFactoryDeclaration<DocumentMergeCheckComponent, never>;
5977
- static ɵcmp: i0.ɵɵComponentDeclaration<DocumentMergeCheckComponent, "ui-document-merge-check", never, {
5978
- "enabled": {
5979
- "alias": "enabled";
3561
+ "errorId": {
3562
+ "alias": "errorId";
3563
+ "required": false;
3564
+ "isSignal": true;
3565
+ };
3566
+ "invalid": {
3567
+ "alias": "invalid";
3568
+ "required": false;
3569
+ "isSignal": true;
3570
+ };
3571
+ "showErrors": {
3572
+ "alias": "showErrors";
5980
3573
  "required": false;
5981
3574
  "isSignal": true;
5982
3575
  };
5983
- "documents": {
5984
- "alias": "documents";
3576
+ "showDetails": {
3577
+ "alias": "showDetails";
5985
3578
  "required": false;
5986
3579
  "isSignal": true;
5987
3580
  };
5988
- "customerId": {
5989
- "alias": "customerId";
3581
+ "isMultiSelect": {
3582
+ "alias": "isMultiSelect";
5990
3583
  "required": false;
5991
3584
  "isSignal": true;
5992
3585
  };
5993
- "signers": {
5994
- "alias": "signers";
3586
+ "showChips": {
3587
+ "alias": "showChips";
5995
3588
  "required": false;
5996
3589
  "isSignal": true;
5997
3590
  };
5998
- "context": {
5999
- "alias": "context";
3591
+ "initialContact": {
3592
+ "alias": "initialContact";
6000
3593
  "required": false;
6001
3594
  "isSignal": true;
6002
3595
  };
6003
3596
  }, {
6004
- "warningsChange": "warningsChange";
3597
+ "contactSelected": "contactSelected";
3598
+ "contactsSelected": "contactsSelected";
3599
+ "invalidChange": "invalidChange";
6005
3600
  }, never, never, true, never>;
6006
3601
  }
6007
3602
  export interface BulkMessageContact {
@@ -6883,60 +4478,353 @@ export declare class DateInputComponent implements ControlValueAccessor, Validat
6883
4478
  export declare class DatetimeInputComponent implements ControlValueAccessor, Validator, UiFieldValidity {
6884
4479
  readonly label: import("@angular/core").InputSignal<string>;
6885
4480
  readonly required: import("@angular/core").InputSignal<boolean>;
6886
- readonly min: import("@angular/core").InputSignal<string>;
6887
- 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>;
6888
4721
  readonly hint: import("@angular/core").InputSignal<string>;
4722
+ /** Host error message; always wins over the built-in message. */
6889
4723
  readonly error: import("@angular/core").InputSignal<string>;
6890
- /** Reveal the built-in error messages now (e.g. after a failed Save click), without waiting for blur. */
6891
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>;
6892
4746
  protected readonly _disabledInput: import("@angular/core").InputSignal<boolean>;
6893
4747
  private readonly _cvaDisabled;
6894
4748
  protected readonly disabled: import("@angular/core").Signal<boolean>;
6895
- 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;
6896
4764
  private readonly _reveal;
6897
4765
  private readonly _issue;
6898
- /** True while the value breaks a built-in rule or the host passed an `[error]`. */
6899
4766
  readonly invalid: import("@angular/core").Signal<boolean>;
6900
- /** Message of the first broken built-in rule ('' when valid), shown or not. */
6901
4767
  readonly errorMessage: import("@angular/core").Signal<string>;
6902
- /** Emits whenever the field becomes invalid / valid. */
6903
- readonly invalidChange: import("@angular/core").OutputEmitterRef<boolean>;
6904
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;
6905
4778
  private _onValidatorChange;
6906
4779
  constructor();
6907
- /** Re-run the form control's validation when a rule input (required, maxlength, min, options, ...) changes. */
6908
4780
  ngOnChanges(): void;
4781
+ writeValue(val: ComboboxSelection | null): void;
6909
4782
  validate(control: AbstractControl): ValidationErrors | null;
6910
4783
  registerOnValidatorChange(fn: () => void): void;
6911
- protected readonly _inputId: string;
6912
- private _onChange;
6913
- private _onTouched;
6914
- writeValue(val: string): void;
6915
- registerOnChange(fn: (v: string) => void): void;
4784
+ registerOnChange(fn: (v: ComboboxSelection | null) => void): void;
6916
4785
  registerOnTouched(fn: () => void): void;
6917
4786
  setDisabledState(d: boolean): void;
6918
- protected onChange(event: Event): void;
6919
- protected onBlur(): void;
6920
4787
  private _check;
6921
- static ɵfac: i0.ɵɵFactoryDeclaration<DatetimeInputComponent, never>;
6922
- 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, {
6923
4811
  "label": {
6924
4812
  "alias": "label";
6925
4813
  "required": false;
6926
4814
  "isSignal": true;
6927
4815
  };
6928
- "required": {
6929
- "alias": "required";
4816
+ "ariaLabel": {
4817
+ "alias": "ariaLabel";
6930
4818
  "required": false;
6931
4819
  "isSignal": true;
6932
4820
  };
6933
- "min": {
6934
- "alias": "min";
4821
+ "placeholder": {
4822
+ "alias": "placeholder";
6935
4823
  "required": false;
6936
4824
  "isSignal": true;
6937
4825
  };
6938
- "max": {
6939
- "alias": "max";
4826
+ "required": {
4827
+ "alias": "required";
6940
4828
  "required": false;
6941
4829
  "isSignal": true;
6942
4830
  };
@@ -6955,94 +4843,43 @@ export declare class DatetimeInputComponent implements ControlValueAccessor, Val
6955
4843
  "required": false;
6956
4844
  "isSignal": true;
6957
4845
  };
6958
- "_disabledInput": {
6959
- "alias": "disabled";
6960
- "required": false;
6961
- "isSignal": true;
6962
- };
6963
- }, {
6964
- "invalidChange": "invalidChange";
6965
- }, never, never, true, never>;
6966
- }
6967
- export declare class TimeInputComponent implements ControlValueAccessor, Validator, UiFieldValidity {
6968
- readonly label: import("@angular/core").InputSignal<string>;
6969
- /** Accessible name when there is no visible `label` (falls back to `label`). */
6970
- readonly ariaLabel: import("@angular/core").InputSignal<string>;
6971
- readonly required: import("@angular/core").InputSignal<boolean>;
6972
- readonly min: import("@angular/core").InputSignal<string>;
6973
- readonly max: import("@angular/core").InputSignal<string>;
6974
- readonly hint: import("@angular/core").InputSignal<string>;
6975
- readonly error: import("@angular/core").InputSignal<string>;
6976
- /** Reveal the built-in error messages now (e.g. after a failed Save click), without waiting for blur. */
6977
- readonly showErrors: import("@angular/core").InputSignal<boolean>;
6978
- protected readonly _disabledInput: import("@angular/core").InputSignal<boolean>;
6979
- private readonly _cvaDisabled;
6980
- protected readonly disabled: import("@angular/core").Signal<boolean>;
6981
- protected readonly _value: import("@angular/core").WritableSignal<string>;
6982
- protected readonly _inputId: string;
6983
- private readonly _reveal;
6984
- private readonly _issue;
6985
- /** True while the value breaks a built-in rule or the host passed an `[error]`. */
6986
- readonly invalid: import("@angular/core").Signal<boolean>;
6987
- /** Message of the first broken built-in rule ('' when valid), shown or not. */
6988
- readonly errorMessage: import("@angular/core").Signal<string>;
6989
- /** Emits whenever the field becomes invalid / valid. */
6990
- readonly invalidChange: import("@angular/core").OutputEmitterRef<boolean>;
6991
- protected readonly _activeError: import("@angular/core").Signal<string>;
6992
- private _onValidatorChange;
6993
- constructor();
6994
- /** Re-run the form control's validation when a rule input (required, min, max) changes. */
6995
- ngOnChanges(): void;
6996
- validate(control: AbstractControl): ValidationErrors | null;
6997
- registerOnValidatorChange(fn: () => void): void;
6998
- private _onChange;
6999
- private _onTouched;
7000
- writeValue(val: string): void;
7001
- registerOnChange(fn: (v: string) => void): void;
7002
- registerOnTouched(fn: () => void): void;
7003
- setDisabledState(d: boolean): void;
7004
- protected onChange(event: Event): void;
7005
- protected onBlur(): void;
7006
- private _check;
7007
- static ɵfac: i0.ɵɵFactoryDeclaration<TimeInputComponent, never>;
7008
- static ɵcmp: i0.ɵɵComponentDeclaration<TimeInputComponent, "ui-time-input", never, {
7009
- "label": {
7010
- "alias": "label";
4846
+ "options": {
4847
+ "alias": "options";
7011
4848
  "required": false;
7012
4849
  "isSignal": true;
7013
4850
  };
7014
- "ariaLabel": {
7015
- "alias": "ariaLabel";
4851
+ "loading": {
4852
+ "alias": "loading";
7016
4853
  "required": false;
7017
4854
  "isSignal": true;
7018
4855
  };
7019
- "required": {
7020
- "alias": "required";
4856
+ "noResultsText": {
4857
+ "alias": "noResultsText";
7021
4858
  "required": false;
7022
4859
  "isSignal": true;
7023
4860
  };
7024
- "min": {
7025
- "alias": "min";
4861
+ "minChars": {
4862
+ "alias": "minChars";
7026
4863
  "required": false;
7027
4864
  "isSignal": true;
7028
4865
  };
7029
- "max": {
7030
- "alias": "max";
4866
+ "debounce": {
4867
+ "alias": "debounce";
7031
4868
  "required": false;
7032
4869
  "isSignal": true;
7033
4870
  };
7034
- "hint": {
7035
- "alias": "hint";
4871
+ "value": {
4872
+ "alias": "value";
7036
4873
  "required": false;
7037
4874
  "isSignal": true;
7038
4875
  };
7039
- "error": {
7040
- "alias": "error";
4876
+ "displayText": {
4877
+ "alias": "displayText";
7041
4878
  "required": false;
7042
4879
  "isSignal": true;
7043
4880
  };
7044
- "showErrors": {
7045
- "alias": "showErrors";
4881
+ "displayWarning": {
4882
+ "alias": "displayWarning";
7046
4883
  "required": false;
7047
4884
  "isSignal": true;
7048
4885
  };
@@ -7052,7 +4889,11 @@ export declare class TimeInputComponent implements ControlValueAccessor, Validat
7052
4889
  "isSignal": true;
7053
4890
  };
7054
4891
  }, {
4892
+ "searchChange": "searchChange";
4893
+ "valueChange": "valueChange";
7055
4894
  "invalidChange": "invalidChange";
4895
+ "focused": "focused";
4896
+ "blurred": "blurred";
7056
4897
  }, never, never, true, never>;
7057
4898
  }
7058
4899
  /**
@@ -8659,167 +6500,6 @@ export declare class KpiCardComponent {
8659
6500
  };
8660
6501
  }, {}, never, ["[kpi-footer]"], true, never>;
8661
6502
  }
8662
- interface StateView {
8663
- id: string;
8664
- name: string;
8665
- path: string;
8666
- value: number;
8667
- /** "12 pickups" (or just "12"). */
8668
- valueText: string;
8669
- /** "Texas, 12 pickups": the accessible name, the tooltip text and the hidden-list entry. */
8670
- label: string;
8671
- fill: string;
8672
- }
8673
- /**
8674
- * US choropleth map: the 50 states plus Washington, DC, each coloured from `colorLow` (value 0) to `colorHigh` (the largest
8675
- * value) by its number in `data`.
8676
- *
8677
- * Interaction and accessibility
8678
- * - Every state is a button (`role="button"`, name "Texas, 12 pickups", `aria-pressed` for the selected one). The group has a
8679
- * single tab stop (roving tabindex: last focused state, else the selected one, else Alabama); arrow keys,
8680
- * Home and End move between states in alphabetical order, Enter / Space emit `stateClick` with the abbreviation.
8681
- * - The tooltip (state name + value) shows on hover AND on keyboard focus; it is real text, `aria-hidden` because the
8682
- * state's accessible name already says the same. Colour is never the only signal: values are in names, tooltip and the
8683
- * visually hidden list of all states.
8684
- * - A selected state gets an orange outline and the others are dimmed; the focus ring is drawn as an overlay outline
8685
- * (works the same in Chrome, Edge, Firefox and Safari) and only for keyboard focus.
8686
- * - `prefers-reduced-motion` turns the transitions off. Strokes use `vector-effect: non-scaling-stroke`, so outlines keep
8687
- * their pixel width when `focusState` zooms in.
8688
- *
8689
- * Known limitation: the very small states (CT, DC, DE, HI, MA, MD, NH, NJ, RI, VT) are tiny touch targets on a phone. They
8690
- * are reachable by keyboard and screen reader like any other; set `showSmallStateButtons` for a row of 44px buttons for them.
8691
- * Territories are not on the map.
8692
- */
8693
- export declare class UsStateMapComponent {
8694
- /** 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. */
8695
- readonly data: import("@angular/core").InputSignal<Record<string, number>>;
8696
- /** Abbreviation of the selected state (orange outline, the others are dimmed). Unknown / null = none. */
8697
- readonly selectedState: import("@angular/core").InputSignal<string | null>;
8698
- /** Abbreviation of a state to zoom the map to (bounding box plus 15% padding). Unknown / null = the whole map. */
8699
- readonly focusState: import("@angular/core").InputSignal<string | null>;
8700
- /** Unit for one, e.g. "pickup": "Texas, 1 pickup". Empty = just the number. */
8701
- readonly unitSingular: import("@angular/core").InputSignal<string>;
8702
- /** Unit for other counts, e.g. "pickups". Empty = the singular text is used for every count. */
8703
- readonly unitPlural: import("@angular/core").InputSignal<string>;
8704
- /** Colour of a value of 0 (CSS hex or rgb()). Invalid values fall back to #e5e7eb. */
8705
- readonly colorLow: import("@angular/core").InputSignal<string>;
8706
- /** Colour of the largest value (CSS hex or rgb()). Invalid values fall back to #1e40af. */
8707
- readonly colorHigh: import("@angular/core").InputSignal<string>;
8708
- /** Shows the colour scale (0 to the largest value). */
8709
- readonly showLegend: import("@angular/core").InputSignal<boolean>;
8710
- /** Shows a row of buttons for the very small states (touch friendly, 44px). Off by default. */
8711
- readonly showSmallStateButtons: import("@angular/core").InputSignal<boolean>;
8712
- /** Accessible name of the whole map. */
8713
- readonly ariaLabel: import("@angular/core").InputSignal<string>;
8714
- /** CSS maximum width of the map (it always shrinks to its container). */
8715
- readonly maxWidth: import("@angular/core").InputSignal<string>;
8716
- /** Optional CSS height of the map, e.g. "420px". Empty = follows the width (aspect ratio of the map). */
8717
- readonly height: import("@angular/core").InputSignal<string>;
8718
- /** Emits the state's abbreviation (upper case) on click, tap, Enter or Space. */
8719
- readonly stateClick: import("@angular/core").OutputEmitterRef<string>;
8720
- private readonly host;
8721
- /** True between a pointer press and the click that follows: a mouse / touch focus must not draw the keyboard ring. */
8722
- protected pointerDown: boolean;
8723
- private readonly hoveredId;
8724
- private readonly focusedId;
8725
- private readonly lastFocusedId;
8726
- private readonly ringVisible;
8727
- protected readonly tipPos: import("@angular/core").WritableSignal<{
8728
- x: number;
8729
- y: number;
8730
- } | null>;
8731
- private readonly low;
8732
- private readonly high;
8733
- private readonly values;
8734
- private readonly max;
8735
- private unit;
8736
- private valueText;
8737
- protected readonly views: import("@angular/core").Signal<StateView[]>;
8738
- protected readonly smallViews: import("@angular/core").Signal<StateView[]>;
8739
- protected readonly selectedId: import("@angular/core").Signal<string | null>;
8740
- protected readonly selectedView: import("@angular/core").Signal<StateView | null>;
8741
- protected readonly focusRingView: import("@angular/core").Signal<StateView | null>;
8742
- protected readonly viewBox: import("@angular/core").Signal<string>;
8743
- /** The one state in the tab order: last focused, else selected, else the first. */
8744
- protected readonly tabStop: import("@angular/core").Signal<string>;
8745
- protected readonly tip: import("@angular/core").Signal<StateView | null>;
8746
- protected readonly gradient: import("@angular/core").Signal<string>;
8747
- protected readonly maxText: import("@angular/core").Signal<string>;
8748
- protected readonly legendLabel: import("@angular/core").Signal<string>;
8749
- protected opacityOf(id: string): string | null;
8750
- protected onHover(ev: PointerEvent, id: string): void;
8751
- protected onLeave(id: string): void;
8752
- protected clearHover(): void;
8753
- protected onClick(id: string): void;
8754
- protected onFocus(id: string): void;
8755
- protected onBlur(id: string): void;
8756
- protected onKey(ev: KeyboardEvent, id: string): void;
8757
- static ɵfac: i0.ɵɵFactoryDeclaration<UsStateMapComponent, never>;
8758
- static ɵcmp: i0.ɵɵComponentDeclaration<UsStateMapComponent, "ui-us-state-map", never, {
8759
- "data": {
8760
- "alias": "data";
8761
- "required": false;
8762
- "isSignal": true;
8763
- };
8764
- "selectedState": {
8765
- "alias": "selectedState";
8766
- "required": false;
8767
- "isSignal": true;
8768
- };
8769
- "focusState": {
8770
- "alias": "focusState";
8771
- "required": false;
8772
- "isSignal": true;
8773
- };
8774
- "unitSingular": {
8775
- "alias": "unitSingular";
8776
- "required": false;
8777
- "isSignal": true;
8778
- };
8779
- "unitPlural": {
8780
- "alias": "unitPlural";
8781
- "required": false;
8782
- "isSignal": true;
8783
- };
8784
- "colorLow": {
8785
- "alias": "colorLow";
8786
- "required": false;
8787
- "isSignal": true;
8788
- };
8789
- "colorHigh": {
8790
- "alias": "colorHigh";
8791
- "required": false;
8792
- "isSignal": true;
8793
- };
8794
- "showLegend": {
8795
- "alias": "showLegend";
8796
- "required": false;
8797
- "isSignal": true;
8798
- };
8799
- "showSmallStateButtons": {
8800
- "alias": "showSmallStateButtons";
8801
- "required": false;
8802
- "isSignal": true;
8803
- };
8804
- "ariaLabel": {
8805
- "alias": "ariaLabel";
8806
- "required": false;
8807
- "isSignal": true;
8808
- };
8809
- "maxWidth": {
8810
- "alias": "maxWidth";
8811
- "required": false;
8812
- "isSignal": true;
8813
- };
8814
- "height": {
8815
- "alias": "height";
8816
- "required": false;
8817
- "isSignal": true;
8818
- };
8819
- }, {
8820
- "stateClick": "stateClick";
8821
- }, never, never, true, never>;
8822
- }
8823
6503
  export type DatePreset = 'today' | '7days' | '30days' | 'month' | 'quarter' | 'ytd' | 'all' | 'custom';
8824
6504
  export interface DateRange {
8825
6505
  preset: DatePreset;
@@ -9966,5 +7646,4 @@ export declare class ActionBarComponent {
9966
7646
  "isSignal": true;
9967
7647
  };
9968
7648
  }, {}, never, ["*"], true, never>;
9969
- }
9970
- export type { CreateDocumentRequestBody, DocuSignSendBody, DocumentSentInfo, DocumentSentMessage, DocumentsPayloadExtras, ExistingEnvelopeSendBody, SendDocumentsPayload, SendEmailPayload, SendTextPayload, VideoDefaults, VideoLinkOptions };
7649
+ }