@forgeroute/ui 0.4.58 → 0.4.60

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.
@@ -29251,7 +29251,7 @@ function defaultLabel(item, index) {
29251
29251
  }
29252
29252
  const DEFAULT_GAP_LIST = "0px";
29253
29253
  const DEFAULT_GAP_GRID = "12px";
29254
- let nextId$2 = 0;
29254
+ let nextId$3 = 0;
29255
29255
  var ListComponent = class ListComponent {
29256
29256
  constructor() {
29257
29257
  this.host = inject(ElementRef);
@@ -29274,11 +29274,12 @@ var ListComponent = class ListComponent {
29274
29274
  this.helpText = input("Hold Shift and press the arrow keys to move this item. Shift plus Home or End moves it to the start or end.", ...ngDevMode ? [{ debugName: "helpText" }] : /* istanbul ignore next */ []);
29275
29275
  this.moveAnnouncement = input((label, position, total) => `${label} moved to position ${position} of ${total}`, ...ngDevMode ? [{ debugName: "moveAnnouncement" }] : /* istanbul ignore next */ []);
29276
29276
  this.navigable = input(false, ...ngDevMode ? [{ debugName: "navigable" }] : /* istanbul ignore next */ []);
29277
+ this.arrow = input(false, ...ngDevMode ? [{ debugName: "arrow" }] : /* istanbul ignore next */ []);
29277
29278
  this.itemClick = output();
29278
29279
  this.itemsChange = output();
29279
29280
  this.reorder = output();
29280
29281
  this.rowTemplate = contentChild(TemplateRef, ...ngDevMode ? [{ debugName: "rowTemplate" }] : /* istanbul ignore next */ []);
29281
- this.helpId = `ul-help-${nextId$2++}`;
29282
+ this.helpId = `ul-help-${nextId$3++}`;
29282
29283
  this.announcement = signal("", ...ngDevMode ? [{ debugName: "announcement" }] : /* istanbul ignore next */ []);
29283
29284
  this.movedKey = signal(void 0, ...ngDevMode ? [{ debugName: "movedKey" }] : /* istanbul ignore next */ []);
29284
29285
  this.dragIndex = signal(null, ...ngDevMode ? [{ debugName: "dragIndex" }] : /* istanbul ignore next */ []);
@@ -29663,6 +29664,13 @@ var ListComponent = class ListComponent {
29663
29664
  isSignal: true,
29664
29665
  isRequired: false,
29665
29666
  transformFunction: null
29667
+ },
29668
+ arrow: {
29669
+ classPropertyName: "arrow",
29670
+ publicName: "arrow",
29671
+ isSignal: true,
29672
+ isRequired: false,
29673
+ transformFunction: null
29666
29674
  }
29667
29675
  },
29668
29676
  outputs: {
@@ -29701,7 +29709,7 @@ var ListComponent = class ListComponent {
29701
29709
  {{ row.label }}
29702
29710
  }
29703
29711
  </div>
29704
- @if (navigable()) {
29712
+ @if (navigable() && arrow()) {
29705
29713
  <svg class="ul-chevron" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M9 18l6-6-6-6"/></svg>
29706
29714
  }
29707
29715
  @if (showControls()) {
@@ -29830,7 +29838,7 @@ i0.ɵɵngDeclareClassMetadata({
29830
29838
  {{ row.label }}
29831
29839
  }
29832
29840
  </div>
29833
- @if (navigable()) {
29841
+ @if (navigable() && arrow()) {
29834
29842
  <svg class="ul-chevron" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M9 18l6-6-6-6"/></svg>
29835
29843
  }
29836
29844
  @if (showControls()) {
@@ -30025,6 +30033,14 @@ i0.ɵɵngDeclareClassMetadata({
30025
30033
  required: false
30026
30034
  }]
30027
30035
  }],
30036
+ arrow: [{
30037
+ type: i0.Input,
30038
+ args: [{
30039
+ isSignal: true,
30040
+ alias: "arrow",
30041
+ required: false
30042
+ }]
30043
+ }],
30028
30044
  itemClick: [{
30029
30045
  type: i0.Output,
30030
30046
  args: ["itemClick"]
@@ -31308,7 +31324,10 @@ var PanelInfoListComponent = class PanelInfoListComponent {
31308
31324
  <a class="pil-header-link" [routerLink]="section.headerLink.url">{{ section.headerLink.label }}</a>
31309
31325
  }
31310
31326
  @if (section.headerAction; as ha) {
31311
- <ui-button class="pil-header-action" variant="secondary" size="xs" [disabled]="!!ha.disabled" [ariaLabel]="ha.ariaLabel ?? ha.label" (click)="ha.action()">{{ ha.label }}</ui-button>
31327
+ <ui-button class="pil-header-action" variant="secondary" size="xs" [disabled]="!!ha.disabled" [ariaLabel]="ha.ariaLabel ?? ha.label" (click)="ha.action()">
31328
+ @if (ha.icon) {
31329
+ <svg class="pil-header-action-icon" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path [attr.d]="ha.icon"/></svg>
31330
+ }{{ ha.label }}</ui-button>
31312
31331
  }
31313
31332
  </div>
31314
31333
  }
@@ -31370,7 +31389,7 @@ var PanelInfoListComponent = class PanelInfoListComponent {
31370
31389
  }
31371
31390
  `,
31372
31391
  isInline: true,
31373
- styles: [":host{display:flex;flex-direction:column;gap:12px}:host(.pil-fill){flex:1;min-height:0}:host(.pil-fill) .pil-section{flex:1}.pil-section{border:1px solid #e2e8f0;border-radius:8px;overflow:hidden}.pil-section-label{display:flex;justify-content:space-between;align-items:center;font-size:.6875rem;font-weight:700;letter-spacing:.07em;color:#94a3b8;text-transform:uppercase;padding:8px 14px;background:#f8fafc;border-bottom:1px solid #e2e8f0}.pil-header-action{text-transform:none;letter-spacing:0;margin:-4px 0;flex-shrink:0}.pil-header-link{font-size:.75rem;font-weight:500;color:#2563eb;text-decoration:none;text-transform:none;letter-spacing:0}.pil-header-link:hover{text-decoration:underline}.pil-row{display:flex;justify-content:space-between;align-items:center;gap:12px;padding:9px 14px;border-bottom:1px solid #f1f5f9}.pil-row:last-child{border-bottom:none}.pil-row--inline{justify-content:flex-start}.pil-row--inline .pil-value{text-align:left;justify-content:flex-start;flex-wrap:wrap;min-width:0;overflow-wrap:anywhere;word-break:break-word}.pil-label{font-size:.8125rem;color:#64748b;flex-shrink:0}.pil-value{font-size:.875rem;font-weight:500;color:#1e293b;text-align:right;display:flex;align-items:center;justify-content:flex-end}.pil-multiline{white-space:pre-line;overflow-wrap:anywhere;word-break:break-word}.pil-strong .pil-label,.pil-strong .pil-value,.pil-strong .pil-muted{font-weight:700;color:#0f172a}.pil-badges{display:flex;align-items:center;gap:4px;flex-wrap:wrap;justify-content:flex-end}.pil-edit-btn{margin-left:4px;flex-shrink:0}ui-empty-state{padding:12px 0}.pil-muted{color:#1e293b;font-weight:400}.pil-danger{color:#ef4444;font-weight:600}.pil-link{font-size:.875rem;font-weight:500;color:#2563eb;text-decoration:none}.pil-link:hover{text-decoration:underline}.pil-link--href{overflow-wrap:anywhere;word-break:break-word}.pil-link:focus-visible,.pil-header-link:focus-visible{outline:2px solid #3b82f6;outline-offset:2px;border-radius:2px}.pil-link-icon{display:inline-flex;align-items:center;gap:5px;font-size:.875rem;font-weight:500;color:#1e293b;text-decoration:none}.pil-link-icon svg{color:#94a3b8;flex-shrink:0}.pil-grid-2{display:grid;grid-template-columns:1fr 1fr}.pil-grid-cell{display:flex;flex-direction:column;gap:3px;padding:10px 14px;border-right:1px solid #f1f5f9}.pil-grid-cell:last-child{border-right:none}.pil-value--block{text-align:left;justify-content:flex-start}\n"],
31392
+ styles: [":host{display:flex;flex-direction:column;gap:12px}:host(.pil-fill){flex:1;min-height:0}:host(.pil-fill) .pil-section{flex:1}.pil-section{border:1px solid #e2e8f0;border-radius:8px;overflow:hidden}.pil-section-label{display:flex;justify-content:space-between;align-items:center;font-size:.6875rem;font-weight:700;letter-spacing:.07em;color:#94a3b8;text-transform:uppercase;padding:8px 14px;background:#f8fafc;border-bottom:1px solid #e2e8f0}.pil-header-action{text-transform:none;letter-spacing:0;margin:-4px 0;flex-shrink:0}.pil-header-action-icon{margin-right:6px;vertical-align:-2px;flex-shrink:0}.pil-header-link{font-size:.75rem;font-weight:500;color:#2563eb;text-decoration:none;text-transform:none;letter-spacing:0}.pil-header-link:hover{text-decoration:underline}.pil-row{display:flex;justify-content:space-between;align-items:center;gap:12px;padding:9px 14px;border-bottom:1px solid #f1f5f9}.pil-row:last-child{border-bottom:none}.pil-row--inline{justify-content:flex-start}.pil-row--inline .pil-value{text-align:left;justify-content:flex-start;flex-wrap:wrap;min-width:0;overflow-wrap:anywhere;word-break:break-word}.pil-label{font-size:.8125rem;color:#64748b;flex-shrink:0}.pil-value{font-size:.875rem;font-weight:500;color:#1e293b;text-align:right;display:flex;align-items:center;justify-content:flex-end}.pil-multiline{white-space:pre-line;overflow-wrap:anywhere;word-break:break-word}.pil-strong .pil-label,.pil-strong .pil-value,.pil-strong .pil-muted{font-weight:700;color:#0f172a}.pil-badges{display:flex;align-items:center;gap:4px;flex-wrap:wrap;justify-content:flex-end}.pil-edit-btn{margin-left:4px;flex-shrink:0}ui-empty-state{padding:12px 0}.pil-muted{color:#1e293b;font-weight:400}.pil-danger{color:#ef4444;font-weight:600}.pil-link{font-size:.875rem;font-weight:500;color:#2563eb;text-decoration:none}.pil-link:hover{text-decoration:underline}.pil-link--href{overflow-wrap:anywhere;word-break:break-word}.pil-link:focus-visible,.pil-header-link:focus-visible{outline:2px solid #3b82f6;outline-offset:2px;border-radius:2px}.pil-link-icon{display:inline-flex;align-items:center;gap:5px;font-size:.875rem;font-weight:500;color:#1e293b;text-decoration:none}.pil-link-icon svg{color:#94a3b8;flex-shrink:0}.pil-grid-2{display:grid;grid-template-columns:1fr 1fr}.pil-grid-cell{display:flex;flex-direction:column;gap:3px;padding:10px 14px;border-right:1px solid #f1f5f9}.pil-grid-cell:last-child{border-right:none}.pil-value--block{text-align:left;justify-content:flex-start}\n"],
31374
31393
  dependencies: [
31375
31394
  {
31376
31395
  kind: "component",
@@ -31487,7 +31506,10 @@ i0.ɵɵngDeclareClassMetadata({
31487
31506
  <a class="pil-header-link" [routerLink]="section.headerLink.url">{{ section.headerLink.label }}</a>
31488
31507
  }
31489
31508
  @if (section.headerAction; as ha) {
31490
- <ui-button class="pil-header-action" variant="secondary" size="xs" [disabled]="!!ha.disabled" [ariaLabel]="ha.ariaLabel ?? ha.label" (click)="ha.action()">{{ ha.label }}</ui-button>
31509
+ <ui-button class="pil-header-action" variant="secondary" size="xs" [disabled]="!!ha.disabled" [ariaLabel]="ha.ariaLabel ?? ha.label" (click)="ha.action()">
31510
+ @if (ha.icon) {
31511
+ <svg class="pil-header-action-icon" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path [attr.d]="ha.icon"/></svg>
31512
+ }{{ ha.label }}</ui-button>
31491
31513
  }
31492
31514
  </div>
31493
31515
  }
@@ -31548,7 +31570,7 @@ i0.ɵɵngDeclareClassMetadata({
31548
31570
  </div>
31549
31571
  }
31550
31572
  `,
31551
- styles: [":host{display:flex;flex-direction:column;gap:12px}:host(.pil-fill){flex:1;min-height:0}:host(.pil-fill) .pil-section{flex:1}.pil-section{border:1px solid #e2e8f0;border-radius:8px;overflow:hidden}.pil-section-label{display:flex;justify-content:space-between;align-items:center;font-size:.6875rem;font-weight:700;letter-spacing:.07em;color:#94a3b8;text-transform:uppercase;padding:8px 14px;background:#f8fafc;border-bottom:1px solid #e2e8f0}.pil-header-action{text-transform:none;letter-spacing:0;margin:-4px 0;flex-shrink:0}.pil-header-link{font-size:.75rem;font-weight:500;color:#2563eb;text-decoration:none;text-transform:none;letter-spacing:0}.pil-header-link:hover{text-decoration:underline}.pil-row{display:flex;justify-content:space-between;align-items:center;gap:12px;padding:9px 14px;border-bottom:1px solid #f1f5f9}.pil-row:last-child{border-bottom:none}.pil-row--inline{justify-content:flex-start}.pil-row--inline .pil-value{text-align:left;justify-content:flex-start;flex-wrap:wrap;min-width:0;overflow-wrap:anywhere;word-break:break-word}.pil-label{font-size:.8125rem;color:#64748b;flex-shrink:0}.pil-value{font-size:.875rem;font-weight:500;color:#1e293b;text-align:right;display:flex;align-items:center;justify-content:flex-end}.pil-multiline{white-space:pre-line;overflow-wrap:anywhere;word-break:break-word}.pil-strong .pil-label,.pil-strong .pil-value,.pil-strong .pil-muted{font-weight:700;color:#0f172a}.pil-badges{display:flex;align-items:center;gap:4px;flex-wrap:wrap;justify-content:flex-end}.pil-edit-btn{margin-left:4px;flex-shrink:0}ui-empty-state{padding:12px 0}.pil-muted{color:#1e293b;font-weight:400}.pil-danger{color:#ef4444;font-weight:600}.pil-link{font-size:.875rem;font-weight:500;color:#2563eb;text-decoration:none}.pil-link:hover{text-decoration:underline}.pil-link--href{overflow-wrap:anywhere;word-break:break-word}.pil-link:focus-visible,.pil-header-link:focus-visible{outline:2px solid #3b82f6;outline-offset:2px;border-radius:2px}.pil-link-icon{display:inline-flex;align-items:center;gap:5px;font-size:.875rem;font-weight:500;color:#1e293b;text-decoration:none}.pil-link-icon svg{color:#94a3b8;flex-shrink:0}.pil-grid-2{display:grid;grid-template-columns:1fr 1fr}.pil-grid-cell{display:flex;flex-direction:column;gap:3px;padding:10px 14px;border-right:1px solid #f1f5f9}.pil-grid-cell:last-child{border-right:none}.pil-value--block{text-align:left;justify-content:flex-start}\n"]
31573
+ styles: [":host{display:flex;flex-direction:column;gap:12px}:host(.pil-fill){flex:1;min-height:0}:host(.pil-fill) .pil-section{flex:1}.pil-section{border:1px solid #e2e8f0;border-radius:8px;overflow:hidden}.pil-section-label{display:flex;justify-content:space-between;align-items:center;font-size:.6875rem;font-weight:700;letter-spacing:.07em;color:#94a3b8;text-transform:uppercase;padding:8px 14px;background:#f8fafc;border-bottom:1px solid #e2e8f0}.pil-header-action{text-transform:none;letter-spacing:0;margin:-4px 0;flex-shrink:0}.pil-header-action-icon{margin-right:6px;vertical-align:-2px;flex-shrink:0}.pil-header-link{font-size:.75rem;font-weight:500;color:#2563eb;text-decoration:none;text-transform:none;letter-spacing:0}.pil-header-link:hover{text-decoration:underline}.pil-row{display:flex;justify-content:space-between;align-items:center;gap:12px;padding:9px 14px;border-bottom:1px solid #f1f5f9}.pil-row:last-child{border-bottom:none}.pil-row--inline{justify-content:flex-start}.pil-row--inline .pil-value{text-align:left;justify-content:flex-start;flex-wrap:wrap;min-width:0;overflow-wrap:anywhere;word-break:break-word}.pil-label{font-size:.8125rem;color:#64748b;flex-shrink:0}.pil-value{font-size:.875rem;font-weight:500;color:#1e293b;text-align:right;display:flex;align-items:center;justify-content:flex-end}.pil-multiline{white-space:pre-line;overflow-wrap:anywhere;word-break:break-word}.pil-strong .pil-label,.pil-strong .pil-value,.pil-strong .pil-muted{font-weight:700;color:#0f172a}.pil-badges{display:flex;align-items:center;gap:4px;flex-wrap:wrap;justify-content:flex-end}.pil-edit-btn{margin-left:4px;flex-shrink:0}ui-empty-state{padding:12px 0}.pil-muted{color:#1e293b;font-weight:400}.pil-danger{color:#ef4444;font-weight:600}.pil-link{font-size:.875rem;font-weight:500;color:#2563eb;text-decoration:none}.pil-link:hover{text-decoration:underline}.pil-link--href{overflow-wrap:anywhere;word-break:break-word}.pil-link:focus-visible,.pil-header-link:focus-visible{outline:2px solid #3b82f6;outline-offset:2px;border-radius:2px}.pil-link-icon{display:inline-flex;align-items:center;gap:5px;font-size:.875rem;font-weight:500;color:#1e293b;text-decoration:none}.pil-link-icon svg{color:#94a3b8;flex-shrink:0}.pil-grid-2{display:grid;grid-template-columns:1fr 1fr}.pil-grid-cell{display:flex;flex-direction:column;gap:3px;padding:10px 14px;border-right:1px solid #f1f5f9}.pil-grid-cell:last-child{border-right:none}.pil-value--block{text-align:left;justify-content:flex-start}\n"]
31552
31574
  }]
31553
31575
  }],
31554
31576
  propDecorators: {
@@ -35515,7 +35537,7 @@ const STATE_COMMANDS = [
35515
35537
  "justifyCenter",
35516
35538
  "justifyRight"
35517
35539
  ];
35518
- let nextId$1 = 0;
35540
+ let nextId$2 = 0;
35519
35541
  var RichTextEditorComponent = class RichTextEditorComponent {
35520
35542
  constructor() {
35521
35543
  this.label = input("", ...ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []);
@@ -35536,7 +35558,7 @@ var RichTextEditorComponent = class RichTextEditorComponent {
35536
35558
  this.disabled = computed(() => this._disabledInput() || this._cvaDisabled(), ...ngDevMode ? [{ debugName: "disabled" }] : /* istanbul ignore next */ []);
35537
35559
  this.inert = computed(() => this.disabled() || this.readonly(), ...ngDevMode ? [{ debugName: "inert" }] : /* istanbul ignore next */ []);
35538
35560
  this.editor = viewChild("editor", ...ngDevMode ? [{ debugName: "editor" }] : /* istanbul ignore next */ []);
35539
- this._id = ++nextId$1;
35561
+ this._id = ++nextId$2;
35540
35562
  this._editorId = `rte-${this._id}`;
35541
35563
  this._labelId = `rte-${this._id}-label`;
35542
35564
  this._errorId = `rte-${this._id}-error`;
@@ -38912,14 +38934,14 @@ i0.ɵɵngDeclareClassMetadata({
38912
38934
  }]
38913
38935
  }
38914
38936
  });
38915
- let nextId = 0;
38937
+ let nextId$1 = 0;
38916
38938
  var ReadonlyFieldsetComponent = class ReadonlyFieldsetComponent {
38917
38939
  constructor() {
38918
38940
  this.readOnly = input(false, ...ngDevMode ? [{ debugName: "readOnly" }] : /* istanbul ignore next */ []);
38919
38941
  this.gap = input("0", ...ngDevMode ? [{ debugName: "gap" }] : /* istanbul ignore next */ []);
38920
38942
  this.ariaLabel = input("", ...ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []);
38921
38943
  this.reason = input("", ...ngDevMode ? [{ debugName: "reason" }] : /* istanbul ignore next */ []);
38922
- this._reasonId = `rf-reason-${nextId++}`;
38944
+ this._reasonId = `rf-reason-${nextId$1++}`;
38923
38945
  this._showReason = computed(() => this.readOnly() && !!this.reason().trim(), ...ngDevMode ? [{ debugName: "_showReason" }] : /* istanbul ignore next */ []);
38924
38946
  }
38925
38947
  static {
@@ -50179,6 +50201,2502 @@ i0.ɵɵngDeclareClassMetadata({
50179
50201
  }]
50180
50202
  }
50181
50203
  });
50182
- export { ActionBarComponent, AlertComponent, AppShellComponent, AudioPlayerComponent, AvatarComponent, BADGE_VARIANT_STYLES, BadgeComponent, BankAccountFormComponent, BarRowComponent, BoardCardDirective, BoardComponent, BulkMessagePanelComponent, BusinessHoursComponent, ButtonComponent, CalendarComponent, CardListItemComponent, CheckboxComponent, CheckboxTrailingDirective, ChipComponent, ChipGroupComponent, ColorInputComponent, ColumnFilterComponent, ColumnsComponent, ComboboxComponent, ConfirmOutletComponent, ConfirmService, ContactPickerComponent, DEFAULT_BANK_ACCOUNT_TYPE_OPTIONS, DEFAULT_BANK_HOLDER_TYPE_OPTIONS, DEFAULT_BANK_MANDATE_TEXT, DEFAULT_EMAIL_TEMPLATE_BLOCK_GROUPS, DEFAULT_EMAIL_TEMPLATE_VARIABLE_GROUPS, DEFAULT_PASSWORD_RULES, DROPDOWN_GROUP, DataTableComponent, DateInputComponent, DateRangePickerComponent, DatetimeInputComponent, DetailCardComponent, DiscountSelectorComponent, DividerComponent, DropdownComponent, EMAIL_BLOCK_DRAG_TYPE, EMAIL_TEMPLATE_MAX_BODY, EMAIL_TEMPLATE_MAX_TEXT, EMAIL_TEMPLATE_START_TEXT, EmailTemplateEditorComponent, EmptyStateComponent, ErrorComponent, ErrorStateComponent, FORGEROUTE_CONFIG, FadeComponent, FileInputComponent, FixedFooterComponent, FormColSpanDirective, FormComponent, FormRowComponent, FormSectionComponent, HintComponent, IDX_BEHAVIOR_SIGNALS, INTEGRATION_CATALOG, INTEGRATION_FIELD_DEFS, INTEGRATION_GROUP_ORDER, INTEGRATION_OPTION_DEFS, IconComponent, ImageComponent, ImageGalleryComponent, ImageGalleryDialogComponent, ImagePreviewComponent, ImageRepositionComponent, ImportExportComponent, ImportSourceGridComponent, KpiCardComponent, LAYOUT_GAP_PX, ListComponent, ListItemComponent, LiveRegionComponent, MAX_EMAIL_ADDRESS_LENGTH, ModalComponent, MoreMenuComponent, MultiSelectComponent, NOTES_MAX_LENGTH, NotesComponent, OfflineBannerComponent, OptionCardComponent, PHONE_NUMBER_AREA_CODE_LENGTH, PHONE_NUMBER_ZIP_LENGTH, PageComponent, PaginationComponent, PanelInfoListComponent, PasswordRequirementsComponent, PdfHotspotComponent, PhoneNumberPickerComponent, PillTabsComponent, ProgressBarComponent, ProgressRingComponent, QrCodeComponent, QuickFilterTabsComponent, RICH_TEXT_OPTIONS, RadioComponent, RadioGroupComponent, RadioMatrixComponent, RadioOptionContentDirective, ReadonlyFieldsetComponent, ReminderAlertsComponent, RichTextEditorComponent, SEMANTIC_BADGE_MAP, SETUP_DONE_KEY, SETUP_INTEGRATIONS, SearchInputComponent, SectionHeaderComponent, SelectComponent, SetupWizardComponent, SetupWizardStepDirective, SetupWizardStepHeaderDirective, ShareMenuComponent, ShowComponent, SidePanelComponent, SidebarLayoutComponent, SignaturePadComponent, SkeletonComponent, SnackbarComponent, SnackbarService, StackComponent, StarComponent, StepperComponent, TableToolbarComponent, TextComponent, TextInputComponent, TextTemplatePickerComponent, TextareaInputComponent, TimeInputComponent, TimelineComponent, ToastComponent, ToastService, ToggleBadgeComponent, ToggleComponent, TooltipDirective, US_STATES, UiFieldValidity, acceptLabel, appShellGroupsStorageKey, autoVariant, blockHasContent, buildDefaultSchedule, buildPreviewDocument, buildVideoBlockHtml, builtInActionIcon, businessTimeOptions, createFieldReveal, decodeFilterValues, digitsOnly, downloadBlob, emailShareUrl, encodeFilterValue, encodeFilterValues, errorContextInterceptor, escapeHtml, facebookShareUrl, fileMatchesAccept, formatAddress, formatCategoryLabel, formatCurrency, formatFileSize, formatIsoDate, formatIsoDateTime, formatTime, formatVideoDuration, getEligibleIds, getEligibleOptions, getErrorMessage, gmailShareUrl, humanReadableMessage, iconPath, insideEditorBlock, integrationPlainText, integrationsForApp, integrationsOnlyFor, isBlockDrag, isValidEmailAddress, isWebUrl, isoKey, issueToErrors, linkedInShareUrl, maxLengthIssue, mergeDescribedBy, normalizeHexColor, outlookShareUrl, parseBizHours, parseIso, parseTime, passwordMeetsRules, pluralize, provideForgerouteToast, reorderItems, requiredIssue, resolveLayoutGap, resolvePreset, serializeBizHours, serializedTextLength, setupIntegrations, splitIntro, xShareUrl };
50204
+ function formatConversationPhone(phone) {
50205
+ if (!phone) return "";
50206
+ const digits = phone.replace(/\D/g, "");
50207
+ if (digits.length === 10) return `(${digits.slice(0, 3)}) ${digits.slice(3, 6)}-${digits.slice(6)}`;
50208
+ if (digits.length === 11 && digits.startsWith("1")) return `+1 (${digits.slice(1, 4)}) ${digits.slice(4, 7)}-${digits.slice(7)}`;
50209
+ return phone;
50210
+ }
50211
+ function truncateConversationText(text, len) {
50212
+ if (!text) return "";
50213
+ return text.length > len ? text.substring(0, len) + "..." : text;
50214
+ }
50215
+ function formatConversationTime(iso, now = /* @__PURE__ */ new Date()) {
50216
+ if (!iso) return "";
50217
+ const d = new Date(iso);
50218
+ if (Number.isNaN(d.getTime())) return "";
50219
+ const mins = Math.floor((now.getTime() - d.getTime()) / 6e4);
50220
+ if (mins < 1) return "now";
50221
+ if (mins < 60) return `${mins}m`;
50222
+ const hrs = Math.floor(mins / 60);
50223
+ if (hrs < 24) return `${hrs}h`;
50224
+ const days = Math.floor(hrs / 24);
50225
+ if (days < 7) return `${days}d`;
50226
+ return d.toLocaleDateString("en-US", {
50227
+ month: "short",
50228
+ day: "numeric"
50229
+ });
50230
+ }
50231
+ function formatMessageTime(iso) {
50232
+ const d = new Date(iso);
50233
+ return Number.isNaN(d.getTime()) ? "" : d.toLocaleTimeString("en-US", {
50234
+ hour: "numeric",
50235
+ minute: "2-digit"
50236
+ });
50237
+ }
50238
+ function conversationDateLabel(iso, now = /* @__PURE__ */ new Date()) {
50239
+ const d = new Date(iso);
50240
+ if (Number.isNaN(d.getTime())) return "";
50241
+ const yesterday = new Date(now);
50242
+ yesterday.setDate(yesterday.getDate() - 1);
50243
+ if (d.toDateString() === now.toDateString()) return "Today";
50244
+ if (d.toDateString() === yesterday.toDateString()) return "Yesterday";
50245
+ return d.toLocaleDateString("en-US", {
50246
+ month: "short",
50247
+ day: "numeric",
50248
+ year: "numeric"
50249
+ });
50250
+ }
50251
+ function conversationInitial(name) {
50252
+ return (name ?? "").trim().charAt(0).toUpperCase() || "?";
50253
+ }
50254
+ function groupMessagesByDay(messages, now = /* @__PURE__ */ new Date()) {
50255
+ return messages.map((message, i) => {
50256
+ const label = conversationDateLabel(message.sentAt, now);
50257
+ return {
50258
+ message,
50259
+ separator: i === 0 || conversationDateLabel(messages[i - 1].sentAt, now) !== label ? label : ""
50260
+ };
50261
+ });
50262
+ }
50263
+ function conversationMessageStatusLabel(status) {
50264
+ switch (status) {
50265
+ case "delivered": return "Delivered";
50266
+ case "sent": return "Sent";
50267
+ case "failed": return "Failed";
50268
+ case "scheduled": return "Scheduled";
50269
+ default: return "";
50270
+ }
50271
+ }
50272
+ function conversationMessageStatusMark(status) {
50273
+ if (status === "delivered") return "✓✓";
50274
+ if (status === "sent") return "✓";
50275
+ return conversationMessageStatusLabel(status);
50276
+ }
50277
+ const SINGLE_COLUMN_QUERY = "(max-width: 768px)";
50278
+ const NEAR_BOTTOM_PX = 120;
50279
+ const PREVIEW_LENGTH = 60;
50280
+ let nextId = 0;
50281
+ var ConversationsComponent = class ConversationsComponent {
50282
+ constructor() {
50283
+ this.conversations = input([], ...ngDevMode ? [{ debugName: "conversations" }] : /* istanbul ignore next */ []);
50284
+ this.selected = input(null, ...ngDevMode ? [{ debugName: "selected" }] : /* istanbul ignore next */ []);
50285
+ this.title = input("Messages", ...ngDevMode ? [{ debugName: "title" }] : /* istanbul ignore next */ []);
50286
+ this.loading = input(false, ...ngDevMode ? [{ debugName: "loading" }] : /* istanbul ignore next */ []);
50287
+ this.error = input(null, ...ngDevMode ? [{ debugName: "error" }] : /* istanbul ignore next */ []);
50288
+ this.searchText = model("", ...ngDevMode ? [{ debugName: "searchText" }] : /* istanbul ignore next */ []);
50289
+ this.searchPlaceholder = input("Search by name or phone...", ...ngDevMode ? [{ debugName: "searchPlaceholder" }] : /* istanbul ignore next */ []);
50290
+ this.searchAriaLabel = input("Search conversations", ...ngDevMode ? [{ debugName: "searchAriaLabel" }] : /* istanbul ignore next */ []);
50291
+ this.showFilters = input(true, ...ngDevMode ? [{ debugName: "showFilters" }] : /* istanbul ignore next */ []);
50292
+ this.filterTabs = input([], ...ngDevMode ? [{ debugName: "filterTabs" }] : /* istanbul ignore next */ []);
50293
+ this.filterCounts = input({}, ...ngDevMode ? [{ debugName: "filterCounts" }] : /* istanbul ignore next */ []);
50294
+ this.activeFilter = input("", ...ngDevMode ? [{ debugName: "activeFilter" }] : /* istanbul ignore next */ []);
50295
+ this.filterAriaLabel = input("Filter conversations", ...ngDevMode ? [{ debugName: "filterAriaLabel" }] : /* istanbul ignore next */ []);
50296
+ this.page = input(1, ...ngDevMode ? [{ debugName: "page" }] : /* istanbul ignore next */ []);
50297
+ this.pageSize = input(25, ...ngDevMode ? [{ debugName: "pageSize" }] : /* istanbul ignore next */ []);
50298
+ this.totalItems = input(0, ...ngDevMode ? [{ debugName: "totalItems" }] : /* istanbul ignore next */ []);
50299
+ this.paginationAriaLabel = input("Conversation pages", ...ngDevMode ? [{ debugName: "paginationAriaLabel" }] : /* istanbul ignore next */ []);
50300
+ this.listAriaLabel = input("Conversations", ...ngDevMode ? [{ debugName: "listAriaLabel" }] : /* istanbul ignore next */ []);
50301
+ this.loadingLabel = input("Loading conversations", ...ngDevMode ? [{ debugName: "loadingLabel" }] : /* istanbul ignore next */ []);
50302
+ this.emptyTitle = input("No conversations yet", ...ngDevMode ? [{ debugName: "emptyTitle" }] : /* istanbul ignore next */ []);
50303
+ this.emptyMessage = input("Click the + button to start messaging", ...ngDevMode ? [{ debugName: "emptyMessage" }] : /* istanbul ignore next */ []);
50304
+ this.emptyReadOnlyMessage = input("Conversations will appear here once texting starts.", ...ngDevMode ? [{ debugName: "emptyReadOnlyMessage" }] : /* istanbul ignore next */ []);
50305
+ this.filteredEmptyTitle = input("No conversations found", ...ngDevMode ? [{ debugName: "filteredEmptyTitle" }] : /* istanbul ignore next */ []);
50306
+ this.filteredEmptyMessage = input("No conversation matches your search or filter.", ...ngDevMode ? [{ debugName: "filteredEmptyMessage" }] : /* istanbul ignore next */ []);
50307
+ this.noMessagesText = input("No messages", ...ngDevMode ? [{ debugName: "noMessagesText" }] : /* istanbul ignore next */ []);
50308
+ this.allowNew = input(true, ...ngDevMode ? [{ debugName: "allowNew" }] : /* istanbul ignore next */ []);
50309
+ this.allowDelete = input(true, ...ngDevMode ? [{ debugName: "allowDelete" }] : /* istanbul ignore next */ []);
50310
+ this.showRowArrow = input(false, ...ngDevMode ? [{ debugName: "showRowArrow" }] : /* istanbul ignore next */ []);
50311
+ this.newLabel = input("Start new message", ...ngDevMode ? [{ debugName: "newLabel" }] : /* istanbul ignore next */ []);
50312
+ this.newTooltip = input("New message", ...ngDevMode ? [{ debugName: "newTooltip" }] : /* istanbul ignore next */ []);
50313
+ this.deleteRowLabel = input("Delete conversation with", ...ngDevMode ? [{ debugName: "deleteRowLabel" }] : /* istanbul ignore next */ []);
50314
+ this.messages = input([], ...ngDevMode ? [{ debugName: "messages" }] : /* istanbul ignore next */ []);
50315
+ this.messagesLoading = input(false, ...ngDevMode ? [{ debugName: "messagesLoading" }] : /* istanbul ignore next */ []);
50316
+ this.messagesError = input(null, ...ngDevMode ? [{ debugName: "messagesError" }] : /* istanbul ignore next */ []);
50317
+ this.hasEarlier = input(false, ...ngDevMode ? [{ debugName: "hasEarlier" }] : /* istanbul ignore next */ []);
50318
+ this.loadingEarlier = input(false, ...ngDevMode ? [{ debugName: "loadingEarlier" }] : /* istanbul ignore next */ []);
50319
+ this.loadEarlierLabel = input("Load earlier messages", ...ngDevMode ? [{ debugName: "loadEarlierLabel" }] : /* istanbul ignore next */ []);
50320
+ this.statusActionLabel = input(null, ...ngDevMode ? [{ debugName: "statusActionLabel" }] : /* istanbul ignore next */ []);
50321
+ this.statusActionIcon = input("close", ...ngDevMode ? [{ debugName: "statusActionIcon" }] : /* istanbul ignore next */ []);
50322
+ this.statusChanging = input(false, ...ngDevMode ? [{ debugName: "statusChanging" }] : /* istanbul ignore next */ []);
50323
+ this.templatesEnabled = input(false, ...ngDevMode ? [{ debugName: "templatesEnabled" }] : /* istanbul ignore next */ []);
50324
+ this.templateLabel = input("Use a template", ...ngDevMode ? [{ debugName: "templateLabel" }] : /* istanbul ignore next */ []);
50325
+ this.deleteThreadLabel = input("Delete conversation", ...ngDevMode ? [{ debugName: "deleteThreadLabel" }] : /* istanbul ignore next */ []);
50326
+ this.backLabel = input("Back to conversations", ...ngDevMode ? [{ debugName: "backLabel" }] : /* istanbul ignore next */ []);
50327
+ this.threadAriaLabel = input("Message thread", ...ngDevMode ? [{ debugName: "threadAriaLabel" }] : /* istanbul ignore next */ []);
50328
+ this.messagesAriaLabel = input("Messages with", ...ngDevMode ? [{ debugName: "messagesAriaLabel" }] : /* istanbul ignore next */ []);
50329
+ this.threadEmptyTitle = input("Select a conversation", ...ngDevMode ? [{ debugName: "threadEmptyTitle" }] : /* istanbul ignore next */ []);
50330
+ this.threadEmptyMessage = input("Choose a conversation from the list or start a new one", ...ngDevMode ? [{ debugName: "threadEmptyMessage" }] : /* istanbul ignore next */ []);
50331
+ this.noMessagesWriteText = input("No messages in this conversation yet. Send the first message below.", ...ngDevMode ? [{ debugName: "noMessagesWriteText" }] : /* istanbul ignore next */ []);
50332
+ this.noMessagesReadText = input("No messages in this conversation yet.", ...ngDevMode ? [{ debugName: "noMessagesReadText" }] : /* istanbul ignore next */ []);
50333
+ this.youLabel = input("You", ...ngDevMode ? [{ debugName: "youLabel" }] : /* istanbul ignore next */ []);
50334
+ this.openMediaLabel = input("Open", ...ngDevMode ? [{ debugName: "openMediaLabel" }] : /* istanbul ignore next */ []);
50335
+ this.imageFallbackName = input("image", ...ngDevMode ? [{ debugName: "imageFallbackName" }] : /* istanbul ignore next */ []);
50336
+ this.fileFallbackName = input("Attachment", ...ngDevMode ? [{ debugName: "fileFallbackName" }] : /* istanbul ignore next */ []);
50337
+ this.hasContext = input(false, ...ngDevMode ? [{ debugName: "hasContext" }] : /* istanbul ignore next */ []);
50338
+ this.contextOpen = model(false, ...ngDevMode ? [{ debugName: "contextOpen" }] : /* istanbul ignore next */ []);
50339
+ this.contextTitle = input("Contact Info", ...ngDevMode ? [{ debugName: "contextTitle" }] : /* istanbul ignore next */ []);
50340
+ this.showContextLabel = input("Show contact info", ...ngDevMode ? [{ debugName: "showContextLabel" }] : /* istanbul ignore next */ []);
50341
+ this.hideContextLabel = input("Hide contact info", ...ngDevMode ? [{ debugName: "hideContextLabel" }] : /* istanbul ignore next */ []);
50342
+ this.closeContextLabel = input("Close contact info", ...ngDevMode ? [{ debugName: "closeContextLabel" }] : /* istanbul ignore next */ []);
50343
+ this.canWrite = input(true, ...ngDevMode ? [{ debugName: "canWrite" }] : /* istanbul ignore next */ []);
50344
+ this.draft = model("", ...ngDevMode ? [{ debugName: "draft" }] : /* istanbul ignore next */ []);
50345
+ this.sending = input(false, ...ngDevMode ? [{ debugName: "sending" }] : /* istanbul ignore next */ []);
50346
+ this.composerDisabled = input(false, ...ngDevMode ? [{ debugName: "composerDisabled" }] : /* istanbul ignore next */ []);
50347
+ this.sendBlocked = input(false, ...ngDevMode ? [{ debugName: "sendBlocked" }] : /* istanbul ignore next */ []);
50348
+ this.composerNotice = input("", ...ngDevMode ? [{ debugName: "composerNotice" }] : /* istanbul ignore next */ []);
50349
+ this.composerStatus = input("", ...ngDevMode ? [{ debugName: "composerStatus" }] : /* istanbul ignore next */ []);
50350
+ this.composerError = input("", ...ngDevMode ? [{ debugName: "composerError" }] : /* istanbul ignore next */ []);
50351
+ this.maxLength = input(1600, ...ngDevMode ? [{ debugName: "maxLength" }] : /* istanbul ignore next */ []);
50352
+ this.attachment = input(null, ...ngDevMode ? [{ debugName: "attachment" }] : /* istanbul ignore next */ []);
50353
+ this.uploading = input(false, ...ngDevMode ? [{ debugName: "uploading" }] : /* istanbul ignore next */ []);
50354
+ this.attachEnabled = input(true, ...ngDevMode ? [{ debugName: "attachEnabled" }] : /* istanbul ignore next */ []);
50355
+ this.acceptedFiles = input("image/*,video/*", ...ngDevMode ? [{ debugName: "acceptedFiles" }] : /* istanbul ignore next */ []);
50356
+ this.maxFileSize = input(null, ...ngDevMode ? [{ debugName: "maxFileSize" }] : /* istanbul ignore next */ []);
50357
+ this.typeMessage = input("Only image and video files are supported.", ...ngDevMode ? [{ debugName: "typeMessage" }] : /* istanbul ignore next */ []);
50358
+ this.sizeMessage = input("That file is too large.", ...ngDevMode ? [{ debugName: "sizeMessage" }] : /* istanbul ignore next */ []);
50359
+ this.composeLabel = input("Type a message", ...ngDevMode ? [{ debugName: "composeLabel" }] : /* istanbul ignore next */ []);
50360
+ this.composePlaceholder = input("Type a message...", ...ngDevMode ? [{ debugName: "composePlaceholder" }] : /* istanbul ignore next */ []);
50361
+ this.sendLabel = input("Send message", ...ngDevMode ? [{ debugName: "sendLabel" }] : /* istanbul ignore next */ []);
50362
+ this.attachLabel = input("Attach image or video", ...ngDevMode ? [{ debugName: "attachLabel" }] : /* istanbul ignore next */ []);
50363
+ this.removeAttachmentLabel = input("Remove attachment", ...ngDevMode ? [{ debugName: "removeAttachmentLabel" }] : /* istanbul ignore next */ []);
50364
+ this.attachmentPreviewLabel = input("Attachment preview", ...ngDevMode ? [{ debugName: "attachmentPreviewLabel" }] : /* istanbul ignore next */ []);
50365
+ this.now = input(null, ...ngDevMode ? [{ debugName: "now" }] : /* istanbul ignore next */ []);
50366
+ this.searchChange = output();
50367
+ this.filterChange = output();
50368
+ this.pageChange = output();
50369
+ this.selectConversation = output();
50370
+ this.back = output();
50371
+ this.newConversation = output();
50372
+ this.retry = output();
50373
+ this.deleteConversation = output();
50374
+ this.statusChange = output();
50375
+ this.templateRequest = output();
50376
+ this.send = output();
50377
+ this.filesSelected = output();
50378
+ this.attachmentRemove = output();
50379
+ this.mediaOpen = output();
50380
+ this.messageAction = output();
50381
+ this.loadEarlier = output();
50382
+ this.messagesRetry = output();
50383
+ this.titleId = `cv-title-${nextId++}`;
50384
+ this.skeletonRows = [
50385
+ 1,
50386
+ 2,
50387
+ 3,
50388
+ 4,
50389
+ 5
50390
+ ];
50391
+ this.skeletonBubbles = [
50392
+ 0,
50393
+ 1,
50394
+ 2
50395
+ ];
50396
+ this.trackConversation = (c) => c.id;
50397
+ this.initial = conversationInitial;
50398
+ this.statusLabel = conversationMessageStatusLabel;
50399
+ this.statusMark = conversationMessageStatusMark;
50400
+ this.injector = inject(Injector);
50401
+ this.host = inject(ElementRef);
50402
+ this.threadHeading = viewChild("threadHeading", ...ngDevMode ? [{ debugName: "threadHeading" }] : /* istanbul ignore next */ []);
50403
+ this.messagesEl = viewChild("messagesEl", ...ngDevMode ? [{ debugName: "messagesEl" }] : /* istanbul ignore next */ []);
50404
+ this.contextPanel = viewChild("contextPanel", ...ngDevMode ? [{ debugName: "contextPanel" }] : /* istanbul ignore next */ []);
50405
+ this.fileInput = viewChild(FileInputComponent, ...ngDevMode ? [{ debugName: "fileInput" }] : /* istanbul ignore next */ []);
50406
+ this.atBottom = true;
50407
+ this.lastThreadId = null;
50408
+ this.filtering = computed(() => !!this.searchText().trim() || this.activeFilter() !== "", ...ngDevMode ? [{ debugName: "filtering" }] : /* istanbul ignore next */ []);
50409
+ this.emptyText = computed(() => this.filtering() ? this.filteredEmptyMessage() : this.canWrite() ? this.emptyMessage() : this.emptyReadOnlyMessage(), ...ngDevMode ? [{ debugName: "emptyText" }] : /* istanbul ignore next */ []);
50410
+ this.messageRows = computed(() => groupMessagesByDay(this.messages(), this.clock()), ...ngDevMode ? [{ debugName: "messageRows" }] : /* istanbul ignore next */ []);
50411
+ this.contextVisible = computed(() => this.hasContext() && this.contextOpen() && !!this.selected(), ...ngDevMode ? [{ debugName: "contextVisible" }] : /* istanbul ignore next */ []);
50412
+ this.canSend = computed(() => !this.composerDisabled() && !this.sendBlocked() && !this.sending() && (this.draft().trim().length > 0 || !!this.attachment()), ...ngDevMode ? [{ debugName: "canSend" }] : /* istanbul ignore next */ []);
50413
+ effect(() => {
50414
+ const id = this.selected()?.id ?? null;
50415
+ const count = this.messages().length;
50416
+ untracked(() => {
50417
+ const switched = id !== this.lastThreadId;
50418
+ this.lastThreadId = id;
50419
+ if (switched) this.atBottom = true;
50420
+ if (count > 0 && this.atBottom) this.scrollToBottom();
50421
+ });
50422
+ });
50423
+ effect(() => {
50424
+ if (!this.selected() && this.contextOpen()) untracked(() => this.contextOpen.set(false));
50425
+ });
50426
+ }
50427
+ relativeTime(iso) {
50428
+ return formatConversationTime(iso, this.clock());
50429
+ }
50430
+ preview(text) {
50431
+ return truncateConversationText(text, PREVIEW_LENGTH);
50432
+ }
50433
+ time(message) {
50434
+ return formatMessageTime(message.sentAt);
50435
+ }
50436
+ onRowOpen(conv) {
50437
+ this.selectConversation.emit(conv);
50438
+ if (this.singleColumn()) afterNextRender(() => this.threadHeading()?.nativeElement.focus(), { injector: this.injector });
50439
+ }
50440
+ onBack() {
50441
+ const id = this.selected()?.id;
50442
+ this.back.emit();
50443
+ afterNextRender(() => {
50444
+ const rows = Array.from(this.host.nativeElement.querySelectorAll("[data-testid=\"conv-item\"]"));
50445
+ (rows.find((r) => r.dataset["conversationId"] === id) ?? rows[0])?.closest("li")?.focus();
50446
+ }, { injector: this.injector });
50447
+ }
50448
+ onMessagesScroll() {
50449
+ const el = this.messagesEl()?.nativeElement;
50450
+ if (el) this.atBottom = el.scrollHeight - el.scrollTop - el.clientHeight < NEAR_BOTTOM_PX;
50451
+ }
50452
+ toggleContext() {
50453
+ if (this.contextOpen()) {
50454
+ this.closeContext(true);
50455
+ return;
50456
+ }
50457
+ this.contextOpen.set(true);
50458
+ afterNextRender(() => this.contextPanel()?.nativeElement.focus(), { injector: this.injector });
50459
+ }
50460
+ closeContext(restoreFocus = false) {
50461
+ this.contextOpen.set(false);
50462
+ if (restoreFocus) afterNextRender(() => this.host.nativeElement.querySelector("[data-testid=\"context-toggle\"] button")?.focus(), { injector: this.injector });
50463
+ }
50464
+ openFilePicker() {
50465
+ this.fileInput()?.open();
50466
+ }
50467
+ onComposeKeydown(event) {
50468
+ if (event.key === "Enter" && !event.shiftKey && !event.isComposing) {
50469
+ event.preventDefault();
50470
+ this.sendMessage();
50471
+ }
50472
+ }
50473
+ sendMessage() {
50474
+ if (!this.canSend()) return;
50475
+ this.send.emit({ text: this.draft().trim() });
50476
+ }
50477
+ clock() {
50478
+ return this.now() ?? /* @__PURE__ */ new Date();
50479
+ }
50480
+ singleColumn() {
50481
+ return typeof window !== "undefined" && typeof window.matchMedia === "function" && window.matchMedia(SINGLE_COLUMN_QUERY).matches;
50482
+ }
50483
+ scrollToBottom() {
50484
+ afterNextRender(() => {
50485
+ const el = this.messagesEl()?.nativeElement;
50486
+ if (el) el.scrollTop = el.scrollHeight;
50487
+ }, { injector: this.injector });
50488
+ }
50489
+ static {
50490
+ this.ɵfac = i0.ɵɵngDeclareFactory({
50491
+ minVersion: "12.0.0",
50492
+ version: "22.2.2",
50493
+ ngImport: i0,
50494
+ type: ConversationsComponent,
50495
+ deps: [],
50496
+ target: i0.ɵɵFactoryTarget.Component
50497
+ });
50498
+ }
50499
+ static {
50500
+ this.ɵcmp = i0.ɵɵngDeclareComponent({
50501
+ minVersion: "17.0.0",
50502
+ version: "22.2.2",
50503
+ type: ConversationsComponent,
50504
+ isStandalone: true,
50505
+ selector: "ui-conversations",
50506
+ inputs: {
50507
+ conversations: {
50508
+ classPropertyName: "conversations",
50509
+ publicName: "conversations",
50510
+ isSignal: true,
50511
+ isRequired: false,
50512
+ transformFunction: null
50513
+ },
50514
+ selected: {
50515
+ classPropertyName: "selected",
50516
+ publicName: "selected",
50517
+ isSignal: true,
50518
+ isRequired: false,
50519
+ transformFunction: null
50520
+ },
50521
+ title: {
50522
+ classPropertyName: "title",
50523
+ publicName: "title",
50524
+ isSignal: true,
50525
+ isRequired: false,
50526
+ transformFunction: null
50527
+ },
50528
+ loading: {
50529
+ classPropertyName: "loading",
50530
+ publicName: "loading",
50531
+ isSignal: true,
50532
+ isRequired: false,
50533
+ transformFunction: null
50534
+ },
50535
+ error: {
50536
+ classPropertyName: "error",
50537
+ publicName: "error",
50538
+ isSignal: true,
50539
+ isRequired: false,
50540
+ transformFunction: null
50541
+ },
50542
+ searchText: {
50543
+ classPropertyName: "searchText",
50544
+ publicName: "searchText",
50545
+ isSignal: true,
50546
+ isRequired: false,
50547
+ transformFunction: null
50548
+ },
50549
+ searchPlaceholder: {
50550
+ classPropertyName: "searchPlaceholder",
50551
+ publicName: "searchPlaceholder",
50552
+ isSignal: true,
50553
+ isRequired: false,
50554
+ transformFunction: null
50555
+ },
50556
+ searchAriaLabel: {
50557
+ classPropertyName: "searchAriaLabel",
50558
+ publicName: "searchAriaLabel",
50559
+ isSignal: true,
50560
+ isRequired: false,
50561
+ transformFunction: null
50562
+ },
50563
+ showFilters: {
50564
+ classPropertyName: "showFilters",
50565
+ publicName: "showFilters",
50566
+ isSignal: true,
50567
+ isRequired: false,
50568
+ transformFunction: null
50569
+ },
50570
+ filterTabs: {
50571
+ classPropertyName: "filterTabs",
50572
+ publicName: "filterTabs",
50573
+ isSignal: true,
50574
+ isRequired: false,
50575
+ transformFunction: null
50576
+ },
50577
+ filterCounts: {
50578
+ classPropertyName: "filterCounts",
50579
+ publicName: "filterCounts",
50580
+ isSignal: true,
50581
+ isRequired: false,
50582
+ transformFunction: null
50583
+ },
50584
+ activeFilter: {
50585
+ classPropertyName: "activeFilter",
50586
+ publicName: "activeFilter",
50587
+ isSignal: true,
50588
+ isRequired: false,
50589
+ transformFunction: null
50590
+ },
50591
+ filterAriaLabel: {
50592
+ classPropertyName: "filterAriaLabel",
50593
+ publicName: "filterAriaLabel",
50594
+ isSignal: true,
50595
+ isRequired: false,
50596
+ transformFunction: null
50597
+ },
50598
+ page: {
50599
+ classPropertyName: "page",
50600
+ publicName: "page",
50601
+ isSignal: true,
50602
+ isRequired: false,
50603
+ transformFunction: null
50604
+ },
50605
+ pageSize: {
50606
+ classPropertyName: "pageSize",
50607
+ publicName: "pageSize",
50608
+ isSignal: true,
50609
+ isRequired: false,
50610
+ transformFunction: null
50611
+ },
50612
+ totalItems: {
50613
+ classPropertyName: "totalItems",
50614
+ publicName: "totalItems",
50615
+ isSignal: true,
50616
+ isRequired: false,
50617
+ transformFunction: null
50618
+ },
50619
+ paginationAriaLabel: {
50620
+ classPropertyName: "paginationAriaLabel",
50621
+ publicName: "paginationAriaLabel",
50622
+ isSignal: true,
50623
+ isRequired: false,
50624
+ transformFunction: null
50625
+ },
50626
+ listAriaLabel: {
50627
+ classPropertyName: "listAriaLabel",
50628
+ publicName: "listAriaLabel",
50629
+ isSignal: true,
50630
+ isRequired: false,
50631
+ transformFunction: null
50632
+ },
50633
+ loadingLabel: {
50634
+ classPropertyName: "loadingLabel",
50635
+ publicName: "loadingLabel",
50636
+ isSignal: true,
50637
+ isRequired: false,
50638
+ transformFunction: null
50639
+ },
50640
+ emptyTitle: {
50641
+ classPropertyName: "emptyTitle",
50642
+ publicName: "emptyTitle",
50643
+ isSignal: true,
50644
+ isRequired: false,
50645
+ transformFunction: null
50646
+ },
50647
+ emptyMessage: {
50648
+ classPropertyName: "emptyMessage",
50649
+ publicName: "emptyMessage",
50650
+ isSignal: true,
50651
+ isRequired: false,
50652
+ transformFunction: null
50653
+ },
50654
+ emptyReadOnlyMessage: {
50655
+ classPropertyName: "emptyReadOnlyMessage",
50656
+ publicName: "emptyReadOnlyMessage",
50657
+ isSignal: true,
50658
+ isRequired: false,
50659
+ transformFunction: null
50660
+ },
50661
+ filteredEmptyTitle: {
50662
+ classPropertyName: "filteredEmptyTitle",
50663
+ publicName: "filteredEmptyTitle",
50664
+ isSignal: true,
50665
+ isRequired: false,
50666
+ transformFunction: null
50667
+ },
50668
+ filteredEmptyMessage: {
50669
+ classPropertyName: "filteredEmptyMessage",
50670
+ publicName: "filteredEmptyMessage",
50671
+ isSignal: true,
50672
+ isRequired: false,
50673
+ transformFunction: null
50674
+ },
50675
+ noMessagesText: {
50676
+ classPropertyName: "noMessagesText",
50677
+ publicName: "noMessagesText",
50678
+ isSignal: true,
50679
+ isRequired: false,
50680
+ transformFunction: null
50681
+ },
50682
+ allowNew: {
50683
+ classPropertyName: "allowNew",
50684
+ publicName: "allowNew",
50685
+ isSignal: true,
50686
+ isRequired: false,
50687
+ transformFunction: null
50688
+ },
50689
+ allowDelete: {
50690
+ classPropertyName: "allowDelete",
50691
+ publicName: "allowDelete",
50692
+ isSignal: true,
50693
+ isRequired: false,
50694
+ transformFunction: null
50695
+ },
50696
+ showRowArrow: {
50697
+ classPropertyName: "showRowArrow",
50698
+ publicName: "showRowArrow",
50699
+ isSignal: true,
50700
+ isRequired: false,
50701
+ transformFunction: null
50702
+ },
50703
+ newLabel: {
50704
+ classPropertyName: "newLabel",
50705
+ publicName: "newLabel",
50706
+ isSignal: true,
50707
+ isRequired: false,
50708
+ transformFunction: null
50709
+ },
50710
+ newTooltip: {
50711
+ classPropertyName: "newTooltip",
50712
+ publicName: "newTooltip",
50713
+ isSignal: true,
50714
+ isRequired: false,
50715
+ transformFunction: null
50716
+ },
50717
+ deleteRowLabel: {
50718
+ classPropertyName: "deleteRowLabel",
50719
+ publicName: "deleteRowLabel",
50720
+ isSignal: true,
50721
+ isRequired: false,
50722
+ transformFunction: null
50723
+ },
50724
+ messages: {
50725
+ classPropertyName: "messages",
50726
+ publicName: "messages",
50727
+ isSignal: true,
50728
+ isRequired: false,
50729
+ transformFunction: null
50730
+ },
50731
+ messagesLoading: {
50732
+ classPropertyName: "messagesLoading",
50733
+ publicName: "messagesLoading",
50734
+ isSignal: true,
50735
+ isRequired: false,
50736
+ transformFunction: null
50737
+ },
50738
+ messagesError: {
50739
+ classPropertyName: "messagesError",
50740
+ publicName: "messagesError",
50741
+ isSignal: true,
50742
+ isRequired: false,
50743
+ transformFunction: null
50744
+ },
50745
+ hasEarlier: {
50746
+ classPropertyName: "hasEarlier",
50747
+ publicName: "hasEarlier",
50748
+ isSignal: true,
50749
+ isRequired: false,
50750
+ transformFunction: null
50751
+ },
50752
+ loadingEarlier: {
50753
+ classPropertyName: "loadingEarlier",
50754
+ publicName: "loadingEarlier",
50755
+ isSignal: true,
50756
+ isRequired: false,
50757
+ transformFunction: null
50758
+ },
50759
+ loadEarlierLabel: {
50760
+ classPropertyName: "loadEarlierLabel",
50761
+ publicName: "loadEarlierLabel",
50762
+ isSignal: true,
50763
+ isRequired: false,
50764
+ transformFunction: null
50765
+ },
50766
+ statusActionLabel: {
50767
+ classPropertyName: "statusActionLabel",
50768
+ publicName: "statusActionLabel",
50769
+ isSignal: true,
50770
+ isRequired: false,
50771
+ transformFunction: null
50772
+ },
50773
+ statusActionIcon: {
50774
+ classPropertyName: "statusActionIcon",
50775
+ publicName: "statusActionIcon",
50776
+ isSignal: true,
50777
+ isRequired: false,
50778
+ transformFunction: null
50779
+ },
50780
+ statusChanging: {
50781
+ classPropertyName: "statusChanging",
50782
+ publicName: "statusChanging",
50783
+ isSignal: true,
50784
+ isRequired: false,
50785
+ transformFunction: null
50786
+ },
50787
+ templatesEnabled: {
50788
+ classPropertyName: "templatesEnabled",
50789
+ publicName: "templatesEnabled",
50790
+ isSignal: true,
50791
+ isRequired: false,
50792
+ transformFunction: null
50793
+ },
50794
+ templateLabel: {
50795
+ classPropertyName: "templateLabel",
50796
+ publicName: "templateLabel",
50797
+ isSignal: true,
50798
+ isRequired: false,
50799
+ transformFunction: null
50800
+ },
50801
+ deleteThreadLabel: {
50802
+ classPropertyName: "deleteThreadLabel",
50803
+ publicName: "deleteThreadLabel",
50804
+ isSignal: true,
50805
+ isRequired: false,
50806
+ transformFunction: null
50807
+ },
50808
+ backLabel: {
50809
+ classPropertyName: "backLabel",
50810
+ publicName: "backLabel",
50811
+ isSignal: true,
50812
+ isRequired: false,
50813
+ transformFunction: null
50814
+ },
50815
+ threadAriaLabel: {
50816
+ classPropertyName: "threadAriaLabel",
50817
+ publicName: "threadAriaLabel",
50818
+ isSignal: true,
50819
+ isRequired: false,
50820
+ transformFunction: null
50821
+ },
50822
+ messagesAriaLabel: {
50823
+ classPropertyName: "messagesAriaLabel",
50824
+ publicName: "messagesAriaLabel",
50825
+ isSignal: true,
50826
+ isRequired: false,
50827
+ transformFunction: null
50828
+ },
50829
+ threadEmptyTitle: {
50830
+ classPropertyName: "threadEmptyTitle",
50831
+ publicName: "threadEmptyTitle",
50832
+ isSignal: true,
50833
+ isRequired: false,
50834
+ transformFunction: null
50835
+ },
50836
+ threadEmptyMessage: {
50837
+ classPropertyName: "threadEmptyMessage",
50838
+ publicName: "threadEmptyMessage",
50839
+ isSignal: true,
50840
+ isRequired: false,
50841
+ transformFunction: null
50842
+ },
50843
+ noMessagesWriteText: {
50844
+ classPropertyName: "noMessagesWriteText",
50845
+ publicName: "noMessagesWriteText",
50846
+ isSignal: true,
50847
+ isRequired: false,
50848
+ transformFunction: null
50849
+ },
50850
+ noMessagesReadText: {
50851
+ classPropertyName: "noMessagesReadText",
50852
+ publicName: "noMessagesReadText",
50853
+ isSignal: true,
50854
+ isRequired: false,
50855
+ transformFunction: null
50856
+ },
50857
+ youLabel: {
50858
+ classPropertyName: "youLabel",
50859
+ publicName: "youLabel",
50860
+ isSignal: true,
50861
+ isRequired: false,
50862
+ transformFunction: null
50863
+ },
50864
+ openMediaLabel: {
50865
+ classPropertyName: "openMediaLabel",
50866
+ publicName: "openMediaLabel",
50867
+ isSignal: true,
50868
+ isRequired: false,
50869
+ transformFunction: null
50870
+ },
50871
+ imageFallbackName: {
50872
+ classPropertyName: "imageFallbackName",
50873
+ publicName: "imageFallbackName",
50874
+ isSignal: true,
50875
+ isRequired: false,
50876
+ transformFunction: null
50877
+ },
50878
+ fileFallbackName: {
50879
+ classPropertyName: "fileFallbackName",
50880
+ publicName: "fileFallbackName",
50881
+ isSignal: true,
50882
+ isRequired: false,
50883
+ transformFunction: null
50884
+ },
50885
+ hasContext: {
50886
+ classPropertyName: "hasContext",
50887
+ publicName: "hasContext",
50888
+ isSignal: true,
50889
+ isRequired: false,
50890
+ transformFunction: null
50891
+ },
50892
+ contextOpen: {
50893
+ classPropertyName: "contextOpen",
50894
+ publicName: "contextOpen",
50895
+ isSignal: true,
50896
+ isRequired: false,
50897
+ transformFunction: null
50898
+ },
50899
+ contextTitle: {
50900
+ classPropertyName: "contextTitle",
50901
+ publicName: "contextTitle",
50902
+ isSignal: true,
50903
+ isRequired: false,
50904
+ transformFunction: null
50905
+ },
50906
+ showContextLabel: {
50907
+ classPropertyName: "showContextLabel",
50908
+ publicName: "showContextLabel",
50909
+ isSignal: true,
50910
+ isRequired: false,
50911
+ transformFunction: null
50912
+ },
50913
+ hideContextLabel: {
50914
+ classPropertyName: "hideContextLabel",
50915
+ publicName: "hideContextLabel",
50916
+ isSignal: true,
50917
+ isRequired: false,
50918
+ transformFunction: null
50919
+ },
50920
+ closeContextLabel: {
50921
+ classPropertyName: "closeContextLabel",
50922
+ publicName: "closeContextLabel",
50923
+ isSignal: true,
50924
+ isRequired: false,
50925
+ transformFunction: null
50926
+ },
50927
+ canWrite: {
50928
+ classPropertyName: "canWrite",
50929
+ publicName: "canWrite",
50930
+ isSignal: true,
50931
+ isRequired: false,
50932
+ transformFunction: null
50933
+ },
50934
+ draft: {
50935
+ classPropertyName: "draft",
50936
+ publicName: "draft",
50937
+ isSignal: true,
50938
+ isRequired: false,
50939
+ transformFunction: null
50940
+ },
50941
+ sending: {
50942
+ classPropertyName: "sending",
50943
+ publicName: "sending",
50944
+ isSignal: true,
50945
+ isRequired: false,
50946
+ transformFunction: null
50947
+ },
50948
+ composerDisabled: {
50949
+ classPropertyName: "composerDisabled",
50950
+ publicName: "composerDisabled",
50951
+ isSignal: true,
50952
+ isRequired: false,
50953
+ transformFunction: null
50954
+ },
50955
+ sendBlocked: {
50956
+ classPropertyName: "sendBlocked",
50957
+ publicName: "sendBlocked",
50958
+ isSignal: true,
50959
+ isRequired: false,
50960
+ transformFunction: null
50961
+ },
50962
+ composerNotice: {
50963
+ classPropertyName: "composerNotice",
50964
+ publicName: "composerNotice",
50965
+ isSignal: true,
50966
+ isRequired: false,
50967
+ transformFunction: null
50968
+ },
50969
+ composerStatus: {
50970
+ classPropertyName: "composerStatus",
50971
+ publicName: "composerStatus",
50972
+ isSignal: true,
50973
+ isRequired: false,
50974
+ transformFunction: null
50975
+ },
50976
+ composerError: {
50977
+ classPropertyName: "composerError",
50978
+ publicName: "composerError",
50979
+ isSignal: true,
50980
+ isRequired: false,
50981
+ transformFunction: null
50982
+ },
50983
+ maxLength: {
50984
+ classPropertyName: "maxLength",
50985
+ publicName: "maxLength",
50986
+ isSignal: true,
50987
+ isRequired: false,
50988
+ transformFunction: null
50989
+ },
50990
+ attachment: {
50991
+ classPropertyName: "attachment",
50992
+ publicName: "attachment",
50993
+ isSignal: true,
50994
+ isRequired: false,
50995
+ transformFunction: null
50996
+ },
50997
+ uploading: {
50998
+ classPropertyName: "uploading",
50999
+ publicName: "uploading",
51000
+ isSignal: true,
51001
+ isRequired: false,
51002
+ transformFunction: null
51003
+ },
51004
+ attachEnabled: {
51005
+ classPropertyName: "attachEnabled",
51006
+ publicName: "attachEnabled",
51007
+ isSignal: true,
51008
+ isRequired: false,
51009
+ transformFunction: null
51010
+ },
51011
+ acceptedFiles: {
51012
+ classPropertyName: "acceptedFiles",
51013
+ publicName: "acceptedFiles",
51014
+ isSignal: true,
51015
+ isRequired: false,
51016
+ transformFunction: null
51017
+ },
51018
+ maxFileSize: {
51019
+ classPropertyName: "maxFileSize",
51020
+ publicName: "maxFileSize",
51021
+ isSignal: true,
51022
+ isRequired: false,
51023
+ transformFunction: null
51024
+ },
51025
+ typeMessage: {
51026
+ classPropertyName: "typeMessage",
51027
+ publicName: "typeMessage",
51028
+ isSignal: true,
51029
+ isRequired: false,
51030
+ transformFunction: null
51031
+ },
51032
+ sizeMessage: {
51033
+ classPropertyName: "sizeMessage",
51034
+ publicName: "sizeMessage",
51035
+ isSignal: true,
51036
+ isRequired: false,
51037
+ transformFunction: null
51038
+ },
51039
+ composeLabel: {
51040
+ classPropertyName: "composeLabel",
51041
+ publicName: "composeLabel",
51042
+ isSignal: true,
51043
+ isRequired: false,
51044
+ transformFunction: null
51045
+ },
51046
+ composePlaceholder: {
51047
+ classPropertyName: "composePlaceholder",
51048
+ publicName: "composePlaceholder",
51049
+ isSignal: true,
51050
+ isRequired: false,
51051
+ transformFunction: null
51052
+ },
51053
+ sendLabel: {
51054
+ classPropertyName: "sendLabel",
51055
+ publicName: "sendLabel",
51056
+ isSignal: true,
51057
+ isRequired: false,
51058
+ transformFunction: null
51059
+ },
51060
+ attachLabel: {
51061
+ classPropertyName: "attachLabel",
51062
+ publicName: "attachLabel",
51063
+ isSignal: true,
51064
+ isRequired: false,
51065
+ transformFunction: null
51066
+ },
51067
+ removeAttachmentLabel: {
51068
+ classPropertyName: "removeAttachmentLabel",
51069
+ publicName: "removeAttachmentLabel",
51070
+ isSignal: true,
51071
+ isRequired: false,
51072
+ transformFunction: null
51073
+ },
51074
+ attachmentPreviewLabel: {
51075
+ classPropertyName: "attachmentPreviewLabel",
51076
+ publicName: "attachmentPreviewLabel",
51077
+ isSignal: true,
51078
+ isRequired: false,
51079
+ transformFunction: null
51080
+ },
51081
+ now: {
51082
+ classPropertyName: "now",
51083
+ publicName: "now",
51084
+ isSignal: true,
51085
+ isRequired: false,
51086
+ transformFunction: null
51087
+ }
51088
+ },
51089
+ outputs: {
51090
+ searchText: "searchTextChange",
51091
+ contextOpen: "contextOpenChange",
51092
+ draft: "draftChange",
51093
+ searchChange: "searchChange",
51094
+ filterChange: "filterChange",
51095
+ pageChange: "pageChange",
51096
+ selectConversation: "selectConversation",
51097
+ back: "back",
51098
+ newConversation: "newConversation",
51099
+ retry: "retry",
51100
+ deleteConversation: "deleteConversation",
51101
+ statusChange: "statusChange",
51102
+ templateRequest: "templateRequest",
51103
+ send: "send",
51104
+ filesSelected: "filesSelected",
51105
+ attachmentRemove: "attachmentRemove",
51106
+ mediaOpen: "mediaOpen",
51107
+ messageAction: "messageAction",
51108
+ loadEarlier: "loadEarlier",
51109
+ messagesRetry: "messagesRetry"
51110
+ },
51111
+ viewQueries: [
51112
+ {
51113
+ propertyName: "threadHeading",
51114
+ first: true,
51115
+ predicate: ["threadHeading"],
51116
+ descendants: true,
51117
+ isSignal: true
51118
+ },
51119
+ {
51120
+ propertyName: "messagesEl",
51121
+ first: true,
51122
+ predicate: ["messagesEl"],
51123
+ descendants: true,
51124
+ isSignal: true
51125
+ },
51126
+ {
51127
+ propertyName: "contextPanel",
51128
+ first: true,
51129
+ predicate: ["contextPanel"],
51130
+ descendants: true,
51131
+ isSignal: true
51132
+ },
51133
+ {
51134
+ propertyName: "fileInput",
51135
+ first: true,
51136
+ predicate: FileInputComponent,
51137
+ descendants: true,
51138
+ isSignal: true
51139
+ }
51140
+ ],
51141
+ ngImport: i0,
51142
+ template: `
51143
+ <div class="cv-layout" [class.has-context]="contextVisible()" data-testid="conversations">
51144
+ @if (contextVisible()) {
51145
+ <div class="cv-context-backdrop" (click)="closeContext()" aria-hidden="true"></div>
51146
+ }
51147
+
51148
+ <!-- LEFT: conversation list -->
51149
+ <section class="cv-list-panel" [class.cv-hidden-mobile]="!!selected()" [attr.aria-labelledby]="titleId">
51150
+ <div class="cv-list-header">
51151
+ <h2 class="cv-list-title" [id]="titleId">{{ title() }}</h2>
51152
+ @if (canWrite() && allowNew()) {
51153
+ <ui-button class="cv-new-btn" variant="primary" size="sm" [ariaLabel]="newLabel()" [uiTooltip]="newTooltip()" tooltipPosition="bottom" (click)="newConversation.emit()" data-testid="new-message-btn">
51154
+ <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/><line x1="12" y1="8" x2="12" y2="16"/><line x1="8" y1="12" x2="16" y2="12"/></svg>
51155
+ </ui-button>
51156
+ }
51157
+ </div>
51158
+
51159
+ @if (showFilters()) {
51160
+ <div class="cv-search">
51161
+ <ui-search-input [placeholder]="searchPlaceholder()" [ariaLabel]="searchAriaLabel()" [(value)]="searchText" (searchChange)="searchChange.emit($event)" data-testid="conv-search" />
51162
+ </div>
51163
+ @if (filterTabs().length) {
51164
+ <div class="cv-filters">
51165
+ <ui-quick-filter-tabs [ariaLabel]="filterAriaLabel()" [tabs]="filterTabs()" [counts]="filterCounts()" [activeValue]="activeFilter()" (tabChange)="filterChange.emit($event)" data-testid="conv-filters" />
51166
+ </div>
51167
+ }
51168
+ }
51169
+
51170
+ @if (loading()) {
51171
+ <div class="cv-loading" aria-busy="true" [attr.aria-label]="loadingLabel()" data-testid="conv-loading">
51172
+ @for (i of skeletonRows; track i) {
51173
+ <div class="cv-skeleton">
51174
+ <ui-skeleton [height]="40" width="40px" [radius]="20" />
51175
+ <div class="cv-skel-content">
51176
+ <div class="cv-skel-row">
51177
+ <ui-skeleton width="55%" [height]="12" />
51178
+ <ui-skeleton width="48px" [height]="10" />
51179
+ </div>
51180
+ <ui-skeleton width="30%" [height]="10" [mb]="2" />
51181
+ <ui-skeleton width="85%" [height]="10" />
51182
+ </div>
51183
+ </div>
51184
+ }
51185
+ </div>
51186
+ } @else if (error()) {
51187
+ <div class="cv-error" data-testid="conv-error">
51188
+ <ui-alert variant="danger">{{ error() }}</ui-alert>
51189
+ <ui-button variant="secondary" size="sm" (click)="retry.emit()" data-testid="conv-retry">Retry</ui-button>
51190
+ </div>
51191
+ } @else if (conversations().length === 0) {
51192
+ <ui-empty-state iconType="message" data-testid="conv-empty" [title]="filtering() ? filteredEmptyTitle() : emptyTitle()" [message]="emptyText()" />
51193
+ } @else {
51194
+ <div class="cv-list">
51195
+ <ui-list [ariaLabel]="listAriaLabel()" [items]="conversations()" [trackBy]="trackConversation" [navigable]="true" [arrow]="false" (itemClick)="onRowOpen($event)">
51196
+ <ng-template let-conv>
51197
+ <div class="cv-item" data-testid="conv-item" [attr.data-conversation-id]="conv.id"
51198
+ [class.selected]="selected()?.id === conv.id" [class.unread]="(conv.unreadCount ?? 0) > 0">
51199
+ <ui-avatar [initials]="initial(conv.name)" [name]="conv.name" [size]="40" />
51200
+ <div class="cv-item-info">
51201
+ <div class="cv-item-top">
51202
+ <span class="cv-name">{{ conv.name }}</span>@if (selected()?.id === conv.id) {<span class="cv-sr-only">, open</span>}
51203
+ <span class="cv-time">{{ relativeTime(conv.lastMessageAt) }}</span>
51204
+ </div>
51205
+ @if (conv.subtitle) { <span class="cv-subtitle">{{ conv.subtitle }}</span> }
51206
+ <div class="cv-item-bottom">
51207
+ <p class="cv-preview">{{ preview(conv.preview) || noMessagesText() }}</p>
51208
+ <div class="cv-item-right">
51209
+ @if (conv.statusLabel) { <ui-badge [label]="conv.statusLabel" variant="gray" /> }
51210
+ @if ((conv.unreadCount ?? 0) > 0) {
51211
+ <ui-badge class="cv-unread-badge" [label]="'' + conv.unreadCount" variant="blue" data-testid="conv-unread" />
51212
+ <span class="cv-sr-only">unread</span>
51213
+ }
51214
+ @if (canWrite() && allowDelete()) {
51215
+ <ui-button class="cv-delete-btn" variant="icon-danger" [ariaLabel]="deleteRowLabel() + ' ' + conv.name" (click)="$event.stopPropagation(); deleteConversation.emit(conv)" data-testid="conv-delete-btn">
51216
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M3 6h18"/><path d="M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6"/><path d="M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2"/></svg>
51217
+ </ui-button>
51218
+ }
51219
+ </div>
51220
+ </div>
51221
+ </div>
51222
+ @if (showRowArrow()) {
51223
+ <svg class="cv-row-arrow" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false" data-testid="conv-arrow"><path d="M9 18l6-6-6-6"/></svg>
51224
+ }
51225
+ </div>
51226
+ </ng-template>
51227
+ </ui-list>
51228
+ <ui-pagination [ariaLabel]="paginationAriaLabel()" [page]="page()" [pageSize]="pageSize()" [totalItems]="totalItems()" (pageChange)="pageChange.emit($event)" />
51229
+ </div>
51230
+ }
51231
+ </section>
51232
+
51233
+ <!-- CENTER: message thread -->
51234
+ <section class="cv-thread-panel" [class.cv-hidden-mobile]="!selected()" [attr.aria-label]="threadAriaLabel()">
51235
+ @if (selected(); as conv) {
51236
+ <div class="cv-thread-header">
51237
+ <ui-button class="cv-back-btn" variant="secondary" size="sm" [ariaLabel]="backLabel()" (click)="onBack()" data-testid="back-to-list">
51238
+ <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><polyline points="15 18 9 12 15 6"/></svg>
51239
+ </ui-button>
51240
+ <div class="cv-thread-header-info">
51241
+ <ui-avatar [initials]="initial(conv.name)" [name]="conv.name" [size]="40" />
51242
+ <div class="cv-thread-header-text">
51243
+ <h3 class="cv-thread-name" #threadHeading tabindex="-1" data-testid="thread-name">{{ conv.name }}</h3>
51244
+ @if (conv.subtitle) { <span class="cv-thread-subtitle" data-testid="thread-phone">{{ conv.subtitle }}</span> }
51245
+ </div>
51246
+ </div>
51247
+ <div class="cv-thread-actions">
51248
+ @if (canWrite() && templatesEnabled()) {
51249
+ <ui-button class="cv-thread-action" variant="secondary" size="sm" [ariaLabel]="templateLabel()" [uiTooltip]="templateLabel()" tooltipPosition="bottom" [disabled]="composerDisabled()" (click)="templateRequest.emit()" data-testid="use-template-btn">
51250
+ <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/></svg>
51251
+ </ui-button>
51252
+ }
51253
+ @if (hasContext()) {
51254
+ <ui-button #contextToggle class="cv-thread-action" [variant]="contextOpen() ? 'primary' : 'secondary'" size="sm" [ariaLabel]="contextOpen() ? hideContextLabel() : showContextLabel()" [uiTooltip]="contextOpen() ? hideContextLabel() : contextTitle()" tooltipPosition="bottom" (click)="toggleContext()" data-testid="context-toggle">
51255
+ <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"/><circle cx="12" cy="7" r="4"/></svg>
51256
+ </ui-button>
51257
+ }
51258
+ @if (canWrite() && statusActionLabel()) {
51259
+ <ui-button class="cv-thread-action" variant="secondary" size="sm" [ariaLabel]="statusActionLabel() ?? ''" [uiTooltip]="statusActionLabel()" tooltipPosition="bottom" [disabled]="statusChanging()" (click)="statusChange.emit(conv)" data-testid="status-btn">
51260
+ @if (statusActionIcon() === 'reopen') {
51261
+ <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><polyline points="1 4 1 10 7 10"/><path d="M3.51 15a9 9 0 1 0 2.13-9.36L1 10"/></svg>
51262
+ } @else {
51263
+ <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/><polyline points="22 4 12 14.01 9 11.01"/></svg>
51264
+ }
51265
+ </ui-button>
51266
+ }
51267
+ @if (canWrite() && allowDelete()) {
51268
+ <ui-button class="cv-thread-action" variant="danger" size="sm" [ariaLabel]="deleteThreadLabel()" [uiTooltip]="deleteThreadLabel()" tooltipPosition="bottom" (click)="deleteConversation.emit(conv)" data-testid="thread-delete-btn">
51269
+ <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M3 6h18"/><path d="M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6"/><path d="M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2"/></svg>
51270
+ </ui-button>
51271
+ }
51272
+ </div>
51273
+ </div>
51274
+
51275
+ <div class="cv-messages" #messagesEl role="log" aria-live="polite" aria-relevant="additions" tabindex="0"
51276
+ [attr.aria-label]="messagesAriaLabel() + ' ' + conv.name" [attr.aria-busy]="messagesLoading()" (scroll)="onMessagesScroll()" data-testid="messages">
51277
+ @if (messagesLoading()) {
51278
+ <div class="cv-messages-loading" data-testid="messages-loading">
51279
+ @for (i of skeletonBubbles; track i) {
51280
+ <div class="cv-msg-skeleton" [class.outbound]="i % 2 === 0">
51281
+ <ui-skeleton [height]="48" [width]="i % 2 === 0 ? '60%' : '55%'" [radius]="16" />
51282
+ </div>
51283
+ }
51284
+ </div>
51285
+ } @else if (messagesError()) {
51286
+ <div class="cv-messages-error" data-testid="thread-error">
51287
+ <ui-alert variant="danger">{{ messagesError() }}</ui-alert>
51288
+ <ui-button variant="secondary" size="sm" (click)="messagesRetry.emit()" data-testid="thread-retry">Retry</ui-button>
51289
+ </div>
51290
+ } @else if (messages().length === 0) {
51291
+ <div class="cv-messages-empty" data-testid="messages-empty">
51292
+ <p>{{ canWrite() ? noMessagesWriteText() : noMessagesReadText() }}</p>
51293
+ </div>
51294
+ } @else {
51295
+ @if (hasEarlier()) {
51296
+ <div class="cv-load-earlier">
51297
+ <ui-button variant="secondary" size="sm" [loading]="loadingEarlier()" (click)="loadEarlier.emit()" data-testid="load-earlier">{{ loadEarlierLabel() }}</ui-button>
51298
+ </div>
51299
+ }
51300
+ @for (row of messageRows(); track row.message.id) {
51301
+ @if (row.separator) { <div class="cv-date-separator"><span>{{ row.separator }}</span></div> }
51302
+ <div class="cv-bubble" data-testid="message" [class.outbound]="row.message.direction === 'outbound'" [class.inbound]="row.message.direction === 'inbound'">
51303
+ <span class="cv-sr-only">{{ row.message.direction === 'outbound' ? youLabel() : conv.name }}:</span>
51304
+ @if (row.message.media; as media) {
51305
+ <div class="cv-media">
51306
+ @if (media.type?.startsWith('image/')) {
51307
+ <button type="button" class="cv-image-btn" (click)="mediaOpen.emit(media.url)" [attr.aria-label]="openMediaLabel() + ' ' + (media.fileName || imageFallbackName())">
51308
+ <img [src]="media.url" [alt]="media.fileName || imageFallbackName()" class="cv-image" loading="lazy" />
51309
+ </button>
51310
+ } @else if (media.type?.startsWith('video/')) {
51311
+ <video [src]="media.url" class="cv-video" controls preload="metadata"></video>
51312
+ } @else {
51313
+ <a [href]="media.url" target="_blank" rel="noopener noreferrer" class="cv-file-link">{{ media.fileName || fileFallbackName() }}</a>
51314
+ }
51315
+ </div>
51316
+ }
51317
+ @if (row.message.body) { <p class="cv-body">{{ row.message.body }}</p> }
51318
+ <span class="cv-meta">
51319
+ @if (row.message.direction === 'outbound' && row.message.sender) { <span class="cv-sender" data-testid="msg-sender">{{ row.message.sender }}</span> }
51320
+ {{ time(row.message) }}
51321
+ @if (row.message.action; as action) {
51322
+ <button type="button" class="cv-msg-action" data-testid="msg-action" (click)="messageAction.emit(row.message)">{{ action.label }}</button>
51323
+ }
51324
+ @if (row.message.direction === 'outbound' && statusLabel(row.message.status)) {
51325
+ <span class="cv-status" [class.failed]="row.message.status === 'failed'" data-testid="msg-status">
51326
+ <span aria-hidden="true">{{ statusMark(row.message.status) }}</span>
51327
+ <span class="cv-sr-only">{{ statusLabel(row.message.status) }}</span>
51328
+ </span>
51329
+ }
51330
+ </span>
51331
+ </div>
51332
+ }
51333
+ }
51334
+ </div>
51335
+
51336
+ @if (canWrite()) {
51337
+ <div class="cv-compose">
51338
+ @if (attachment(); as file) {
51339
+ <div class="cv-attachment" data-testid="attachment-preview">
51340
+ @if (file.previewUrl) {
51341
+ <img [src]="file.previewUrl" [alt]="attachmentPreviewLabel()" class="cv-attachment-thumb" />
51342
+ } @else {
51343
+ <span class="cv-attachment-name">{{ file.fileName }}</span>
51344
+ }
51345
+ <ui-button class="cv-attachment-remove" variant="icon-danger" [ariaLabel]="removeAttachmentLabel()" (click)="attachmentRemove.emit()" data-testid="attachment-remove">
51346
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>
51347
+ </ui-button>
51348
+ </div>
51349
+ }
51350
+ <div class="cv-compose-row">
51351
+ @if (attachEnabled()) {
51352
+ <ui-button class="cv-attach-btn" variant="icon" [ariaLabel]="attachLabel()" [disabled]="uploading() || composerDisabled()" [loading]="uploading()" (click)="openFilePicker()" data-testid="attach-btn">
51353
+ <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M21.44 11.05l-9.19 9.19a6 6 0 0 1-8.49-8.49l9.19-9.19a4 4 0 0 1 5.66 5.66l-9.2 9.19a2 2 0 0 1-2.83-2.83l8.49-8.48"/></svg>
51354
+ </ui-button>
51355
+ <ui-file-input [showField]="false" [accept]="acceptedFiles()" [maxSize]="maxFileSize()" [toastOnReject]="true"
51356
+ [typeMessage]="typeMessage()" [sizeMessage]="sizeMessage()" (filesSelected)="filesSelected.emit($event)" data-testid="attach-input" />
51357
+ }
51358
+ <ui-textarea-input class="cv-compose-input" [ariaLabel]="composeLabel()" [placeholder]="composePlaceholder()" [rows]="1" [maxlength]="maxLength()"
51359
+ [ngModel]="draft()" (ngModelChange)="draft.set($event)" [disabled]="composerDisabled()" [error]="composerError()"
51360
+ (keydown)="onComposeKeydown($event)" data-testid="compose-input" />
51361
+ <ui-button class="cv-send-btn" variant="primary" [ariaLabel]="sendLabel()" [disabled]="!canSend()" [loading]="sending()" (click)="sendMessage()" data-testid="send-btn">
51362
+ <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><line x1="22" y1="2" x2="11" y2="13"/><polygon points="22 2 15 22 11 13 2 9 22 2"/></svg>
51363
+ </ui-button>
51364
+ </div>
51365
+ @if (composerNotice()) {
51366
+ <ui-alert variant="warning" data-testid="compose-opted-out">{{ composerNotice() }}</ui-alert>
51367
+ }
51368
+ <!-- Always in the page (a live region that appears together with its text is often not announced): only its text comes and goes. -->
51369
+ <p class="cv-compose-status" role="status" data-testid="compose-loading-contact">{{ composerStatus() }}</p>
51370
+ </div>
51371
+ }
51372
+ } @else {
51373
+ <ui-empty-state iconType="message" [title]="threadEmptyTitle()" [message]="threadEmptyMessage()" data-testid="thread-empty" />
51374
+ }
51375
+ </section>
51376
+
51377
+ <!-- RIGHT: contact panel (the host's content) -->
51378
+ @if (contextVisible()) {
51379
+ <aside class="cv-context" #contextPanel tabindex="-1" [attr.aria-label]="contextTitle()" (keydown.escape)="closeContext(true)" data-testid="context-panel">
51380
+ <div class="cv-context-header">
51381
+ <h3>{{ contextTitle() }}</h3>
51382
+ <ui-button variant="icon" [ariaLabel]="closeContextLabel()" (click)="closeContext(true)" data-testid="context-close">
51383
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>
51384
+ </ui-button>
51385
+ </div>
51386
+ <div class="cv-context-body"><ng-content select="[uiConversationsContext]" /></div>
51387
+ </aside>
51388
+ }
51389
+ </div>
51390
+ `,
51391
+ isInline: true,
51392
+ styles: [":host{display:flex;flex:1;min-height:0;min-width:0}.cv-sr-only{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}.cv-layout{display:grid;grid-template-columns:340px 1fr;flex:1;min-height:0;min-width:0;background:#fff;border-radius:12px;overflow:hidden;box-shadow:0 1px 3px #0000000f;border:1px solid #e2e8f0}.cv-layout.has-context{grid-template-columns:340px 1fr 280px}.cv-list-panel{display:flex;flex-direction:column;min-height:0;border-right:1px solid #e2e8f0;background:#f8fafc;overflow:hidden}.cv-list-header{display:flex;align-items:center;justify-content:space-between;padding:20px 20px 12px}.cv-list-title{margin:0;font-size:1.125rem;font-weight:700;color:#1e293b}.cv-search,.cv-filters{padding:0 16px 12px}.cv-list{flex:1;min-height:0;overflow-y:auto;overscroll-behavior:contain}.cv-item{display:flex;gap:12px;padding:14px 16px;border-bottom:1px solid #f1f5f9;transition:background .15s}.cv-item.unread{background:#fffbeb}.cv-item.selected{background:#eff6ff;box-shadow:inset 3px 0 #2563eb}.cv-item-info{flex:1;min-width:0}.cv-row-arrow{flex:0 0 auto;align-self:center;color:#94a3b8}.cv-item-top{display:flex;justify-content:space-between;align-items:center;margin-bottom:4px}.cv-name{font-size:.875rem;font-weight:600;color:#1e293b;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.cv-time{font-size:.6875rem;color:#64748b;flex-shrink:0;margin-left:8px}.cv-subtitle{font-size:.6875rem;color:#64748b;display:block;margin-bottom:2px}.cv-item-bottom{display:flex;justify-content:space-between;align-items:center;gap:8px}.cv-preview{margin:0;font-size:.8125rem;color:#64748b;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;flex:1;min-width:0}.cv-item-right{display:flex;align-items:center;gap:6px;flex-shrink:0}.cv-delete-btn{opacity:0;transition:opacity .15s}.cv-item:hover .cv-delete-btn,.cv-item:focus-within .cv-delete-btn,.cv-delete-btn:focus-within{opacity:1}@media(hover:none){.cv-delete-btn{opacity:1}}.cv-loading{padding:8px 0}.cv-skeleton{display:flex;gap:12px;align-items:flex-start;padding:14px 16px;border-bottom:1px solid #f1f5f9}.cv-skel-content{flex:1;min-width:0;display:flex;flex-direction:column;gap:6px;padding-top:2px}.cv-skel-row{display:flex;justify-content:space-between;gap:8px}.cv-error{display:flex;flex-direction:column;align-items:center;gap:12px;padding:24px 16px;text-align:center}.cv-thread-panel{display:flex;flex-direction:column;min-width:0;min-height:0;overflow:hidden;background:#fff}.cv-thread-header{display:flex;align-items:center;gap:12px;padding:16px 20px;border-bottom:1px solid #e2e8f0;background:#fff}.cv-back-btn{display:none}.cv-thread-header-info{display:flex;align-items:center;gap:12px;flex:1;min-width:0}.cv-thread-header-text{min-width:0;display:flex;flex-direction:column}.cv-thread-name{margin:0;font-size:.9375rem;font-weight:600;color:#1e293b;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.cv-thread-name:focus{outline:none}.cv-thread-name:focus-visible{outline:2px solid #2563eb;outline-offset:2px;border-radius:4px}.cv-thread-subtitle{font-size:.75rem;color:#64748b}.cv-thread-actions{display:flex;align-items:center;gap:8px}.cv-messages{flex:1;min-height:0;overflow-y:auto;overflow-x:hidden;overscroll-behavior:contain;padding:20px 24px;display:flex;flex-direction:column;gap:4px;background:#f8fafc}.cv-messages:focus-visible{outline:2px solid #2563eb;outline-offset:-2px}.cv-messages-loading{display:flex;flex-direction:column;gap:12px;padding:20px 0}.cv-msg-skeleton{display:flex}.cv-msg-skeleton.outbound{justify-content:flex-end}.cv-messages-error{display:flex;flex-direction:column;align-items:center;gap:12px;padding:24px 16px;text-align:center}.cv-load-earlier{display:flex;justify-content:center;padding:4px 0 12px}.cv-sender{font-weight:600}.cv-msg-action{padding:0;border:0;background:none;color:inherit;font:inherit;text-decoration:underline;cursor:pointer}.cv-msg-action:focus-visible{outline:2px solid currentColor;outline-offset:2px;border-radius:2px}.cv-messages-empty{display:flex;align-items:center;justify-content:center;flex:1}.cv-messages-empty p{margin:0;font-size:.875rem;color:#64748b;text-align:center}.cv-date-separator{display:flex;align-items:center;justify-content:center;padding:16px 0 8px}.cv-date-separator span{padding:4px 14px;border-radius:12px;background:#e2e8f0;font-size:.6875rem;font-weight:600;color:#475569;text-transform:uppercase;letter-spacing:.3px}.cv-bubble{max-width:70%;padding:10px 14px;border-radius:16px;position:relative;word-break:break-word;overflow-wrap:break-word}.cv-bubble.inbound{align-self:flex-start;background:#fff;border:1px solid #e2e8f0;border-bottom-left-radius:4px}.cv-bubble.inbound .cv-body{color:#1e293b}.cv-bubble.inbound .cv-meta{color:#64748b}.cv-bubble.outbound{align-self:flex-end;background:#2563eb;border-bottom-right-radius:4px}.cv-bubble.outbound .cv-body,.cv-bubble.outbound .cv-meta{color:#fff}@media(prefers-reduced-motion:no-preference){.cv-bubble{animation:cv-appear .2s ease}.cv-context{animation:cv-slide-in .25s ease}}.cv-body{margin:0;font-size:.875rem;line-height:1.45;word-break:break-word;white-space:pre-wrap}.cv-media{margin-bottom:6px}.cv-image-btn{display:block;padding:0;border:0;background:none;cursor:pointer;border-radius:8px}.cv-image-btn:focus-visible{outline:2px solid #fff;outline-offset:2px;box-shadow:0 0 0 4px #2563eb}.cv-image{display:block;max-width:240px;max-height:240px;border-radius:8px;object-fit:cover}.cv-video{max-width:240px;max-height:200px;border-radius:8px}.cv-file-link{font-size:.8125rem;color:#fff;text-decoration:underline}.cv-bubble.inbound .cv-file-link{color:#2563eb}.cv-meta{display:flex;align-items:center;gap:6px;justify-content:flex-end;font-size:.6875rem;margin-top:4px}.cv-status{font-weight:500}.cv-status.failed{color:#fff;font-weight:700}.cv-bubble.inbound .cv-status.failed{color:#dc2626}.cv-compose{display:flex;flex-direction:column;padding:12px 20px 16px;padding-bottom:calc(16px + env(safe-area-inset-bottom,0px));border-top:1px solid #e2e8f0;background:#fff}.cv-compose-row{display:flex;align-items:flex-end;gap:10px}.cv-compose-input{flex:1;min-width:0}.cv-attach-btn,.cv-send-btn{flex-shrink:0}.cv-attachment{display:flex;align-items:center;gap:8px;padding:8px 12px;margin-bottom:8px;background:#f8fafc;border:1px solid #e2e8f0;border-radius:8px}.cv-attachment-thumb{width:48px;height:48px;object-fit:cover;border-radius:6px}.cv-attachment-name{font-size:.8125rem;color:#475569;flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.cv-attachment-remove{flex-shrink:0}.cv-compose-status{margin:4px 0 0;font-size:.8125rem;color:#64748b}.cv-compose-status:empty{margin:0}.cv-context-backdrop{display:none}.cv-context{width:100%;min-width:0;border-left:1px solid #e2e8f0;background:#fff;display:flex;flex-direction:column;overflow-y:auto}.cv-context-header{display:flex;justify-content:space-between;align-items:center;padding:20px;border-bottom:1px solid #e2e8f0}.cv-context-header h3{margin:0;font-size:.875rem;font-weight:700;color:#1e293b}.cv-context-body{padding:20px;display:flex;flex-direction:column;gap:16px}@keyframes cv-appear{0%{opacity:0;transform:translateY(4px)}to{opacity:1;transform:translateY(0)}}@keyframes cv-slide-in{0%{transform:translate(100%)}to{transform:translate(0)}}@media(max-width:1100px){.cv-layout.has-context{grid-template-columns:280px 1fr 240px}}@media(max-width:768px){.cv-layout,.cv-layout.has-context{grid-template-columns:1fr;height:100%}.cv-hidden-mobile{display:none!important}.cv-back-btn{display:inline-flex}.cv-context-backdrop{display:block;position:fixed;inset:0;background:#00000059;z-index:99}.cv-context{position:fixed;top:0;right:0;bottom:0;width:300px;max-width:85vw;z-index:100;box-shadow:-4px 0 20px #0000001a}.cv-bubble{max-width:85%}.cv-messages,.cv-thread-header{padding:12px 16px}}@media(max-width:480px){.cv-thread-subtitle{display:none}.cv-compose{padding:8px 12px 12px;padding-bottom:calc(12px + env(safe-area-inset-bottom,0px))}.cv-list-header{padding:12px 16px 10px}.cv-context{width:100%;max-width:100vw}}\n"],
51393
+ dependencies: [
51394
+ {
51395
+ kind: "ngmodule",
51396
+ type: FormsModule
51397
+ },
51398
+ {
51399
+ kind: "directive",
51400
+ type: i1.NgControlStatus,
51401
+ selector: "[formControlName],[ngModel],[formControl]"
51402
+ },
51403
+ {
51404
+ kind: "directive",
51405
+ type: i1.MaxLengthValidator,
51406
+ selector: "[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]",
51407
+ inputs: ["maxlength"]
51408
+ },
51409
+ {
51410
+ kind: "directive",
51411
+ type: i1.NgModel,
51412
+ selector: "[ngModel]:not([formControlName]):not([formControl])",
51413
+ inputs: [
51414
+ "name",
51415
+ "disabled",
51416
+ "ngModel",
51417
+ "ngModelOptions"
51418
+ ],
51419
+ outputs: ["ngModelChange"],
51420
+ exportAs: ["ngModel"]
51421
+ },
51422
+ {
51423
+ kind: "component",
51424
+ type: AlertComponent,
51425
+ selector: "ui-alert",
51426
+ inputs: [
51427
+ "variant",
51428
+ "title",
51429
+ "dismissible",
51430
+ "dismissAriaLabel",
51431
+ "quiet",
51432
+ "compact",
51433
+ "inline",
51434
+ "fill"
51435
+ ],
51436
+ outputs: ["dismissed"]
51437
+ },
51438
+ {
51439
+ kind: "component",
51440
+ type: AvatarComponent,
51441
+ selector: "ui-avatar",
51442
+ inputs: [
51443
+ "initials",
51444
+ "name",
51445
+ "size",
51446
+ "imageUrl",
51447
+ "editable",
51448
+ "editLabel",
51449
+ "busy"
51450
+ ],
51451
+ outputs: ["editClick", "imageError"]
51452
+ },
51453
+ {
51454
+ kind: "component",
51455
+ type: BadgeComponent,
51456
+ selector: "ui-badge",
51457
+ inputs: ["label", "variant"]
51458
+ },
51459
+ {
51460
+ kind: "component",
51461
+ type: ButtonComponent,
51462
+ selector: "ui-button",
51463
+ inputs: [
51464
+ "variant",
51465
+ "routerLink",
51466
+ "queryParams",
51467
+ "fragment",
51468
+ "state",
51469
+ "href",
51470
+ "target",
51471
+ "rel",
51472
+ "shortLabel",
51473
+ "shortBelow",
51474
+ "color",
51475
+ "active",
51476
+ "size",
51477
+ "type",
51478
+ "disabled",
51479
+ "loading",
51480
+ "fullWidth",
51481
+ "ariaLabel",
51482
+ "ariaExpanded",
51483
+ "ariaPressed",
51484
+ "ariaDescribedBy",
51485
+ "modal-footer-left",
51486
+ "modal-footer-right"
51487
+ ]
51488
+ },
51489
+ {
51490
+ kind: "component",
51491
+ type: EmptyStateComponent,
51492
+ selector: "ui-empty-state",
51493
+ inputs: [
51494
+ "message",
51495
+ "title",
51496
+ "iconType"
51497
+ ]
51498
+ },
51499
+ {
51500
+ kind: "component",
51501
+ type: FileInputComponent,
51502
+ selector: "ui-file-input",
51503
+ inputs: [
51504
+ "label",
51505
+ "ariaLabel",
51506
+ "placeholder",
51507
+ "buttonLabel",
51508
+ "accept",
51509
+ "multiple",
51510
+ "required",
51511
+ "hint",
51512
+ "error",
51513
+ "showField",
51514
+ "showErrors",
51515
+ "toastOnReject",
51516
+ "clearable",
51517
+ "removeLabel",
51518
+ "maxSize",
51519
+ "enforceAccept",
51520
+ "typeMessage",
51521
+ "sizeMessage",
51522
+ "rejectEmpty",
51523
+ "emptyMessage",
51524
+ "minSize",
51525
+ "minSizeMessage",
51526
+ "dropzone",
51527
+ "showDetails",
51528
+ "preview",
51529
+ "loading",
51530
+ "loadingText",
51531
+ "disabled"
51532
+ ],
51533
+ outputs: [
51534
+ "filesSelected",
51535
+ "fileRejected",
51536
+ "fileRemoved",
51537
+ "invalidChange"
51538
+ ]
51539
+ },
51540
+ {
51541
+ kind: "component",
51542
+ type: ListComponent,
51543
+ selector: "ui-list",
51544
+ inputs: [
51545
+ "items",
51546
+ "ordered",
51547
+ "layout",
51548
+ "gridMin",
51549
+ "gap",
51550
+ "reorderable",
51551
+ "disabled",
51552
+ "moveControls",
51553
+ "dragDrop",
51554
+ "ariaLabel",
51555
+ "ariaLabelledby",
51556
+ "itemLabelFn",
51557
+ "trackBy",
51558
+ "moveEarlierLabel",
51559
+ "moveLaterLabel",
51560
+ "helpText",
51561
+ "moveAnnouncement",
51562
+ "navigable",
51563
+ "arrow"
51564
+ ],
51565
+ outputs: [
51566
+ "itemClick",
51567
+ "itemsChange",
51568
+ "reorder"
51569
+ ]
51570
+ },
51571
+ {
51572
+ kind: "component",
51573
+ type: PaginationComponent,
51574
+ selector: "ui-pagination",
51575
+ inputs: [
51576
+ "page",
51577
+ "pageSize",
51578
+ "totalItems",
51579
+ "detached",
51580
+ "embedded",
51581
+ "ariaLabel"
51582
+ ],
51583
+ outputs: ["pageChange"]
51584
+ },
51585
+ {
51586
+ kind: "component",
51587
+ type: QuickFilterTabsComponent,
51588
+ selector: "ui-quick-filter-tabs",
51589
+ inputs: [
51590
+ "tabs",
51591
+ "counts",
51592
+ "activeValue",
51593
+ "ariaLabel"
51594
+ ],
51595
+ outputs: ["tabChange"]
51596
+ },
51597
+ {
51598
+ kind: "component",
51599
+ type: SearchInputComponent,
51600
+ selector: "ui-search-input",
51601
+ inputs: [
51602
+ "placeholder",
51603
+ "ariaLabel",
51604
+ "value",
51605
+ "maxlength",
51606
+ "endpoint",
51607
+ "loading"
51608
+ ],
51609
+ outputs: [
51610
+ "valueChange",
51611
+ "searchChange",
51612
+ "filteredData"
51613
+ ]
51614
+ },
51615
+ {
51616
+ kind: "component",
51617
+ type: SkeletonComponent,
51618
+ selector: "ui-skeleton",
51619
+ inputs: [
51620
+ "height",
51621
+ "width",
51622
+ "radius",
51623
+ "mb",
51624
+ "ariaLabel"
51625
+ ]
51626
+ },
51627
+ {
51628
+ kind: "component",
51629
+ type: TextareaInputComponent,
51630
+ selector: "ui-textarea-input",
51631
+ inputs: [
51632
+ "label",
51633
+ "ariaLabel",
51634
+ "placeholder",
51635
+ "rows",
51636
+ "maxlength",
51637
+ "required",
51638
+ "readonly",
51639
+ "hint",
51640
+ "ariaDescribedBy",
51641
+ "hintAsDescription",
51642
+ "error",
51643
+ "monospace",
51644
+ "showErrors",
51645
+ "disabled"
51646
+ ],
51647
+ outputs: ["invalidChange"]
51648
+ },
51649
+ {
51650
+ kind: "directive",
51651
+ type: TooltipDirective,
51652
+ selector: "[uiTooltip]",
51653
+ inputs: ["uiTooltip", "tooltipPosition"]
51654
+ }
51655
+ ],
51656
+ changeDetection: i0.ChangeDetectionStrategy.OnPush
51657
+ });
51658
+ }
51659
+ };
51660
+ i0.ɵɵngDeclareClassMetadata({
51661
+ minVersion: "12.0.0",
51662
+ version: "22.2.2",
51663
+ ngImport: i0,
51664
+ type: ConversationsComponent,
51665
+ decorators: [{
51666
+ type: Component,
51667
+ args: [{
51668
+ selector: "ui-conversations",
51669
+ standalone: true,
51670
+ changeDetection: ChangeDetectionStrategy.OnPush,
51671
+ imports: [
51672
+ FormsModule,
51673
+ AlertComponent,
51674
+ AvatarComponent,
51675
+ BadgeComponent,
51676
+ ButtonComponent,
51677
+ EmptyStateComponent,
51678
+ FileInputComponent,
51679
+ ListComponent,
51680
+ PaginationComponent,
51681
+ QuickFilterTabsComponent,
51682
+ SearchInputComponent,
51683
+ SkeletonComponent,
51684
+ TextareaInputComponent,
51685
+ TooltipDirective
51686
+ ],
51687
+ template: `
51688
+ <div class="cv-layout" [class.has-context]="contextVisible()" data-testid="conversations">
51689
+ @if (contextVisible()) {
51690
+ <div class="cv-context-backdrop" (click)="closeContext()" aria-hidden="true"></div>
51691
+ }
51692
+
51693
+ <!-- LEFT: conversation list -->
51694
+ <section class="cv-list-panel" [class.cv-hidden-mobile]="!!selected()" [attr.aria-labelledby]="titleId">
51695
+ <div class="cv-list-header">
51696
+ <h2 class="cv-list-title" [id]="titleId">{{ title() }}</h2>
51697
+ @if (canWrite() && allowNew()) {
51698
+ <ui-button class="cv-new-btn" variant="primary" size="sm" [ariaLabel]="newLabel()" [uiTooltip]="newTooltip()" tooltipPosition="bottom" (click)="newConversation.emit()" data-testid="new-message-btn">
51699
+ <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/><line x1="12" y1="8" x2="12" y2="16"/><line x1="8" y1="12" x2="16" y2="12"/></svg>
51700
+ </ui-button>
51701
+ }
51702
+ </div>
51703
+
51704
+ @if (showFilters()) {
51705
+ <div class="cv-search">
51706
+ <ui-search-input [placeholder]="searchPlaceholder()" [ariaLabel]="searchAriaLabel()" [(value)]="searchText" (searchChange)="searchChange.emit($event)" data-testid="conv-search" />
51707
+ </div>
51708
+ @if (filterTabs().length) {
51709
+ <div class="cv-filters">
51710
+ <ui-quick-filter-tabs [ariaLabel]="filterAriaLabel()" [tabs]="filterTabs()" [counts]="filterCounts()" [activeValue]="activeFilter()" (tabChange)="filterChange.emit($event)" data-testid="conv-filters" />
51711
+ </div>
51712
+ }
51713
+ }
51714
+
51715
+ @if (loading()) {
51716
+ <div class="cv-loading" aria-busy="true" [attr.aria-label]="loadingLabel()" data-testid="conv-loading">
51717
+ @for (i of skeletonRows; track i) {
51718
+ <div class="cv-skeleton">
51719
+ <ui-skeleton [height]="40" width="40px" [radius]="20" />
51720
+ <div class="cv-skel-content">
51721
+ <div class="cv-skel-row">
51722
+ <ui-skeleton width="55%" [height]="12" />
51723
+ <ui-skeleton width="48px" [height]="10" />
51724
+ </div>
51725
+ <ui-skeleton width="30%" [height]="10" [mb]="2" />
51726
+ <ui-skeleton width="85%" [height]="10" />
51727
+ </div>
51728
+ </div>
51729
+ }
51730
+ </div>
51731
+ } @else if (error()) {
51732
+ <div class="cv-error" data-testid="conv-error">
51733
+ <ui-alert variant="danger">{{ error() }}</ui-alert>
51734
+ <ui-button variant="secondary" size="sm" (click)="retry.emit()" data-testid="conv-retry">Retry</ui-button>
51735
+ </div>
51736
+ } @else if (conversations().length === 0) {
51737
+ <ui-empty-state iconType="message" data-testid="conv-empty" [title]="filtering() ? filteredEmptyTitle() : emptyTitle()" [message]="emptyText()" />
51738
+ } @else {
51739
+ <div class="cv-list">
51740
+ <ui-list [ariaLabel]="listAriaLabel()" [items]="conversations()" [trackBy]="trackConversation" [navigable]="true" [arrow]="false" (itemClick)="onRowOpen($event)">
51741
+ <ng-template let-conv>
51742
+ <div class="cv-item" data-testid="conv-item" [attr.data-conversation-id]="conv.id"
51743
+ [class.selected]="selected()?.id === conv.id" [class.unread]="(conv.unreadCount ?? 0) > 0">
51744
+ <ui-avatar [initials]="initial(conv.name)" [name]="conv.name" [size]="40" />
51745
+ <div class="cv-item-info">
51746
+ <div class="cv-item-top">
51747
+ <span class="cv-name">{{ conv.name }}</span>@if (selected()?.id === conv.id) {<span class="cv-sr-only">, open</span>}
51748
+ <span class="cv-time">{{ relativeTime(conv.lastMessageAt) }}</span>
51749
+ </div>
51750
+ @if (conv.subtitle) { <span class="cv-subtitle">{{ conv.subtitle }}</span> }
51751
+ <div class="cv-item-bottom">
51752
+ <p class="cv-preview">{{ preview(conv.preview) || noMessagesText() }}</p>
51753
+ <div class="cv-item-right">
51754
+ @if (conv.statusLabel) { <ui-badge [label]="conv.statusLabel" variant="gray" /> }
51755
+ @if ((conv.unreadCount ?? 0) > 0) {
51756
+ <ui-badge class="cv-unread-badge" [label]="'' + conv.unreadCount" variant="blue" data-testid="conv-unread" />
51757
+ <span class="cv-sr-only">unread</span>
51758
+ }
51759
+ @if (canWrite() && allowDelete()) {
51760
+ <ui-button class="cv-delete-btn" variant="icon-danger" [ariaLabel]="deleteRowLabel() + ' ' + conv.name" (click)="$event.stopPropagation(); deleteConversation.emit(conv)" data-testid="conv-delete-btn">
51761
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M3 6h18"/><path d="M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6"/><path d="M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2"/></svg>
51762
+ </ui-button>
51763
+ }
51764
+ </div>
51765
+ </div>
51766
+ </div>
51767
+ @if (showRowArrow()) {
51768
+ <svg class="cv-row-arrow" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false" data-testid="conv-arrow"><path d="M9 18l6-6-6-6"/></svg>
51769
+ }
51770
+ </div>
51771
+ </ng-template>
51772
+ </ui-list>
51773
+ <ui-pagination [ariaLabel]="paginationAriaLabel()" [page]="page()" [pageSize]="pageSize()" [totalItems]="totalItems()" (pageChange)="pageChange.emit($event)" />
51774
+ </div>
51775
+ }
51776
+ </section>
51777
+
51778
+ <!-- CENTER: message thread -->
51779
+ <section class="cv-thread-panel" [class.cv-hidden-mobile]="!selected()" [attr.aria-label]="threadAriaLabel()">
51780
+ @if (selected(); as conv) {
51781
+ <div class="cv-thread-header">
51782
+ <ui-button class="cv-back-btn" variant="secondary" size="sm" [ariaLabel]="backLabel()" (click)="onBack()" data-testid="back-to-list">
51783
+ <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><polyline points="15 18 9 12 15 6"/></svg>
51784
+ </ui-button>
51785
+ <div class="cv-thread-header-info">
51786
+ <ui-avatar [initials]="initial(conv.name)" [name]="conv.name" [size]="40" />
51787
+ <div class="cv-thread-header-text">
51788
+ <h3 class="cv-thread-name" #threadHeading tabindex="-1" data-testid="thread-name">{{ conv.name }}</h3>
51789
+ @if (conv.subtitle) { <span class="cv-thread-subtitle" data-testid="thread-phone">{{ conv.subtitle }}</span> }
51790
+ </div>
51791
+ </div>
51792
+ <div class="cv-thread-actions">
51793
+ @if (canWrite() && templatesEnabled()) {
51794
+ <ui-button class="cv-thread-action" variant="secondary" size="sm" [ariaLabel]="templateLabel()" [uiTooltip]="templateLabel()" tooltipPosition="bottom" [disabled]="composerDisabled()" (click)="templateRequest.emit()" data-testid="use-template-btn">
51795
+ <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/></svg>
51796
+ </ui-button>
51797
+ }
51798
+ @if (hasContext()) {
51799
+ <ui-button #contextToggle class="cv-thread-action" [variant]="contextOpen() ? 'primary' : 'secondary'" size="sm" [ariaLabel]="contextOpen() ? hideContextLabel() : showContextLabel()" [uiTooltip]="contextOpen() ? hideContextLabel() : contextTitle()" tooltipPosition="bottom" (click)="toggleContext()" data-testid="context-toggle">
51800
+ <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"/><circle cx="12" cy="7" r="4"/></svg>
51801
+ </ui-button>
51802
+ }
51803
+ @if (canWrite() && statusActionLabel()) {
51804
+ <ui-button class="cv-thread-action" variant="secondary" size="sm" [ariaLabel]="statusActionLabel() ?? ''" [uiTooltip]="statusActionLabel()" tooltipPosition="bottom" [disabled]="statusChanging()" (click)="statusChange.emit(conv)" data-testid="status-btn">
51805
+ @if (statusActionIcon() === 'reopen') {
51806
+ <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><polyline points="1 4 1 10 7 10"/><path d="M3.51 15a9 9 0 1 0 2.13-9.36L1 10"/></svg>
51807
+ } @else {
51808
+ <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/><polyline points="22 4 12 14.01 9 11.01"/></svg>
51809
+ }
51810
+ </ui-button>
51811
+ }
51812
+ @if (canWrite() && allowDelete()) {
51813
+ <ui-button class="cv-thread-action" variant="danger" size="sm" [ariaLabel]="deleteThreadLabel()" [uiTooltip]="deleteThreadLabel()" tooltipPosition="bottom" (click)="deleteConversation.emit(conv)" data-testid="thread-delete-btn">
51814
+ <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M3 6h18"/><path d="M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6"/><path d="M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2"/></svg>
51815
+ </ui-button>
51816
+ }
51817
+ </div>
51818
+ </div>
51819
+
51820
+ <div class="cv-messages" #messagesEl role="log" aria-live="polite" aria-relevant="additions" tabindex="0"
51821
+ [attr.aria-label]="messagesAriaLabel() + ' ' + conv.name" [attr.aria-busy]="messagesLoading()" (scroll)="onMessagesScroll()" data-testid="messages">
51822
+ @if (messagesLoading()) {
51823
+ <div class="cv-messages-loading" data-testid="messages-loading">
51824
+ @for (i of skeletonBubbles; track i) {
51825
+ <div class="cv-msg-skeleton" [class.outbound]="i % 2 === 0">
51826
+ <ui-skeleton [height]="48" [width]="i % 2 === 0 ? '60%' : '55%'" [radius]="16" />
51827
+ </div>
51828
+ }
51829
+ </div>
51830
+ } @else if (messagesError()) {
51831
+ <div class="cv-messages-error" data-testid="thread-error">
51832
+ <ui-alert variant="danger">{{ messagesError() }}</ui-alert>
51833
+ <ui-button variant="secondary" size="sm" (click)="messagesRetry.emit()" data-testid="thread-retry">Retry</ui-button>
51834
+ </div>
51835
+ } @else if (messages().length === 0) {
51836
+ <div class="cv-messages-empty" data-testid="messages-empty">
51837
+ <p>{{ canWrite() ? noMessagesWriteText() : noMessagesReadText() }}</p>
51838
+ </div>
51839
+ } @else {
51840
+ @if (hasEarlier()) {
51841
+ <div class="cv-load-earlier">
51842
+ <ui-button variant="secondary" size="sm" [loading]="loadingEarlier()" (click)="loadEarlier.emit()" data-testid="load-earlier">{{ loadEarlierLabel() }}</ui-button>
51843
+ </div>
51844
+ }
51845
+ @for (row of messageRows(); track row.message.id) {
51846
+ @if (row.separator) { <div class="cv-date-separator"><span>{{ row.separator }}</span></div> }
51847
+ <div class="cv-bubble" data-testid="message" [class.outbound]="row.message.direction === 'outbound'" [class.inbound]="row.message.direction === 'inbound'">
51848
+ <span class="cv-sr-only">{{ row.message.direction === 'outbound' ? youLabel() : conv.name }}:</span>
51849
+ @if (row.message.media; as media) {
51850
+ <div class="cv-media">
51851
+ @if (media.type?.startsWith('image/')) {
51852
+ <button type="button" class="cv-image-btn" (click)="mediaOpen.emit(media.url)" [attr.aria-label]="openMediaLabel() + ' ' + (media.fileName || imageFallbackName())">
51853
+ <img [src]="media.url" [alt]="media.fileName || imageFallbackName()" class="cv-image" loading="lazy" />
51854
+ </button>
51855
+ } @else if (media.type?.startsWith('video/')) {
51856
+ <video [src]="media.url" class="cv-video" controls preload="metadata"></video>
51857
+ } @else {
51858
+ <a [href]="media.url" target="_blank" rel="noopener noreferrer" class="cv-file-link">{{ media.fileName || fileFallbackName() }}</a>
51859
+ }
51860
+ </div>
51861
+ }
51862
+ @if (row.message.body) { <p class="cv-body">{{ row.message.body }}</p> }
51863
+ <span class="cv-meta">
51864
+ @if (row.message.direction === 'outbound' && row.message.sender) { <span class="cv-sender" data-testid="msg-sender">{{ row.message.sender }}</span> }
51865
+ {{ time(row.message) }}
51866
+ @if (row.message.action; as action) {
51867
+ <button type="button" class="cv-msg-action" data-testid="msg-action" (click)="messageAction.emit(row.message)">{{ action.label }}</button>
51868
+ }
51869
+ @if (row.message.direction === 'outbound' && statusLabel(row.message.status)) {
51870
+ <span class="cv-status" [class.failed]="row.message.status === 'failed'" data-testid="msg-status">
51871
+ <span aria-hidden="true">{{ statusMark(row.message.status) }}</span>
51872
+ <span class="cv-sr-only">{{ statusLabel(row.message.status) }}</span>
51873
+ </span>
51874
+ }
51875
+ </span>
51876
+ </div>
51877
+ }
51878
+ }
51879
+ </div>
51880
+
51881
+ @if (canWrite()) {
51882
+ <div class="cv-compose">
51883
+ @if (attachment(); as file) {
51884
+ <div class="cv-attachment" data-testid="attachment-preview">
51885
+ @if (file.previewUrl) {
51886
+ <img [src]="file.previewUrl" [alt]="attachmentPreviewLabel()" class="cv-attachment-thumb" />
51887
+ } @else {
51888
+ <span class="cv-attachment-name">{{ file.fileName }}</span>
51889
+ }
51890
+ <ui-button class="cv-attachment-remove" variant="icon-danger" [ariaLabel]="removeAttachmentLabel()" (click)="attachmentRemove.emit()" data-testid="attachment-remove">
51891
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>
51892
+ </ui-button>
51893
+ </div>
51894
+ }
51895
+ <div class="cv-compose-row">
51896
+ @if (attachEnabled()) {
51897
+ <ui-button class="cv-attach-btn" variant="icon" [ariaLabel]="attachLabel()" [disabled]="uploading() || composerDisabled()" [loading]="uploading()" (click)="openFilePicker()" data-testid="attach-btn">
51898
+ <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M21.44 11.05l-9.19 9.19a6 6 0 0 1-8.49-8.49l9.19-9.19a4 4 0 0 1 5.66 5.66l-9.2 9.19a2 2 0 0 1-2.83-2.83l8.49-8.48"/></svg>
51899
+ </ui-button>
51900
+ <ui-file-input [showField]="false" [accept]="acceptedFiles()" [maxSize]="maxFileSize()" [toastOnReject]="true"
51901
+ [typeMessage]="typeMessage()" [sizeMessage]="sizeMessage()" (filesSelected)="filesSelected.emit($event)" data-testid="attach-input" />
51902
+ }
51903
+ <ui-textarea-input class="cv-compose-input" [ariaLabel]="composeLabel()" [placeholder]="composePlaceholder()" [rows]="1" [maxlength]="maxLength()"
51904
+ [ngModel]="draft()" (ngModelChange)="draft.set($event)" [disabled]="composerDisabled()" [error]="composerError()"
51905
+ (keydown)="onComposeKeydown($event)" data-testid="compose-input" />
51906
+ <ui-button class="cv-send-btn" variant="primary" [ariaLabel]="sendLabel()" [disabled]="!canSend()" [loading]="sending()" (click)="sendMessage()" data-testid="send-btn">
51907
+ <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><line x1="22" y1="2" x2="11" y2="13"/><polygon points="22 2 15 22 11 13 2 9 22 2"/></svg>
51908
+ </ui-button>
51909
+ </div>
51910
+ @if (composerNotice()) {
51911
+ <ui-alert variant="warning" data-testid="compose-opted-out">{{ composerNotice() }}</ui-alert>
51912
+ }
51913
+ <!-- Always in the page (a live region that appears together with its text is often not announced): only its text comes and goes. -->
51914
+ <p class="cv-compose-status" role="status" data-testid="compose-loading-contact">{{ composerStatus() }}</p>
51915
+ </div>
51916
+ }
51917
+ } @else {
51918
+ <ui-empty-state iconType="message" [title]="threadEmptyTitle()" [message]="threadEmptyMessage()" data-testid="thread-empty" />
51919
+ }
51920
+ </section>
51921
+
51922
+ <!-- RIGHT: contact panel (the host's content) -->
51923
+ @if (contextVisible()) {
51924
+ <aside class="cv-context" #contextPanel tabindex="-1" [attr.aria-label]="contextTitle()" (keydown.escape)="closeContext(true)" data-testid="context-panel">
51925
+ <div class="cv-context-header">
51926
+ <h3>{{ contextTitle() }}</h3>
51927
+ <ui-button variant="icon" [ariaLabel]="closeContextLabel()" (click)="closeContext(true)" data-testid="context-close">
51928
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>
51929
+ </ui-button>
51930
+ </div>
51931
+ <div class="cv-context-body"><ng-content select="[uiConversationsContext]" /></div>
51932
+ </aside>
51933
+ }
51934
+ </div>
51935
+ `,
51936
+ styles: [":host{display:flex;flex:1;min-height:0;min-width:0}.cv-sr-only{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}.cv-layout{display:grid;grid-template-columns:340px 1fr;flex:1;min-height:0;min-width:0;background:#fff;border-radius:12px;overflow:hidden;box-shadow:0 1px 3px #0000000f;border:1px solid #e2e8f0}.cv-layout.has-context{grid-template-columns:340px 1fr 280px}.cv-list-panel{display:flex;flex-direction:column;min-height:0;border-right:1px solid #e2e8f0;background:#f8fafc;overflow:hidden}.cv-list-header{display:flex;align-items:center;justify-content:space-between;padding:20px 20px 12px}.cv-list-title{margin:0;font-size:1.125rem;font-weight:700;color:#1e293b}.cv-search,.cv-filters{padding:0 16px 12px}.cv-list{flex:1;min-height:0;overflow-y:auto;overscroll-behavior:contain}.cv-item{display:flex;gap:12px;padding:14px 16px;border-bottom:1px solid #f1f5f9;transition:background .15s}.cv-item.unread{background:#fffbeb}.cv-item.selected{background:#eff6ff;box-shadow:inset 3px 0 #2563eb}.cv-item-info{flex:1;min-width:0}.cv-row-arrow{flex:0 0 auto;align-self:center;color:#94a3b8}.cv-item-top{display:flex;justify-content:space-between;align-items:center;margin-bottom:4px}.cv-name{font-size:.875rem;font-weight:600;color:#1e293b;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.cv-time{font-size:.6875rem;color:#64748b;flex-shrink:0;margin-left:8px}.cv-subtitle{font-size:.6875rem;color:#64748b;display:block;margin-bottom:2px}.cv-item-bottom{display:flex;justify-content:space-between;align-items:center;gap:8px}.cv-preview{margin:0;font-size:.8125rem;color:#64748b;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;flex:1;min-width:0}.cv-item-right{display:flex;align-items:center;gap:6px;flex-shrink:0}.cv-delete-btn{opacity:0;transition:opacity .15s}.cv-item:hover .cv-delete-btn,.cv-item:focus-within .cv-delete-btn,.cv-delete-btn:focus-within{opacity:1}@media(hover:none){.cv-delete-btn{opacity:1}}.cv-loading{padding:8px 0}.cv-skeleton{display:flex;gap:12px;align-items:flex-start;padding:14px 16px;border-bottom:1px solid #f1f5f9}.cv-skel-content{flex:1;min-width:0;display:flex;flex-direction:column;gap:6px;padding-top:2px}.cv-skel-row{display:flex;justify-content:space-between;gap:8px}.cv-error{display:flex;flex-direction:column;align-items:center;gap:12px;padding:24px 16px;text-align:center}.cv-thread-panel{display:flex;flex-direction:column;min-width:0;min-height:0;overflow:hidden;background:#fff}.cv-thread-header{display:flex;align-items:center;gap:12px;padding:16px 20px;border-bottom:1px solid #e2e8f0;background:#fff}.cv-back-btn{display:none}.cv-thread-header-info{display:flex;align-items:center;gap:12px;flex:1;min-width:0}.cv-thread-header-text{min-width:0;display:flex;flex-direction:column}.cv-thread-name{margin:0;font-size:.9375rem;font-weight:600;color:#1e293b;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.cv-thread-name:focus{outline:none}.cv-thread-name:focus-visible{outline:2px solid #2563eb;outline-offset:2px;border-radius:4px}.cv-thread-subtitle{font-size:.75rem;color:#64748b}.cv-thread-actions{display:flex;align-items:center;gap:8px}.cv-messages{flex:1;min-height:0;overflow-y:auto;overflow-x:hidden;overscroll-behavior:contain;padding:20px 24px;display:flex;flex-direction:column;gap:4px;background:#f8fafc}.cv-messages:focus-visible{outline:2px solid #2563eb;outline-offset:-2px}.cv-messages-loading{display:flex;flex-direction:column;gap:12px;padding:20px 0}.cv-msg-skeleton{display:flex}.cv-msg-skeleton.outbound{justify-content:flex-end}.cv-messages-error{display:flex;flex-direction:column;align-items:center;gap:12px;padding:24px 16px;text-align:center}.cv-load-earlier{display:flex;justify-content:center;padding:4px 0 12px}.cv-sender{font-weight:600}.cv-msg-action{padding:0;border:0;background:none;color:inherit;font:inherit;text-decoration:underline;cursor:pointer}.cv-msg-action:focus-visible{outline:2px solid currentColor;outline-offset:2px;border-radius:2px}.cv-messages-empty{display:flex;align-items:center;justify-content:center;flex:1}.cv-messages-empty p{margin:0;font-size:.875rem;color:#64748b;text-align:center}.cv-date-separator{display:flex;align-items:center;justify-content:center;padding:16px 0 8px}.cv-date-separator span{padding:4px 14px;border-radius:12px;background:#e2e8f0;font-size:.6875rem;font-weight:600;color:#475569;text-transform:uppercase;letter-spacing:.3px}.cv-bubble{max-width:70%;padding:10px 14px;border-radius:16px;position:relative;word-break:break-word;overflow-wrap:break-word}.cv-bubble.inbound{align-self:flex-start;background:#fff;border:1px solid #e2e8f0;border-bottom-left-radius:4px}.cv-bubble.inbound .cv-body{color:#1e293b}.cv-bubble.inbound .cv-meta{color:#64748b}.cv-bubble.outbound{align-self:flex-end;background:#2563eb;border-bottom-right-radius:4px}.cv-bubble.outbound .cv-body,.cv-bubble.outbound .cv-meta{color:#fff}@media(prefers-reduced-motion:no-preference){.cv-bubble{animation:cv-appear .2s ease}.cv-context{animation:cv-slide-in .25s ease}}.cv-body{margin:0;font-size:.875rem;line-height:1.45;word-break:break-word;white-space:pre-wrap}.cv-media{margin-bottom:6px}.cv-image-btn{display:block;padding:0;border:0;background:none;cursor:pointer;border-radius:8px}.cv-image-btn:focus-visible{outline:2px solid #fff;outline-offset:2px;box-shadow:0 0 0 4px #2563eb}.cv-image{display:block;max-width:240px;max-height:240px;border-radius:8px;object-fit:cover}.cv-video{max-width:240px;max-height:200px;border-radius:8px}.cv-file-link{font-size:.8125rem;color:#fff;text-decoration:underline}.cv-bubble.inbound .cv-file-link{color:#2563eb}.cv-meta{display:flex;align-items:center;gap:6px;justify-content:flex-end;font-size:.6875rem;margin-top:4px}.cv-status{font-weight:500}.cv-status.failed{color:#fff;font-weight:700}.cv-bubble.inbound .cv-status.failed{color:#dc2626}.cv-compose{display:flex;flex-direction:column;padding:12px 20px 16px;padding-bottom:calc(16px + env(safe-area-inset-bottom,0px));border-top:1px solid #e2e8f0;background:#fff}.cv-compose-row{display:flex;align-items:flex-end;gap:10px}.cv-compose-input{flex:1;min-width:0}.cv-attach-btn,.cv-send-btn{flex-shrink:0}.cv-attachment{display:flex;align-items:center;gap:8px;padding:8px 12px;margin-bottom:8px;background:#f8fafc;border:1px solid #e2e8f0;border-radius:8px}.cv-attachment-thumb{width:48px;height:48px;object-fit:cover;border-radius:6px}.cv-attachment-name{font-size:.8125rem;color:#475569;flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.cv-attachment-remove{flex-shrink:0}.cv-compose-status{margin:4px 0 0;font-size:.8125rem;color:#64748b}.cv-compose-status:empty{margin:0}.cv-context-backdrop{display:none}.cv-context{width:100%;min-width:0;border-left:1px solid #e2e8f0;background:#fff;display:flex;flex-direction:column;overflow-y:auto}.cv-context-header{display:flex;justify-content:space-between;align-items:center;padding:20px;border-bottom:1px solid #e2e8f0}.cv-context-header h3{margin:0;font-size:.875rem;font-weight:700;color:#1e293b}.cv-context-body{padding:20px;display:flex;flex-direction:column;gap:16px}@keyframes cv-appear{0%{opacity:0;transform:translateY(4px)}to{opacity:1;transform:translateY(0)}}@keyframes cv-slide-in{0%{transform:translate(100%)}to{transform:translate(0)}}@media(max-width:1100px){.cv-layout.has-context{grid-template-columns:280px 1fr 240px}}@media(max-width:768px){.cv-layout,.cv-layout.has-context{grid-template-columns:1fr;height:100%}.cv-hidden-mobile{display:none!important}.cv-back-btn{display:inline-flex}.cv-context-backdrop{display:block;position:fixed;inset:0;background:#00000059;z-index:99}.cv-context{position:fixed;top:0;right:0;bottom:0;width:300px;max-width:85vw;z-index:100;box-shadow:-4px 0 20px #0000001a}.cv-bubble{max-width:85%}.cv-messages,.cv-thread-header{padding:12px 16px}}@media(max-width:480px){.cv-thread-subtitle{display:none}.cv-compose{padding:8px 12px 12px;padding-bottom:calc(12px + env(safe-area-inset-bottom,0px))}.cv-list-header{padding:12px 16px 10px}.cv-context{width:100%;max-width:100vw}}\n"]
51937
+ }]
51938
+ }],
51939
+ ctorParameters: () => [],
51940
+ propDecorators: {
51941
+ conversations: [{
51942
+ type: i0.Input,
51943
+ args: [{
51944
+ isSignal: true,
51945
+ alias: "conversations",
51946
+ required: false
51947
+ }]
51948
+ }],
51949
+ selected: [{
51950
+ type: i0.Input,
51951
+ args: [{
51952
+ isSignal: true,
51953
+ alias: "selected",
51954
+ required: false
51955
+ }]
51956
+ }],
51957
+ title: [{
51958
+ type: i0.Input,
51959
+ args: [{
51960
+ isSignal: true,
51961
+ alias: "title",
51962
+ required: false
51963
+ }]
51964
+ }],
51965
+ loading: [{
51966
+ type: i0.Input,
51967
+ args: [{
51968
+ isSignal: true,
51969
+ alias: "loading",
51970
+ required: false
51971
+ }]
51972
+ }],
51973
+ error: [{
51974
+ type: i0.Input,
51975
+ args: [{
51976
+ isSignal: true,
51977
+ alias: "error",
51978
+ required: false
51979
+ }]
51980
+ }],
51981
+ searchText: [{
51982
+ type: i0.Input,
51983
+ args: [{
51984
+ isSignal: true,
51985
+ alias: "searchText",
51986
+ required: false
51987
+ }]
51988
+ }, {
51989
+ type: i0.Output,
51990
+ args: ["searchTextChange"]
51991
+ }],
51992
+ searchPlaceholder: [{
51993
+ type: i0.Input,
51994
+ args: [{
51995
+ isSignal: true,
51996
+ alias: "searchPlaceholder",
51997
+ required: false
51998
+ }]
51999
+ }],
52000
+ searchAriaLabel: [{
52001
+ type: i0.Input,
52002
+ args: [{
52003
+ isSignal: true,
52004
+ alias: "searchAriaLabel",
52005
+ required: false
52006
+ }]
52007
+ }],
52008
+ showFilters: [{
52009
+ type: i0.Input,
52010
+ args: [{
52011
+ isSignal: true,
52012
+ alias: "showFilters",
52013
+ required: false
52014
+ }]
52015
+ }],
52016
+ filterTabs: [{
52017
+ type: i0.Input,
52018
+ args: [{
52019
+ isSignal: true,
52020
+ alias: "filterTabs",
52021
+ required: false
52022
+ }]
52023
+ }],
52024
+ filterCounts: [{
52025
+ type: i0.Input,
52026
+ args: [{
52027
+ isSignal: true,
52028
+ alias: "filterCounts",
52029
+ required: false
52030
+ }]
52031
+ }],
52032
+ activeFilter: [{
52033
+ type: i0.Input,
52034
+ args: [{
52035
+ isSignal: true,
52036
+ alias: "activeFilter",
52037
+ required: false
52038
+ }]
52039
+ }],
52040
+ filterAriaLabel: [{
52041
+ type: i0.Input,
52042
+ args: [{
52043
+ isSignal: true,
52044
+ alias: "filterAriaLabel",
52045
+ required: false
52046
+ }]
52047
+ }],
52048
+ page: [{
52049
+ type: i0.Input,
52050
+ args: [{
52051
+ isSignal: true,
52052
+ alias: "page",
52053
+ required: false
52054
+ }]
52055
+ }],
52056
+ pageSize: [{
52057
+ type: i0.Input,
52058
+ args: [{
52059
+ isSignal: true,
52060
+ alias: "pageSize",
52061
+ required: false
52062
+ }]
52063
+ }],
52064
+ totalItems: [{
52065
+ type: i0.Input,
52066
+ args: [{
52067
+ isSignal: true,
52068
+ alias: "totalItems",
52069
+ required: false
52070
+ }]
52071
+ }],
52072
+ paginationAriaLabel: [{
52073
+ type: i0.Input,
52074
+ args: [{
52075
+ isSignal: true,
52076
+ alias: "paginationAriaLabel",
52077
+ required: false
52078
+ }]
52079
+ }],
52080
+ listAriaLabel: [{
52081
+ type: i0.Input,
52082
+ args: [{
52083
+ isSignal: true,
52084
+ alias: "listAriaLabel",
52085
+ required: false
52086
+ }]
52087
+ }],
52088
+ loadingLabel: [{
52089
+ type: i0.Input,
52090
+ args: [{
52091
+ isSignal: true,
52092
+ alias: "loadingLabel",
52093
+ required: false
52094
+ }]
52095
+ }],
52096
+ emptyTitle: [{
52097
+ type: i0.Input,
52098
+ args: [{
52099
+ isSignal: true,
52100
+ alias: "emptyTitle",
52101
+ required: false
52102
+ }]
52103
+ }],
52104
+ emptyMessage: [{
52105
+ type: i0.Input,
52106
+ args: [{
52107
+ isSignal: true,
52108
+ alias: "emptyMessage",
52109
+ required: false
52110
+ }]
52111
+ }],
52112
+ emptyReadOnlyMessage: [{
52113
+ type: i0.Input,
52114
+ args: [{
52115
+ isSignal: true,
52116
+ alias: "emptyReadOnlyMessage",
52117
+ required: false
52118
+ }]
52119
+ }],
52120
+ filteredEmptyTitle: [{
52121
+ type: i0.Input,
52122
+ args: [{
52123
+ isSignal: true,
52124
+ alias: "filteredEmptyTitle",
52125
+ required: false
52126
+ }]
52127
+ }],
52128
+ filteredEmptyMessage: [{
52129
+ type: i0.Input,
52130
+ args: [{
52131
+ isSignal: true,
52132
+ alias: "filteredEmptyMessage",
52133
+ required: false
52134
+ }]
52135
+ }],
52136
+ noMessagesText: [{
52137
+ type: i0.Input,
52138
+ args: [{
52139
+ isSignal: true,
52140
+ alias: "noMessagesText",
52141
+ required: false
52142
+ }]
52143
+ }],
52144
+ allowNew: [{
52145
+ type: i0.Input,
52146
+ args: [{
52147
+ isSignal: true,
52148
+ alias: "allowNew",
52149
+ required: false
52150
+ }]
52151
+ }],
52152
+ allowDelete: [{
52153
+ type: i0.Input,
52154
+ args: [{
52155
+ isSignal: true,
52156
+ alias: "allowDelete",
52157
+ required: false
52158
+ }]
52159
+ }],
52160
+ showRowArrow: [{
52161
+ type: i0.Input,
52162
+ args: [{
52163
+ isSignal: true,
52164
+ alias: "showRowArrow",
52165
+ required: false
52166
+ }]
52167
+ }],
52168
+ newLabel: [{
52169
+ type: i0.Input,
52170
+ args: [{
52171
+ isSignal: true,
52172
+ alias: "newLabel",
52173
+ required: false
52174
+ }]
52175
+ }],
52176
+ newTooltip: [{
52177
+ type: i0.Input,
52178
+ args: [{
52179
+ isSignal: true,
52180
+ alias: "newTooltip",
52181
+ required: false
52182
+ }]
52183
+ }],
52184
+ deleteRowLabel: [{
52185
+ type: i0.Input,
52186
+ args: [{
52187
+ isSignal: true,
52188
+ alias: "deleteRowLabel",
52189
+ required: false
52190
+ }]
52191
+ }],
52192
+ messages: [{
52193
+ type: i0.Input,
52194
+ args: [{
52195
+ isSignal: true,
52196
+ alias: "messages",
52197
+ required: false
52198
+ }]
52199
+ }],
52200
+ messagesLoading: [{
52201
+ type: i0.Input,
52202
+ args: [{
52203
+ isSignal: true,
52204
+ alias: "messagesLoading",
52205
+ required: false
52206
+ }]
52207
+ }],
52208
+ messagesError: [{
52209
+ type: i0.Input,
52210
+ args: [{
52211
+ isSignal: true,
52212
+ alias: "messagesError",
52213
+ required: false
52214
+ }]
52215
+ }],
52216
+ hasEarlier: [{
52217
+ type: i0.Input,
52218
+ args: [{
52219
+ isSignal: true,
52220
+ alias: "hasEarlier",
52221
+ required: false
52222
+ }]
52223
+ }],
52224
+ loadingEarlier: [{
52225
+ type: i0.Input,
52226
+ args: [{
52227
+ isSignal: true,
52228
+ alias: "loadingEarlier",
52229
+ required: false
52230
+ }]
52231
+ }],
52232
+ loadEarlierLabel: [{
52233
+ type: i0.Input,
52234
+ args: [{
52235
+ isSignal: true,
52236
+ alias: "loadEarlierLabel",
52237
+ required: false
52238
+ }]
52239
+ }],
52240
+ statusActionLabel: [{
52241
+ type: i0.Input,
52242
+ args: [{
52243
+ isSignal: true,
52244
+ alias: "statusActionLabel",
52245
+ required: false
52246
+ }]
52247
+ }],
52248
+ statusActionIcon: [{
52249
+ type: i0.Input,
52250
+ args: [{
52251
+ isSignal: true,
52252
+ alias: "statusActionIcon",
52253
+ required: false
52254
+ }]
52255
+ }],
52256
+ statusChanging: [{
52257
+ type: i0.Input,
52258
+ args: [{
52259
+ isSignal: true,
52260
+ alias: "statusChanging",
52261
+ required: false
52262
+ }]
52263
+ }],
52264
+ templatesEnabled: [{
52265
+ type: i0.Input,
52266
+ args: [{
52267
+ isSignal: true,
52268
+ alias: "templatesEnabled",
52269
+ required: false
52270
+ }]
52271
+ }],
52272
+ templateLabel: [{
52273
+ type: i0.Input,
52274
+ args: [{
52275
+ isSignal: true,
52276
+ alias: "templateLabel",
52277
+ required: false
52278
+ }]
52279
+ }],
52280
+ deleteThreadLabel: [{
52281
+ type: i0.Input,
52282
+ args: [{
52283
+ isSignal: true,
52284
+ alias: "deleteThreadLabel",
52285
+ required: false
52286
+ }]
52287
+ }],
52288
+ backLabel: [{
52289
+ type: i0.Input,
52290
+ args: [{
52291
+ isSignal: true,
52292
+ alias: "backLabel",
52293
+ required: false
52294
+ }]
52295
+ }],
52296
+ threadAriaLabel: [{
52297
+ type: i0.Input,
52298
+ args: [{
52299
+ isSignal: true,
52300
+ alias: "threadAriaLabel",
52301
+ required: false
52302
+ }]
52303
+ }],
52304
+ messagesAriaLabel: [{
52305
+ type: i0.Input,
52306
+ args: [{
52307
+ isSignal: true,
52308
+ alias: "messagesAriaLabel",
52309
+ required: false
52310
+ }]
52311
+ }],
52312
+ threadEmptyTitle: [{
52313
+ type: i0.Input,
52314
+ args: [{
52315
+ isSignal: true,
52316
+ alias: "threadEmptyTitle",
52317
+ required: false
52318
+ }]
52319
+ }],
52320
+ threadEmptyMessage: [{
52321
+ type: i0.Input,
52322
+ args: [{
52323
+ isSignal: true,
52324
+ alias: "threadEmptyMessage",
52325
+ required: false
52326
+ }]
52327
+ }],
52328
+ noMessagesWriteText: [{
52329
+ type: i0.Input,
52330
+ args: [{
52331
+ isSignal: true,
52332
+ alias: "noMessagesWriteText",
52333
+ required: false
52334
+ }]
52335
+ }],
52336
+ noMessagesReadText: [{
52337
+ type: i0.Input,
52338
+ args: [{
52339
+ isSignal: true,
52340
+ alias: "noMessagesReadText",
52341
+ required: false
52342
+ }]
52343
+ }],
52344
+ youLabel: [{
52345
+ type: i0.Input,
52346
+ args: [{
52347
+ isSignal: true,
52348
+ alias: "youLabel",
52349
+ required: false
52350
+ }]
52351
+ }],
52352
+ openMediaLabel: [{
52353
+ type: i0.Input,
52354
+ args: [{
52355
+ isSignal: true,
52356
+ alias: "openMediaLabel",
52357
+ required: false
52358
+ }]
52359
+ }],
52360
+ imageFallbackName: [{
52361
+ type: i0.Input,
52362
+ args: [{
52363
+ isSignal: true,
52364
+ alias: "imageFallbackName",
52365
+ required: false
52366
+ }]
52367
+ }],
52368
+ fileFallbackName: [{
52369
+ type: i0.Input,
52370
+ args: [{
52371
+ isSignal: true,
52372
+ alias: "fileFallbackName",
52373
+ required: false
52374
+ }]
52375
+ }],
52376
+ hasContext: [{
52377
+ type: i0.Input,
52378
+ args: [{
52379
+ isSignal: true,
52380
+ alias: "hasContext",
52381
+ required: false
52382
+ }]
52383
+ }],
52384
+ contextOpen: [{
52385
+ type: i0.Input,
52386
+ args: [{
52387
+ isSignal: true,
52388
+ alias: "contextOpen",
52389
+ required: false
52390
+ }]
52391
+ }, {
52392
+ type: i0.Output,
52393
+ args: ["contextOpenChange"]
52394
+ }],
52395
+ contextTitle: [{
52396
+ type: i0.Input,
52397
+ args: [{
52398
+ isSignal: true,
52399
+ alias: "contextTitle",
52400
+ required: false
52401
+ }]
52402
+ }],
52403
+ showContextLabel: [{
52404
+ type: i0.Input,
52405
+ args: [{
52406
+ isSignal: true,
52407
+ alias: "showContextLabel",
52408
+ required: false
52409
+ }]
52410
+ }],
52411
+ hideContextLabel: [{
52412
+ type: i0.Input,
52413
+ args: [{
52414
+ isSignal: true,
52415
+ alias: "hideContextLabel",
52416
+ required: false
52417
+ }]
52418
+ }],
52419
+ closeContextLabel: [{
52420
+ type: i0.Input,
52421
+ args: [{
52422
+ isSignal: true,
52423
+ alias: "closeContextLabel",
52424
+ required: false
52425
+ }]
52426
+ }],
52427
+ canWrite: [{
52428
+ type: i0.Input,
52429
+ args: [{
52430
+ isSignal: true,
52431
+ alias: "canWrite",
52432
+ required: false
52433
+ }]
52434
+ }],
52435
+ draft: [{
52436
+ type: i0.Input,
52437
+ args: [{
52438
+ isSignal: true,
52439
+ alias: "draft",
52440
+ required: false
52441
+ }]
52442
+ }, {
52443
+ type: i0.Output,
52444
+ args: ["draftChange"]
52445
+ }],
52446
+ sending: [{
52447
+ type: i0.Input,
52448
+ args: [{
52449
+ isSignal: true,
52450
+ alias: "sending",
52451
+ required: false
52452
+ }]
52453
+ }],
52454
+ composerDisabled: [{
52455
+ type: i0.Input,
52456
+ args: [{
52457
+ isSignal: true,
52458
+ alias: "composerDisabled",
52459
+ required: false
52460
+ }]
52461
+ }],
52462
+ sendBlocked: [{
52463
+ type: i0.Input,
52464
+ args: [{
52465
+ isSignal: true,
52466
+ alias: "sendBlocked",
52467
+ required: false
52468
+ }]
52469
+ }],
52470
+ composerNotice: [{
52471
+ type: i0.Input,
52472
+ args: [{
52473
+ isSignal: true,
52474
+ alias: "composerNotice",
52475
+ required: false
52476
+ }]
52477
+ }],
52478
+ composerStatus: [{
52479
+ type: i0.Input,
52480
+ args: [{
52481
+ isSignal: true,
52482
+ alias: "composerStatus",
52483
+ required: false
52484
+ }]
52485
+ }],
52486
+ composerError: [{
52487
+ type: i0.Input,
52488
+ args: [{
52489
+ isSignal: true,
52490
+ alias: "composerError",
52491
+ required: false
52492
+ }]
52493
+ }],
52494
+ maxLength: [{
52495
+ type: i0.Input,
52496
+ args: [{
52497
+ isSignal: true,
52498
+ alias: "maxLength",
52499
+ required: false
52500
+ }]
52501
+ }],
52502
+ attachment: [{
52503
+ type: i0.Input,
52504
+ args: [{
52505
+ isSignal: true,
52506
+ alias: "attachment",
52507
+ required: false
52508
+ }]
52509
+ }],
52510
+ uploading: [{
52511
+ type: i0.Input,
52512
+ args: [{
52513
+ isSignal: true,
52514
+ alias: "uploading",
52515
+ required: false
52516
+ }]
52517
+ }],
52518
+ attachEnabled: [{
52519
+ type: i0.Input,
52520
+ args: [{
52521
+ isSignal: true,
52522
+ alias: "attachEnabled",
52523
+ required: false
52524
+ }]
52525
+ }],
52526
+ acceptedFiles: [{
52527
+ type: i0.Input,
52528
+ args: [{
52529
+ isSignal: true,
52530
+ alias: "acceptedFiles",
52531
+ required: false
52532
+ }]
52533
+ }],
52534
+ maxFileSize: [{
52535
+ type: i0.Input,
52536
+ args: [{
52537
+ isSignal: true,
52538
+ alias: "maxFileSize",
52539
+ required: false
52540
+ }]
52541
+ }],
52542
+ typeMessage: [{
52543
+ type: i0.Input,
52544
+ args: [{
52545
+ isSignal: true,
52546
+ alias: "typeMessage",
52547
+ required: false
52548
+ }]
52549
+ }],
52550
+ sizeMessage: [{
52551
+ type: i0.Input,
52552
+ args: [{
52553
+ isSignal: true,
52554
+ alias: "sizeMessage",
52555
+ required: false
52556
+ }]
52557
+ }],
52558
+ composeLabel: [{
52559
+ type: i0.Input,
52560
+ args: [{
52561
+ isSignal: true,
52562
+ alias: "composeLabel",
52563
+ required: false
52564
+ }]
52565
+ }],
52566
+ composePlaceholder: [{
52567
+ type: i0.Input,
52568
+ args: [{
52569
+ isSignal: true,
52570
+ alias: "composePlaceholder",
52571
+ required: false
52572
+ }]
52573
+ }],
52574
+ sendLabel: [{
52575
+ type: i0.Input,
52576
+ args: [{
52577
+ isSignal: true,
52578
+ alias: "sendLabel",
52579
+ required: false
52580
+ }]
52581
+ }],
52582
+ attachLabel: [{
52583
+ type: i0.Input,
52584
+ args: [{
52585
+ isSignal: true,
52586
+ alias: "attachLabel",
52587
+ required: false
52588
+ }]
52589
+ }],
52590
+ removeAttachmentLabel: [{
52591
+ type: i0.Input,
52592
+ args: [{
52593
+ isSignal: true,
52594
+ alias: "removeAttachmentLabel",
52595
+ required: false
52596
+ }]
52597
+ }],
52598
+ attachmentPreviewLabel: [{
52599
+ type: i0.Input,
52600
+ args: [{
52601
+ isSignal: true,
52602
+ alias: "attachmentPreviewLabel",
52603
+ required: false
52604
+ }]
52605
+ }],
52606
+ now: [{
52607
+ type: i0.Input,
52608
+ args: [{
52609
+ isSignal: true,
52610
+ alias: "now",
52611
+ required: false
52612
+ }]
52613
+ }],
52614
+ searchChange: [{
52615
+ type: i0.Output,
52616
+ args: ["searchChange"]
52617
+ }],
52618
+ filterChange: [{
52619
+ type: i0.Output,
52620
+ args: ["filterChange"]
52621
+ }],
52622
+ pageChange: [{
52623
+ type: i0.Output,
52624
+ args: ["pageChange"]
52625
+ }],
52626
+ selectConversation: [{
52627
+ type: i0.Output,
52628
+ args: ["selectConversation"]
52629
+ }],
52630
+ back: [{
52631
+ type: i0.Output,
52632
+ args: ["back"]
52633
+ }],
52634
+ newConversation: [{
52635
+ type: i0.Output,
52636
+ args: ["newConversation"]
52637
+ }],
52638
+ retry: [{
52639
+ type: i0.Output,
52640
+ args: ["retry"]
52641
+ }],
52642
+ deleteConversation: [{
52643
+ type: i0.Output,
52644
+ args: ["deleteConversation"]
52645
+ }],
52646
+ statusChange: [{
52647
+ type: i0.Output,
52648
+ args: ["statusChange"]
52649
+ }],
52650
+ templateRequest: [{
52651
+ type: i0.Output,
52652
+ args: ["templateRequest"]
52653
+ }],
52654
+ send: [{
52655
+ type: i0.Output,
52656
+ args: ["send"]
52657
+ }],
52658
+ filesSelected: [{
52659
+ type: i0.Output,
52660
+ args: ["filesSelected"]
52661
+ }],
52662
+ attachmentRemove: [{
52663
+ type: i0.Output,
52664
+ args: ["attachmentRemove"]
52665
+ }],
52666
+ mediaOpen: [{
52667
+ type: i0.Output,
52668
+ args: ["mediaOpen"]
52669
+ }],
52670
+ messageAction: [{
52671
+ type: i0.Output,
52672
+ args: ["messageAction"]
52673
+ }],
52674
+ loadEarlier: [{
52675
+ type: i0.Output,
52676
+ args: ["loadEarlier"]
52677
+ }],
52678
+ messagesRetry: [{
52679
+ type: i0.Output,
52680
+ args: ["messagesRetry"]
52681
+ }],
52682
+ threadHeading: [{
52683
+ type: i0.ViewChild,
52684
+ args: ["threadHeading", { isSignal: true }]
52685
+ }],
52686
+ messagesEl: [{
52687
+ type: i0.ViewChild,
52688
+ args: ["messagesEl", { isSignal: true }]
52689
+ }],
52690
+ contextPanel: [{
52691
+ type: i0.ViewChild,
52692
+ args: ["contextPanel", { isSignal: true }]
52693
+ }],
52694
+ fileInput: [{
52695
+ type: i0.ViewChild,
52696
+ args: [i0.forwardRef(() => FileInputComponent), { isSignal: true }]
52697
+ }]
52698
+ }
52699
+ });
52700
+ export { ActionBarComponent, AlertComponent, AppShellComponent, AudioPlayerComponent, AvatarComponent, BADGE_VARIANT_STYLES, BadgeComponent, BankAccountFormComponent, BarRowComponent, BoardCardDirective, BoardComponent, BulkMessagePanelComponent, BusinessHoursComponent, ButtonComponent, CalendarComponent, CardListItemComponent, CheckboxComponent, CheckboxTrailingDirective, ChipComponent, ChipGroupComponent, ColorInputComponent, ColumnFilterComponent, ColumnsComponent, ComboboxComponent, ConfirmOutletComponent, ConfirmService, ContactPickerComponent, ConversationsComponent, DEFAULT_BANK_ACCOUNT_TYPE_OPTIONS, DEFAULT_BANK_HOLDER_TYPE_OPTIONS, DEFAULT_BANK_MANDATE_TEXT, DEFAULT_EMAIL_TEMPLATE_BLOCK_GROUPS, DEFAULT_EMAIL_TEMPLATE_VARIABLE_GROUPS, DEFAULT_PASSWORD_RULES, DROPDOWN_GROUP, DataTableComponent, DateInputComponent, DateRangePickerComponent, DatetimeInputComponent, DetailCardComponent, DiscountSelectorComponent, DividerComponent, DropdownComponent, EMAIL_BLOCK_DRAG_TYPE, EMAIL_TEMPLATE_MAX_BODY, EMAIL_TEMPLATE_MAX_TEXT, EMAIL_TEMPLATE_START_TEXT, EmailTemplateEditorComponent, EmptyStateComponent, ErrorComponent, ErrorStateComponent, FORGEROUTE_CONFIG, FadeComponent, FileInputComponent, FixedFooterComponent, FormColSpanDirective, FormComponent, FormRowComponent, FormSectionComponent, HintComponent, IDX_BEHAVIOR_SIGNALS, INTEGRATION_CATALOG, INTEGRATION_FIELD_DEFS, INTEGRATION_GROUP_ORDER, INTEGRATION_OPTION_DEFS, IconComponent, ImageComponent, ImageGalleryComponent, ImageGalleryDialogComponent, ImagePreviewComponent, ImageRepositionComponent, ImportExportComponent, ImportSourceGridComponent, KpiCardComponent, LAYOUT_GAP_PX, ListComponent, ListItemComponent, LiveRegionComponent, MAX_EMAIL_ADDRESS_LENGTH, ModalComponent, MoreMenuComponent, MultiSelectComponent, NOTES_MAX_LENGTH, NotesComponent, OfflineBannerComponent, OptionCardComponent, PHONE_NUMBER_AREA_CODE_LENGTH, PHONE_NUMBER_ZIP_LENGTH, PageComponent, PaginationComponent, PanelInfoListComponent, PasswordRequirementsComponent, PdfHotspotComponent, PhoneNumberPickerComponent, PillTabsComponent, ProgressBarComponent, ProgressRingComponent, QrCodeComponent, QuickFilterTabsComponent, RICH_TEXT_OPTIONS, RadioComponent, RadioGroupComponent, RadioMatrixComponent, RadioOptionContentDirective, ReadonlyFieldsetComponent, ReminderAlertsComponent, RichTextEditorComponent, SEMANTIC_BADGE_MAP, SETUP_DONE_KEY, SETUP_INTEGRATIONS, SearchInputComponent, SectionHeaderComponent, SelectComponent, SetupWizardComponent, SetupWizardStepDirective, SetupWizardStepHeaderDirective, ShareMenuComponent, ShowComponent, SidePanelComponent, SidebarLayoutComponent, SignaturePadComponent, SkeletonComponent, SnackbarComponent, SnackbarService, StackComponent, StarComponent, StepperComponent, TableToolbarComponent, TextComponent, TextInputComponent, TextTemplatePickerComponent, TextareaInputComponent, TimeInputComponent, TimelineComponent, ToastComponent, ToastService, ToggleBadgeComponent, ToggleComponent, TooltipDirective, US_STATES, UiFieldValidity, acceptLabel, appShellGroupsStorageKey, autoVariant, blockHasContent, buildDefaultSchedule, buildPreviewDocument, buildVideoBlockHtml, builtInActionIcon, businessTimeOptions, conversationDateLabel, conversationInitial, conversationMessageStatusLabel, conversationMessageStatusMark, createFieldReveal, decodeFilterValues, digitsOnly, downloadBlob, emailShareUrl, encodeFilterValue, encodeFilterValues, errorContextInterceptor, escapeHtml, facebookShareUrl, fileMatchesAccept, formatAddress, formatCategoryLabel, formatConversationPhone, formatConversationTime, formatCurrency, formatFileSize, formatIsoDate, formatIsoDateTime, formatMessageTime, formatTime, formatVideoDuration, getEligibleIds, getEligibleOptions, getErrorMessage, gmailShareUrl, groupMessagesByDay, humanReadableMessage, iconPath, insideEditorBlock, integrationPlainText, integrationsForApp, integrationsOnlyFor, isBlockDrag, isValidEmailAddress, isWebUrl, isoKey, issueToErrors, linkedInShareUrl, maxLengthIssue, mergeDescribedBy, normalizeHexColor, outlookShareUrl, parseBizHours, parseIso, parseTime, passwordMeetsRules, pluralize, provideForgerouteToast, reorderItems, requiredIssue, resolveLayoutGap, resolvePreset, serializeBizHours, serializedTextLength, setupIntegrations, splitIntro, truncateConversationText, xShareUrl };
50183
52701
 
50184
52702
  //# sourceMappingURL=forgeroute-ui.mjs.map