@propbinder/mobile-design 0.2.4 → 0.2.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.d.ts CHANGED
@@ -1,7 +1,8 @@
1
1
  import * as _angular_core from '@angular/core';
2
- import { AfterViewInit, OnInit, ElementRef, OnDestroy, EventEmitter, ApplicationRef, EnvironmentInjector, Type } from '@angular/core';
3
- import { ModalController, IonContent, NavController, GestureController } from '@ionic/angular/standalone';
2
+ import { AfterViewInit, OnInit, ElementRef, OnDestroy, EventEmitter, ApplicationRef, EnvironmentInjector, Type, AfterContentInit, ChangeDetectorRef } from '@angular/core';
3
+ import { ModalController, IonContent, NavController, GestureController, ModalOptions as ModalOptions$1 } from '@ionic/angular/standalone';
4
4
  import { ImpactStyle } from '@capacitor/haptics';
5
+ import { DsTextareaComponent } from '@propbinder/design-system';
5
6
  import { ControlValueAccessor } from '@angular/forms';
6
7
  import { Router, ActivatedRoute } from '@angular/router';
7
8
  import { Animation } from '@ionic/angular';
@@ -403,13 +404,58 @@ declare class DsMobilePageMainComponent extends MobilePageBase implements AfterV
403
404
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<DsMobilePageMainComponent, "ds-mobile-page-main", never, { "title": { "alias": "title"; "required": true; "isSignal": true; }; "headerTitle": { "alias": "headerTitle"; "required": false; "isSignal": true; }; "headerSubtitle": { "alias": "headerSubtitle"; "required": false; "isSignal": true; }; "avatarType": { "alias": "avatarType"; "required": false; "isSignal": true; }; "avatarInitials": { "alias": "avatarInitials"; "required": false; "isSignal": true; }; "avatarSrc": { "alias": "avatarSrc"; "required": false; "isSignal": true; }; "avatarIconName": { "alias": "avatarIconName"; "required": false; "isSignal": true; }; "showRefresh": { "alias": "showRefresh"; "required": false; "isSignal": true; }; "showCondensedHeader": { "alias": "showCondensedHeader"; "required": false; "isSignal": true; }; "scrollThreshold": { "alias": "scrollThreshold"; "required": false; "isSignal": true; }; "headerFadeDistance": { "alias": "headerFadeDistance"; "required": false; "isSignal": true; }; "profileMenuItems": { "alias": "profileMenuItems"; "required": false; "isSignal": true; }; }, { "avatarClick": "avatarClick"; "profileActionSelected": "profileActionSelected"; "refresh": "refresh"; "scroll": "scroll"; }, never, ["[header-content]", "*"], true, never>;
404
405
  }
405
406
 
407
+ interface InlineTabItem {
408
+ id: string;
409
+ label: string;
410
+ badge?: number;
411
+ }
412
+ /**
413
+ * DsMobileInlineTabsComponent
414
+ *
415
+ * Pill-style inline tabs for filtering/switching views
416
+ * Used in the purple header section of pages
417
+ *
418
+ * @example
419
+ * ```html
420
+ * <ds-mobile-inline-tabs
421
+ * [tabs]="[
422
+ * { id: 'all', label: 'All' },
423
+ * { id: 'open', label: 'Open' },
424
+ * { id: 'closed', label: 'Closed' }
425
+ * ]"
426
+ * [activeTab]="'all'"
427
+ * (tabChange)="handleTabChange($event)">
428
+ * </ds-mobile-inline-tabs>
429
+ * ```
430
+ */
431
+ declare class DsMobileInlineTabsComponent {
432
+ /**
433
+ * Array of tab items to display
434
+ */
435
+ tabs: _angular_core.InputSignal<InlineTabItem[]>;
436
+ /**
437
+ * Currently active tab ID
438
+ */
439
+ activeTab: _angular_core.InputSignal<string>;
440
+ /**
441
+ * Emitted when a tab is clicked
442
+ */
443
+ tabChange: _angular_core.OutputEmitterRef<string>;
444
+ handleTabClick(tabId: string): void;
445
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<DsMobileInlineTabsComponent, never>;
446
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<DsMobileInlineTabsComponent, "ds-mobile-inline-tabs", never, { "tabs": { "alias": "tabs"; "required": true; "isSignal": true; }; "activeTab": { "alias": "activeTab"; "required": true; "isSignal": true; }; }, { "tabChange": "tabChange"; }, never, never, true, never>;
447
+ }
448
+
406
449
  /**
407
450
  * DsMobilePageDetailsComponent
408
451
  *
409
- * A mobile page layout for detail/drill-down pages with:
410
- * - Back button header (mobile + desktop variants)
411
- * - White background content area
412
- * - Responsive padding
452
+ * A complete mobile page layout for detail/drill-down pages with:
453
+ * - Fixed header with back button + title (fades in on scroll)
454
+ * - Purple expandable header section (scrolls with content)
455
+ * - Optional inline tabs in expandable header
456
+ * - White rounded content wrapper
457
+ * - Pull-to-refresh support (native platforms only)
458
+ * - Auto scroll title fade-in and header fade-out
413
459
  *
414
460
  * @example
415
461
  * ```html
@@ -422,47 +468,63 @@ declare class DsMobilePageMainComponent extends MobilePageBase implements AfterV
422
468
  * </div>
423
469
  * </ds-mobile-page-details>
424
470
  *
425
- * <!-- With default back route -->
471
+ * <!-- With tabs -->
426
472
  * <ds-mobile-page-details
427
- * title="Invoice Details"
428
- * backRoute="/invoices">
473
+ * title="Inquiry Details"
474
+ * [tabs]="tabItems"
475
+ * [activeTab]="activeTab()"
476
+ * (tabChange)="setActiveTab($event)"
477
+ * (back)="goBack()">
429
478
  * <div class="page-content">
430
479
  * <!-- Your content -->
431
480
  * </div>
432
481
  * </ds-mobile-page-details>
433
482
  * ```
434
483
  */
435
- declare class DsMobilePageDetailsComponent extends MobilePageBase {
484
+ declare class DsMobilePageDetailsComponent extends MobilePageBase implements AfterViewInit {
436
485
  private navCtrl;
437
486
  private elementRef;
487
+ ionContent?: IonContent;
488
+ private platform;
489
+ isNativePlatform: _angular_core.Signal<boolean>;
438
490
  title: _angular_core.InputSignal<string>;
439
491
  backRoute: _angular_core.InputSignal<string>;
492
+ tabs: _angular_core.InputSignal<InlineTabItem[] | undefined>;
493
+ activeTab: _angular_core.InputSignal<string>;
494
+ showRefresh: _angular_core.InputSignal<boolean>;
495
+ scrollThreshold: _angular_core.InputSignal<number>;
496
+ headerFadeDistance: _angular_core.InputSignal<number>;
440
497
  back: _angular_core.OutputEmitterRef<void>;
498
+ tabChange: _angular_core.OutputEmitterRef<string>;
499
+ refresh: _angular_core.OutputEmitterRef<any>;
500
+ scroll: _angular_core.OutputEmitterRef<any>;
441
501
  constructor(navCtrl: NavController, elementRef: ElementRef);
502
+ ngAfterViewInit(): void;
442
503
  /**
443
504
  * Handle back navigation
444
505
  *
445
506
  * By default, navigates using the provided backRoute or browser back.
446
507
  * Parent components can listen to the (back) event to override this behavior.
447
- *
448
- * @example
449
- * ```html
450
- * <!-- Default behavior: uses backRoute or browser back -->
451
- * <ds-mobile-page-details
452
- * title="Details"
453
- * backRoute="/home">
454
- * </ds-mobile-page-details>
455
- *
456
- * <!-- Custom behavior: parent handles navigation -->
457
- * <ds-mobile-page-details
458
- * title="Details"
459
- * (back)="customBackHandler()">
460
- * </ds-mobile-page-details>
461
- * ```
462
508
  */
463
509
  handleBack(): void;
510
+ /**
511
+ * Handle tab change
512
+ */
513
+ handleTabChange(tabId: string): void;
514
+ /**
515
+ * Handle scroll events
516
+ * - Shows title in fixed header when scrolled past threshold
517
+ * - Fades out expandable header content based on scroll position
518
+ * - Emits scroll event for custom handling
519
+ */
520
+ handleScroll(event: any): void;
521
+ /**
522
+ * Handle pull-to-refresh
523
+ * Emits refresh event - parent should call event.target.complete()
524
+ */
525
+ handleRefresh(event: any): Promise<void>;
464
526
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<DsMobilePageDetailsComponent, never>;
465
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<DsMobilePageDetailsComponent, "ds-mobile-page-details", never, { "title": { "alias": "title"; "required": true; "isSignal": true; }; "backRoute": { "alias": "backRoute"; "required": false; "isSignal": true; }; }, { "back": "back"; }, never, ["*"], true, never>;
527
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<DsMobilePageDetailsComponent, "ds-mobile-page-details", never, { "title": { "alias": "title"; "required": true; "isSignal": true; }; "backRoute": { "alias": "backRoute"; "required": false; "isSignal": true; }; "tabs": { "alias": "tabs"; "required": false; "isSignal": true; }; "activeTab": { "alias": "activeTab"; "required": false; "isSignal": true; }; "showRefresh": { "alias": "showRefresh"; "required": false; "isSignal": true; }; "scrollThreshold": { "alias": "scrollThreshold"; "required": false; "isSignal": true; }; "headerFadeDistance": { "alias": "headerFadeDistance"; "required": false; "isSignal": true; }; }, { "back": "back"; "tabChange": "tabChange"; "refresh": "refresh"; "scroll": "scroll"; }, never, ["*"], true, never>;
466
528
  }
467
529
 
468
530
  /**
@@ -814,6 +876,72 @@ declare class DsMobilePostComposerComponent {
814
876
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<DsMobilePostComposerComponent, "ds-mobile-post-composer", never, { "avatarInitials": { "alias": "avatarInitials"; "required": false; "isSignal": true; }; "avatarType": { "alias": "avatarType"; "required": false; "isSignal": true; }; "avatarSrc": { "alias": "avatarSrc"; "required": false; "isSignal": true; }; "avatarIconName": { "alias": "avatarIconName"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "buttonText": { "alias": "buttonText"; "required": false; "isSignal": true; }; }, { "composerClick": "composerClick"; }, never, never, true, never>;
815
877
  }
816
878
 
879
+ /**
880
+ * File type for attachment preview
881
+ */
882
+ type AttachmentFileType = 'image' | 'pdf' | 'doc' | 'docx' | 'xls' | 'xlsx' | 'other';
883
+ /**
884
+ * Attachment data interface
885
+ */
886
+ interface AttachmentData {
887
+ id: string;
888
+ src: string;
889
+ type: AttachmentFileType;
890
+ name?: string;
891
+ size?: string;
892
+ }
893
+ /**
894
+ * DsMobileAttachmentPreviewComponent
895
+ *
896
+ * Reusable component for displaying attachment previews.
897
+ * Supports both image previews and file type indicators (PDF, DOCX, etc.).
898
+ *
899
+ * Features:
900
+ * - Image preview for photos
901
+ * - File type indicator box for documents
902
+ * - Remove button overlay
903
+ * - Consistent 96x96 size
904
+ *
905
+ * @example
906
+ * ```html
907
+ * <!-- Image attachment -->
908
+ * <ds-mobile-attachment-preview
909
+ * [attachment]="{ id: '1', src: 'photo.jpg', type: 'image' }"
910
+ * (remove)="handleRemove($event)">
911
+ * </ds-mobile-attachment-preview>
912
+ *
913
+ * <!-- PDF attachment -->
914
+ * <ds-mobile-attachment-preview
915
+ * [attachment]="{ id: '2', src: 'doc.pdf', type: 'pdf', name: 'Document.pdf' }"
916
+ * (remove)="handleRemove($event)">
917
+ * </ds-mobile-attachment-preview>
918
+ * ```
919
+ */
920
+ declare class DsMobileAttachmentPreviewComponent {
921
+ /**
922
+ * Attachment data to display
923
+ */
924
+ attachment: _angular_core.InputSignal<AttachmentData>;
925
+ /**
926
+ * Emits when the remove button is clicked
927
+ */
928
+ remove: _angular_core.OutputEmitterRef<string>;
929
+ /**
930
+ * Get the file type label (PDF, DOCX, etc.)
931
+ */
932
+ getFileTypeLabel(): string;
933
+ /**
934
+ * Get the appropriate icon name based on file type
935
+ */
936
+ getIconName(): string;
937
+ /**
938
+ * Handle remove button click
939
+ */
940
+ handleRemove(): void;
941
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<DsMobileAttachmentPreviewComponent, never>;
942
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<DsMobileAttachmentPreviewComponent, "ds-mobile-attachment-preview", never, { "attachment": { "alias": "attachment"; "required": true; "isSignal": true; }; }, { "remove": "remove"; }, never, never, true, never>;
943
+ }
944
+
817
945
  /**
818
946
  * DsMobileMessageComposerComponent
819
947
  *
@@ -859,6 +987,14 @@ declare class DsMobileMessageComposerComponent implements AfterViewInit, OnDestr
859
987
  * Send button aria label
860
988
  */
861
989
  sendButtonLabel: _angular_core.InputSignal<string>;
990
+ /**
991
+ * Attachment button aria label
992
+ */
993
+ attachmentButtonLabel: _angular_core.InputSignal<string>;
994
+ /**
995
+ * Whether to show the attachment button
996
+ */
997
+ showAttachmentButton: _angular_core.InputSignal<boolean>;
862
998
  /**
863
999
  * Edit indicator text (when editing)
864
1000
  */
@@ -887,10 +1023,18 @@ declare class DsMobileMessageComposerComponent implements AfterViewInit, OnDestr
887
1023
  * ViewChild for message input
888
1024
  */
889
1025
  messageInput?: ElementRef<HTMLTextAreaElement>;
1026
+ /**
1027
+ * ViewChild for file input
1028
+ */
1029
+ fileInput?: ElementRef<HTMLInputElement>;
890
1030
  /**
891
1031
  * Message text signal
892
1032
  */
893
1033
  messageText: _angular_core.WritableSignal<string>;
1034
+ /**
1035
+ * Attachments signal
1036
+ */
1037
+ attachments: _angular_core.WritableSignal<AttachmentData[]>;
894
1038
  /**
895
1039
  * Editing message state (optional)
896
1040
  */
@@ -930,6 +1074,7 @@ declare class DsMobileMessageComposerComponent implements AfterViewInit, OnDestr
930
1074
  isReply?: boolean;
931
1075
  replyTo?: string;
932
1076
  isEdit?: boolean;
1077
+ attachments?: AttachmentData[];
933
1078
  }>;
934
1079
  /**
935
1080
  * Emits when edit is cancelled
@@ -945,6 +1090,10 @@ declare class DsMobileMessageComposerComponent implements AfterViewInit, OnDestr
945
1090
  mentionSelected: _angular_core.OutputEmitterRef<{
946
1091
  userName: string;
947
1092
  }>;
1093
+ /**
1094
+ * Emits when attachment button is clicked
1095
+ */
1096
+ attachmentClicked: _angular_core.OutputEmitterRef<void>;
948
1097
  ngAfterViewInit(): void;
949
1098
  ngOnDestroy(): void;
950
1099
  /**
@@ -959,6 +1108,10 @@ declare class DsMobileMessageComposerComponent implements AfterViewInit, OnDestr
959
1108
  * Show the keyboard when user interacts with input
960
1109
  */
961
1110
  showKeyboard(): void;
1111
+ /**
1112
+ * Handle keyboard shortcuts (Shift+Enter to send)
1113
+ */
1114
+ handleKeyDown(event: KeyboardEvent): void;
962
1115
  /**
963
1116
  * Handle input changes and detect @ mentions
964
1117
  */
@@ -991,12 +1144,32 @@ declare class DsMobileMessageComposerComponent implements AfterViewInit, OnDestr
991
1144
  * Focus the input
992
1145
  */
993
1146
  focus(): void;
1147
+ /**
1148
+ * Handle attachment button click
1149
+ */
1150
+ handleAttachmentClick(): void;
1151
+ /**
1152
+ * Detect file type from file name or mime type
1153
+ */
1154
+ private detectFileType;
1155
+ /**
1156
+ * Format file size for display
1157
+ */
1158
+ private formatFileSize;
1159
+ /**
1160
+ * Handle file selection from file input
1161
+ */
1162
+ handleFileSelect(event: Event): void;
1163
+ /**
1164
+ * Remove an attachment from the list
1165
+ */
1166
+ removeAttachment(attachmentId: string): void;
994
1167
  /**
995
1168
  * Send message
996
1169
  */
997
1170
  sendMessage(): void;
998
1171
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<DsMobileMessageComposerComponent, never>;
999
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<DsMobileMessageComposerComponent, "ds-mobile-message-composer", never, { "avatarInitials": { "alias": "avatarInitials"; "required": false; "isSignal": true; }; "avatarType": { "alias": "avatarType"; "required": false; "isSignal": true; }; "avatarSrc": { "alias": "avatarSrc"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "sendButtonLabel": { "alias": "sendButtonLabel"; "required": false; "isSignal": true; }; "editIndicatorText": { "alias": "editIndicatorText"; "required": false; "isSignal": true; }; "replyIndicatorText": { "alias": "replyIndicatorText"; "required": false; "isSignal": true; }; "enableMentions": { "alias": "enableMentions"; "required": false; "isSignal": true; }; "mentionUsers": { "alias": "mentionUsers"; "required": false; "isSignal": true; }; "autoFocus": { "alias": "autoFocus"; "required": false; "isSignal": true; }; }, { "messageSent": "messageSent"; "editCancelled": "editCancelled"; "replyCancelled": "replyCancelled"; "mentionSelected": "mentionSelected"; }, never, never, true, never>;
1172
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<DsMobileMessageComposerComponent, "ds-mobile-message-composer", never, { "avatarInitials": { "alias": "avatarInitials"; "required": false; "isSignal": true; }; "avatarType": { "alias": "avatarType"; "required": false; "isSignal": true; }; "avatarSrc": { "alias": "avatarSrc"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "sendButtonLabel": { "alias": "sendButtonLabel"; "required": false; "isSignal": true; }; "attachmentButtonLabel": { "alias": "attachmentButtonLabel"; "required": false; "isSignal": true; }; "showAttachmentButton": { "alias": "showAttachmentButton"; "required": false; "isSignal": true; }; "editIndicatorText": { "alias": "editIndicatorText"; "required": false; "isSignal": true; }; "replyIndicatorText": { "alias": "replyIndicatorText"; "required": false; "isSignal": true; }; "enableMentions": { "alias": "enableMentions"; "required": false; "isSignal": true; }; "mentionUsers": { "alias": "mentionUsers"; "required": false; "isSignal": true; }; "autoFocus": { "alias": "autoFocus"; "required": false; "isSignal": true; }; }, { "messageSent": "messageSent"; "editCancelled": "editCancelled"; "replyCancelled": "replyCancelled"; "mentionSelected": "mentionSelected"; "attachmentClicked": "attachmentClicked"; }, never, never, true, never>;
1000
1173
  }
1001
1174
 
1002
1175
  /**
@@ -1064,6 +1237,10 @@ declare class DsMobileMessageBubbleComponent {
1064
1237
  * Timestamp text (e.g., "12:34", "08-12-2025 13:18")
1065
1238
  */
1066
1239
  timestamp: _angular_core.InputSignal<string>;
1240
+ /**
1241
+ * Whether to show the timestamp below the bubble
1242
+ */
1243
+ showTimestamp: _angular_core.InputSignal<boolean>;
1067
1244
  /**
1068
1245
  * Avatar initials
1069
1246
  */
@@ -1095,6 +1272,10 @@ declare class DsMobileMessageBubbleComponent {
1095
1272
  * Emits when the message is long-pressed
1096
1273
  */
1097
1274
  longPress: _angular_core.OutputEmitterRef<void>;
1275
+ /**
1276
+ * Emits when the message is clicked (to toggle timestamp)
1277
+ */
1278
+ messageClick: _angular_core.OutputEmitterRef<void>;
1098
1279
  /**
1099
1280
  * Long press tracking
1100
1281
  */
@@ -1104,16 +1285,21 @@ declare class DsMobileMessageBubbleComponent {
1104
1285
  private touchStartY;
1105
1286
  private readonly LONG_PRESS_DURATION;
1106
1287
  private readonly MOVE_THRESHOLD;
1288
+ private clickStartTime;
1107
1289
  /**
1108
1290
  * Handle attachment click
1109
1291
  */
1110
1292
  handleAttachmentClick(attachment: ChatAttachment): void;
1293
+ /**
1294
+ * Handle click (for web/mouse support)
1295
+ */
1296
+ handleClick(event: MouseEvent): void;
1111
1297
  /**
1112
1298
  * Handle touch start for long press detection
1113
1299
  */
1114
1300
  handleTouchStart(event: TouchEvent): void;
1115
1301
  /**
1116
- * Handle touch end to clear long press timer
1302
+ * Handle touch end to clear long press timer and detect short tap
1117
1303
  */
1118
1304
  handleTouchEnd(event: TouchEvent): void;
1119
1305
  /**
@@ -1125,7 +1311,7 @@ declare class DsMobileMessageBubbleComponent {
1125
1311
  */
1126
1312
  handleContextMenu(event: Event): void;
1127
1313
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<DsMobileMessageBubbleComponent, never>;
1128
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<DsMobileMessageBubbleComponent, "ds-mobile-message-bubble", never, { "content": { "alias": "content"; "required": true; "isSignal": true; }; "isOwnMessage": { "alias": "isOwnMessage"; "required": false; "isSignal": true; }; "senderName": { "alias": "senderName"; "required": false; "isSignal": true; }; "timestamp": { "alias": "timestamp"; "required": true; "isSignal": true; }; "avatarInitials": { "alias": "avatarInitials"; "required": false; "isSignal": true; }; "avatarType": { "alias": "avatarType"; "required": false; "isSignal": true; }; "avatarSrc": { "alias": "avatarSrc"; "required": false; "isSignal": true; }; "attachments": { "alias": "attachments"; "required": false; "isSignal": true; }; "clickable": { "alias": "clickable"; "required": false; "isSignal": true; }; }, { "attachmentClick": "attachmentClick"; "longPress": "longPress"; }, never, never, true, never>;
1314
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<DsMobileMessageBubbleComponent, "ds-mobile-message-bubble", never, { "content": { "alias": "content"; "required": true; "isSignal": true; }; "isOwnMessage": { "alias": "isOwnMessage"; "required": false; "isSignal": true; }; "senderName": { "alias": "senderName"; "required": false; "isSignal": true; }; "timestamp": { "alias": "timestamp"; "required": true; "isSignal": true; }; "showTimestamp": { "alias": "showTimestamp"; "required": false; "isSignal": true; }; "avatarInitials": { "alias": "avatarInitials"; "required": false; "isSignal": true; }; "avatarType": { "alias": "avatarType"; "required": false; "isSignal": true; }; "avatarSrc": { "alias": "avatarSrc"; "required": false; "isSignal": true; }; "attachments": { "alias": "attachments"; "required": false; "isSignal": true; }; "clickable": { "alias": "clickable"; "required": false; "isSignal": true; }; }, { "attachmentClick": "attachmentClick"; "longPress": "longPress"; "messageClick": "messageClick"; }, never, never, true, never>;
1129
1315
  }
1130
1316
 
1131
1317
  /**
@@ -2058,85 +2244,293 @@ declare class DsMobileTabsComponent implements OnInit {
2058
2244
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<DsMobileTabsComponent, "ds-mobile-tabs", never, { "tabs": { "alias": "tabs"; "required": false; }; "avatarType": { "alias": "avatarType"; "required": false; }; "avatarInitials": { "alias": "avatarInitials"; "required": false; }; "avatarSrc": { "alias": "avatarSrc"; "required": false; }; "avatarIconName": { "alias": "avatarIconName"; "required": false; }; }, { "avatarClick": "avatarClick"; }, never, never, true, never>;
2059
2245
  }
2060
2246
 
2061
- interface InlineTabItem {
2062
- id: string;
2063
- label: string;
2064
- badge?: number;
2065
- }
2066
2247
  /**
2067
- * DsMobileInlineTabsComponent
2248
+ * DsMobileCardInlineComponent
2068
2249
  *
2069
- * Pill-style inline tabs for filtering/switching views
2070
- * Used in the purple header section of pages
2250
+ * A versatile, always-interactive inline card component for standalone or small-group usage.
2251
+ * Designed for tappable card-like elements such as file attachments, contact cards, etc.
2252
+ * Not intended for long scrolling lists - use ds-mobile-list-item for that purpose.
2253
+ *
2254
+ * Features:
2255
+ * - Always interactive/tappable (unless disabled)
2256
+ * - Two layout variants: default (column) and compact (row)
2257
+ * - Flexible content projection with leading/main/trailing slots
2258
+ * - Consistent styling with rounded corners and neutral background
2259
+ * - Built-in hover and active states
2260
+ * - Accessibility features (role, tabindex, aria attributes)
2071
2261
  *
2072
2262
  * @example
2073
2263
  * ```html
2074
- * <ds-mobile-inline-tabs
2075
- * [tabs]="[
2076
- * { id: 'all', label: 'All' },
2077
- * { id: 'open', label: 'Open' },
2078
- * { id: 'closed', label: 'Closed' }
2079
- * ]"
2080
- * [activeTab]="'all'"
2081
- * (tabChange)="handleTabChange($event)">
2082
- * </ds-mobile-inline-tabs>
2264
+ * <!-- Default variant (column layout) -->
2265
+ * <ds-mobile-card-inline
2266
+ * [variant]="'default'"
2267
+ * (cardClick)="handleClick()">
2268
+ *
2269
+ * <div content-leading>
2270
+ * <ds-avatar initials="JD" />
2271
+ * </div>
2272
+ *
2273
+ * <div content-main>
2274
+ * <div class="title">Document Title</div>
2275
+ * <div class="subtitle">PDF · 1.2 MB</div>
2276
+ * </div>
2277
+ *
2278
+ * <ds-icon content-trailing name="remixArrowRightSLine" />
2279
+ * </ds-mobile-card-inline>
2280
+ *
2281
+ * <!-- Compact variant (row layout) -->
2282
+ * <ds-mobile-card-inline
2283
+ * [variant]="'compact'"
2284
+ * (cardClick)="handleClick()">
2285
+ *
2286
+ * <ds-avatar content-leading size="sm" />
2287
+ *
2288
+ * <div content-main>
2289
+ * <span class="name">File.pdf</span>
2290
+ * <span class="size">245 KB</span>
2291
+ * </div>
2292
+ *
2293
+ * <ds-icon content-trailing name="remixArrowRightSLine" />
2294
+ * </ds-mobile-card-inline>
2295
+ *
2296
+ * <!-- Disabled state -->
2297
+ * <ds-mobile-card-inline [disabled]="true">
2298
+ * <div content-main>Disabled card</div>
2299
+ * </ds-mobile-card-inline>
2083
2300
  * ```
2084
2301
  */
2085
- declare class DsMobileInlineTabsComponent {
2302
+ declare class DsMobileCardInlineComponent {
2086
2303
  /**
2087
- * Array of tab items to display
2304
+ * Display variant
2305
+ * - 'default' - Column layout with standard padding (gap: 12px, padding: 10px 12px)
2306
+ * - 'compact' - Row layout with reduced padding (gap: 8px, padding: 10px)
2088
2307
  */
2089
- tabs: _angular_core.InputSignal<InlineTabItem[]>;
2308
+ variant: _angular_core.InputSignal<"default" | "compact">;
2090
2309
  /**
2091
- * Currently active tab ID
2310
+ * Whether the card is disabled
2311
+ * Disables all interactions and reduces opacity
2092
2312
  */
2093
- activeTab: _angular_core.InputSignal<string>;
2313
+ disabled: _angular_core.InputSignal<boolean>;
2094
2314
  /**
2095
- * Emitted when a tab is clicked
2315
+ * Emits when the card is clicked (if not disabled)
2096
2316
  */
2097
- tabChange: _angular_core.OutputEmitterRef<string>;
2098
- handleTabClick(tabId: string): void;
2099
- static ɵfac: _angular_core.ɵɵFactoryDeclaration<DsMobileInlineTabsComponent, never>;
2100
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<DsMobileInlineTabsComponent, "ds-mobile-inline-tabs", never, { "tabs": { "alias": "tabs"; "required": true; "isSignal": true; }; "activeTab": { "alias": "activeTab"; "required": true; "isSignal": true; }; }, { "tabChange": "tabChange"; }, never, never, true, never>;
2317
+ cardClick: _angular_core.OutputEmitterRef<void>;
2318
+ /**
2319
+ * Handle click events
2320
+ */
2321
+ handleClick(event: Event): void;
2322
+ /**
2323
+ * Handle keyboard events (Enter/Space)
2324
+ */
2325
+ handleKeyDown(event: KeyboardEvent): void;
2326
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<DsMobileCardInlineComponent, never>;
2327
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<DsMobileCardInlineComponent, "ds-mobile-card-inline", never, { "variant": { "alias": "variant"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; }, { "cardClick": "cardClick"; }, never, ["[content-leading]", "[content-main]", "*", "[content-trailing]"], true, never>;
2101
2328
  }
2102
2329
 
2103
2330
  /**
2104
- * Media file types supported by the lightbox
2105
- */
2106
- type LightboxMediaType = 'image' | 'pdf';
2107
- /**
2108
- * Base media file interface
2109
- */
2110
- interface LightboxMediaFile {
2111
- /** File source URL */
2112
- src: string;
2113
- /** Media type - determines which viewer to use */
2114
- type: LightboxMediaType;
2115
- /** File title */
2116
- title?: string;
2117
- /** File description */
2118
- description?: string;
2119
- }
2120
- /**
2121
- * Image data for lightbox display
2331
+ * DsMobileCardInlineBannerComponent
2332
+ *
2333
+ * Specialized interactive component for displaying notification banners.
2334
+ * Used to show unread message notifications above inquiry details.
2335
+ *
2336
+ * Features:
2337
+ * - Neutral background matching file/contact cards
2338
+ * - Avatar icon with message symbol
2339
+ * - Title and timestamp
2340
+ * - Unread count badge
2341
+ * - Chevron for navigation indication
2342
+ *
2343
+ * @example
2344
+ * ```html
2345
+ * <ds-mobile-card-inline-banner
2346
+ * [title]="'New messages'"
2347
+ * [timestamp]="'2 min ago'"
2348
+ * [unreadCount]="3"
2349
+ * (bannerClick)="navigateToMessages()">
2350
+ * </ds-mobile-card-inline-banner>
2351
+ * ```
2122
2352
  */
2123
- interface LightboxImage extends LightboxMediaFile {
2124
- type: 'image';
2125
- /** Alt text for accessibility */
2126
- alt?: string;
2127
- /** Thumbnail URL for faster loading (optional) */
2128
- thumbnail?: string;
2129
- /** Whether the image is liked */
2130
- isLiked?: boolean;
2131
- /** Number of likes */
2132
- likeCount?: number;
2133
- /** Number of comments */
2134
- commentCount?: number;
2353
+ declare class DsMobileCardInlineBannerComponent {
2354
+ /**
2355
+ * Banner title (e.g., "New messages", "Unread messages")
2356
+ */
2357
+ title: _angular_core.InputSignal<string>;
2358
+ /**
2359
+ * Timestamp text (e.g., "2 min ago", "Just now")
2360
+ */
2361
+ timestamp: _angular_core.InputSignal<string>;
2362
+ /**
2363
+ * Number of unread items (optional, shows badge if > 0)
2364
+ */
2365
+ unreadCount: _angular_core.InputSignal<number>;
2366
+ /**
2367
+ * Layout variant
2368
+ * - 'default' - Standard padding and column layout
2369
+ * - 'compact' - Reduced padding and row layout
2370
+ */
2371
+ layout: _angular_core.InputSignal<"default" | "compact">;
2372
+ /**
2373
+ * Emits when the banner is clicked
2374
+ */
2375
+ bannerClick: _angular_core.OutputEmitterRef<void>;
2376
+ handleBannerClick(): void;
2377
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<DsMobileCardInlineBannerComponent, never>;
2378
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<DsMobileCardInlineBannerComponent, "ds-mobile-card-inline-banner", never, { "title": { "alias": "title"; "required": true; "isSignal": true; }; "timestamp": { "alias": "timestamp"; "required": false; "isSignal": true; }; "unreadCount": { "alias": "unreadCount"; "required": false; "isSignal": true; }; "layout": { "alias": "layout"; "required": false; "isSignal": true; }; }, { "bannerClick": "bannerClick"; }, never, never, true, never>;
2135
2379
  }
2380
+
2136
2381
  /**
2137
- * PDF document data for lightbox display
2382
+ * DsMobileCardInlineContactComponent
2383
+ *
2384
+ * Specialized interactive component for displaying contacts.
2385
+ * Displays contact name with avatar initials and metadata (person name + phone number).
2386
+ * Similar styling to file attachments with rounded corners and hover states.
2387
+ *
2388
+ * @example
2389
+ * ```html
2390
+ * <ds-mobile-card-inline-contact
2391
+ * [name]="'Mortensen & Søn ApS'"
2392
+ * [initials]="'M'"
2393
+ * [contactPerson]="'John Mortensen'"
2394
+ * [phoneNumber]="'+45 12 34 56 78'"
2395
+ * [clickable]="true"
2396
+ * (contactClick)="openContact()">
2397
+ * </ds-mobile-card-inline-contact>
2398
+ * ```
2138
2399
  */
2139
- interface LightboxPdf extends LightboxMediaFile {
2400
+ declare class DsMobileCardInlineContactComponent {
2401
+ /**
2402
+ * Contact/company name
2403
+ */
2404
+ name: _angular_core.InputSignal<string>;
2405
+ /**
2406
+ * Avatar initials (usually 1-2 letters)
2407
+ */
2408
+ initials: _angular_core.InputSignal<string>;
2409
+ /**
2410
+ * Contact person name (optional)
2411
+ */
2412
+ contactPerson: _angular_core.InputSignal<string>;
2413
+ /**
2414
+ * Phone number (optional)
2415
+ */
2416
+ phoneNumber: _angular_core.InputSignal<string>;
2417
+ /**
2418
+ * Layout variant
2419
+ * - 'default' - Standard padding and column layout
2420
+ * - 'compact' - Reduced padding and row layout
2421
+ */
2422
+ layout: _angular_core.InputSignal<"default" | "compact">;
2423
+ /**
2424
+ * Whether the contact item is clickable
2425
+ */
2426
+ clickable: _angular_core.InputSignal<boolean>;
2427
+ /**
2428
+ * Whether to show chevron icon
2429
+ */
2430
+ showChevron: _angular_core.InputSignal<boolean>;
2431
+ /**
2432
+ * Emits when the contact item is clicked (if clickable)
2433
+ */
2434
+ contactClick: _angular_core.OutputEmitterRef<void>;
2435
+ handleContactClick(): void;
2436
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<DsMobileCardInlineContactComponent, never>;
2437
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<DsMobileCardInlineContactComponent, "ds-mobile-card-inline-contact", never, { "name": { "alias": "name"; "required": true; "isSignal": true; }; "initials": { "alias": "initials"; "required": true; "isSignal": true; }; "contactPerson": { "alias": "contactPerson"; "required": false; "isSignal": true; }; "phoneNumber": { "alias": "phoneNumber"; "required": false; "isSignal": true; }; "layout": { "alias": "layout"; "required": false; "isSignal": true; }; "clickable": { "alias": "clickable"; "required": false; "isSignal": true; }; "showChevron": { "alias": "showChevron"; "required": false; "isSignal": true; }; }, { "contactClick": "contactClick"; }, never, never, true, never>;
2438
+ }
2439
+
2440
+ /**
2441
+ * DsMobileCardInlineFileComponent
2442
+ *
2443
+ * File attachment display for various document types.
2444
+ * Shows file info card with icon, filename, and file size.
2445
+ * Supports PDF and generic document formats.
2446
+ * Emits click event to open file in viewer.
2447
+ *
2448
+ * @example
2449
+ * ```html
2450
+ * <ds-mobile-card-inline-file
2451
+ * [fileName]="'Document.pdf'"
2452
+ * [fileSize]="'1.2 MB'"
2453
+ * [variant]="'pdf'"
2454
+ * [layout]="'compact'"
2455
+ * (fileClick)="openFile()">
2456
+ * </ds-mobile-card-inline-file>
2457
+ * ```
2458
+ */
2459
+ declare class DsMobileCardInlineFileComponent {
2460
+ /**
2461
+ * File name
2462
+ */
2463
+ fileName: _angular_core.InputSignal<string>;
2464
+ /**
2465
+ * File size display (e.g., "1.2 MB")
2466
+ */
2467
+ fileSize: _angular_core.InputSignal<string>;
2468
+ /**
2469
+ * File type variant
2470
+ * - 'pdf' - PDF document (red icon)
2471
+ * - 'doc' - Generic document (blue icon)
2472
+ */
2473
+ variant: _angular_core.InputSignal<"pdf" | "doc">;
2474
+ /**
2475
+ * Layout variant
2476
+ * - 'default' - Standard padding and column layout
2477
+ * - 'compact' - Reduced padding and row layout
2478
+ */
2479
+ layout: _angular_core.InputSignal<"default" | "compact">;
2480
+ /**
2481
+ * Emits when the file attachment is clicked
2482
+ */
2483
+ fileClick: _angular_core.OutputEmitterRef<void>;
2484
+ /**
2485
+ * Get the appropriate icon name based on variant
2486
+ */
2487
+ getIconName(): string;
2488
+ /**
2489
+ * Get the file type label based on variant
2490
+ */
2491
+ getFileTypeLabel(): string;
2492
+ handleClick(): void;
2493
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<DsMobileCardInlineFileComponent, never>;
2494
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<DsMobileCardInlineFileComponent, "ds-mobile-card-inline-file", never, { "fileName": { "alias": "fileName"; "required": false; "isSignal": true; }; "fileSize": { "alias": "fileSize"; "required": false; "isSignal": true; }; "variant": { "alias": "variant"; "required": false; "isSignal": true; }; "layout": { "alias": "layout"; "required": false; "isSignal": true; }; }, { "fileClick": "fileClick"; }, never, never, true, never>;
2495
+ }
2496
+
2497
+ /**
2498
+ * Media file types supported by the lightbox
2499
+ */
2500
+ type LightboxMediaType = 'image' | 'pdf';
2501
+ /**
2502
+ * Base media file interface
2503
+ */
2504
+ interface LightboxMediaFile {
2505
+ /** File source URL */
2506
+ src: string;
2507
+ /** Media type - determines which viewer to use */
2508
+ type: LightboxMediaType;
2509
+ /** File title */
2510
+ title?: string;
2511
+ /** File description */
2512
+ description?: string;
2513
+ }
2514
+ /**
2515
+ * Image data for lightbox display
2516
+ */
2517
+ interface LightboxImage extends LightboxMediaFile {
2518
+ type: 'image';
2519
+ /** Alt text for accessibility */
2520
+ alt?: string;
2521
+ /** Thumbnail URL for faster loading (optional) */
2522
+ thumbnail?: string;
2523
+ /** Whether the image is liked */
2524
+ isLiked?: boolean;
2525
+ /** Number of likes */
2526
+ likeCount?: number;
2527
+ /** Number of comments */
2528
+ commentCount?: number;
2529
+ }
2530
+ /**
2531
+ * PDF document data for lightbox display
2532
+ */
2533
+ interface LightboxPdf extends LightboxMediaFile {
2140
2534
  type: 'pdf';
2141
2535
  /** File size in bytes (optional, for display) */
2142
2536
  fileSize?: number;
@@ -2808,6 +3202,224 @@ declare class DsMobileModalService {
2808
3202
  static ɵprov: _angular_core.ɵɵInjectableDeclaration<DsMobileModalService>;
2809
3203
  }
2810
3204
 
3205
+ /**
3206
+ * MobileModalBase
3207
+ *
3208
+ * Shared base class for mobile modal components.
3209
+ * Provides consistent modal behavior, state management, and keyboard handling.
3210
+ *
3211
+ * **Key Features:**
3212
+ * - Loading and error state management
3213
+ * - Header configuration (title, meta)
3214
+ * - Automatic keyboard height tracking (iOS/Android)
3215
+ * - Fixed bottom component support
3216
+ * - Consistent close behavior
3217
+ *
3218
+ * **Usage:**
3219
+ * ```typescript
3220
+ * export class MyModalComponent extends MobileModalBase {
3221
+ * constructor() {
3222
+ * super();
3223
+ * }
3224
+ * }
3225
+ * ```
3226
+ *
3227
+ * @internal This is a base class and should not be used directly.
3228
+ */
3229
+ declare abstract class MobileModalBase implements OnInit, OnDestroy {
3230
+ protected modalController: ModalController;
3231
+ /**
3232
+ * Reference to IonContent for accessing scroll element
3233
+ */
3234
+ protected ionContent?: IonContent;
3235
+ /**
3236
+ * ResizeObserver for tracking fixed bottom height
3237
+ */
3238
+ private fixedBottomObserver?;
3239
+ /**
3240
+ * Loading state - when true, shows loading indicator
3241
+ * @default false
3242
+ */
3243
+ loading: _angular_core.InputSignal<boolean>;
3244
+ /**
3245
+ * Error state - when set, shows error message
3246
+ * @default undefined
3247
+ */
3248
+ error: _angular_core.InputSignal<string | undefined>;
3249
+ /**
3250
+ * Modal header title
3251
+ * @default ''
3252
+ */
3253
+ headerTitle: _angular_core.InputSignal<string>;
3254
+ /**
3255
+ * Modal header metadata (subtitle/secondary text)
3256
+ * @default ''
3257
+ */
3258
+ headerMeta: _angular_core.InputSignal<string>;
3259
+ /**
3260
+ * Accessibility label for close button
3261
+ * @default 'Close'
3262
+ */
3263
+ closeButtonLabel: _angular_core.InputSignal<string>;
3264
+ /**
3265
+ * Enable automatic keyboard height tracking
3266
+ * When enabled, sets --keyboard-height CSS variable for sliding content
3267
+ * @default false
3268
+ */
3269
+ enableKeyboardHandling: _angular_core.InputSignal<boolean>;
3270
+ /**
3271
+ * Whether modal has a fixed bottom component
3272
+ * Used to manage spacing and keyboard interactions
3273
+ * @default false
3274
+ */
3275
+ hasFixedBottom: _angular_core.InputSignal<boolean>;
3276
+ /**
3277
+ * Emitted when modal is closed
3278
+ */
3279
+ closed: _angular_core.OutputEmitterRef<void>;
3280
+ ngOnInit(): void;
3281
+ ngOnDestroy(): void;
3282
+ /**
3283
+ * Close the modal
3284
+ * Emits closed event and dismisses the modal
3285
+ */
3286
+ close(): void;
3287
+ /**
3288
+ * Set up keyboard event listeners to adjust component position
3289
+ * Uses --keyboard-height for fixed bottom composer and adds padding to scroll area
3290
+ * @protected
3291
+ */
3292
+ protected setupKeyboardListeners(): void;
3293
+ /**
3294
+ * Set up ResizeObserver to track fixed bottom height and apply as CSS variable
3295
+ * This allows dynamic bottom padding that adjusts to content
3296
+ * @protected
3297
+ */
3298
+ protected setupFixedBottomObserver(): Promise<void>;
3299
+ /**
3300
+ * Clean up keyboard event listeners
3301
+ * @protected
3302
+ */
3303
+ protected cleanupKeyboardListeners(): void;
3304
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<MobileModalBase, never>;
3305
+ static ɵdir: _angular_core.ɵɵDirectiveDeclaration<MobileModalBase, never, never, { "loading": { "alias": "loading"; "required": false; "isSignal": true; }; "error": { "alias": "error"; "required": false; "isSignal": true; }; "headerTitle": { "alias": "headerTitle"; "required": false; "isSignal": true; }; "headerMeta": { "alias": "headerMeta"; "required": false; "isSignal": true; }; "closeButtonLabel": { "alias": "closeButtonLabel"; "required": false; "isSignal": true; }; "enableKeyboardHandling": { "alias": "enableKeyboardHandling"; "required": false; "isSignal": true; }; "hasFixedBottom": { "alias": "hasFixedBottom"; "required": false; "isSignal": true; }; }, { "closed": "closed"; }, never, never, true, never>;
3306
+ }
3307
+
3308
+ /**
3309
+ * DsMobileModalBaseComponent
3310
+ *
3311
+ * Base modal component providing consistent layout and behavior for all modals.
3312
+ *
3313
+ * **Features:**
3314
+ * - Optional header with auto-detection of content
3315
+ * - Flexible header with slots for leading content (avatar, icon)
3316
+ * - Title and metadata inputs or custom header slot
3317
+ * - Default loading and error state templates (with override capability)
3318
+ * - Fixed bottom component support (e.g., message composer)
3319
+ * - Automatic keyboard handling
3320
+ * - Safe area support
3321
+ *
3322
+ * **Slot Structure:**
3323
+ * - `[header-leading]` - Left side of header (avatar, icon)
3324
+ * - `[header-main]` - Custom header content (replaces title/meta)
3325
+ * - `[loading-state]` - Custom loading template
3326
+ * - `[error-state]` - Custom error template
3327
+ * - `[footer]` or `[fixed-bottom]` - Fixed bottom component (slides with keyboard)
3328
+ * - Default slot - Main modal content
3329
+ *
3330
+ * @example
3331
+ * ```html
3332
+ * <!-- Simple title modal -->
3333
+ * <ds-mobile-modal-base
3334
+ * headerTitle="Settings"
3335
+ * closeButtonLabel="Close">
3336
+ * <div class="content">...</div>
3337
+ * </ds-mobile-modal-base>
3338
+ *
3339
+ * <!-- Avatar header modal -->
3340
+ * <ds-mobile-modal-base
3341
+ * headerTitle="John Doe"
3342
+ * headerMeta="Tenant · 2h ago"
3343
+ * [hasFixedBottom]="true"
3344
+ * [enableKeyboardHandling]="true">
3345
+ *
3346
+ * <ds-avatar header-leading [initials]="'JD'" size="md" />
3347
+ *
3348
+ * <div class="content">...</div>
3349
+ *
3350
+ * <div fixed-bottom class="composer">...</div>
3351
+ * </ds-mobile-modal-base>
3352
+ *
3353
+ * <!-- Headerless modal (close button positioned absolutely) -->
3354
+ * <ds-mobile-modal-base [showHeader]="false">
3355
+ * <div class="full-width-content">...</div>
3356
+ * </ds-mobile-modal-base>
3357
+ *
3358
+ * <!-- Modal with footer actions (slides with keyboard) -->
3359
+ * <ds-mobile-modal-base
3360
+ * headerTitle="Create Inquiry"
3361
+ * [hasFixedBottom]="true"
3362
+ * [enableKeyboardHandling]="true">
3363
+ *
3364
+ * <div class="content">
3365
+ * <input type="text" placeholder="Type something..." />
3366
+ * </div>
3367
+ *
3368
+ * <div footer class="action-bar">
3369
+ * <button>Cancel</button>
3370
+ * <button>Submit</button>
3371
+ * </div>
3372
+ * </ds-mobile-modal-base>
3373
+ * ```
3374
+ */
3375
+ declare class DsMobileModalBaseComponent extends MobileModalBase implements AfterContentInit {
3376
+ private cdr;
3377
+ /**
3378
+ * Reference to ion-content for keyboard handling
3379
+ */
3380
+ ionContent?: IonContent;
3381
+ /**
3382
+ * Control header visibility
3383
+ * - true: Always show header
3384
+ * - false: Never show header (close button becomes absolute)
3385
+ * - 'auto' (default): Auto-detect based on header content
3386
+ */
3387
+ showHeader: _angular_core.InputSignal<boolean | "auto">;
3388
+ /**
3389
+ * Detect if custom loading state is provided
3390
+ */
3391
+ customLoadingState?: ElementRef;
3392
+ /**
3393
+ * Detect if custom error state is provided
3394
+ */
3395
+ customErrorState?: ElementRef;
3396
+ /**
3397
+ * Detect if header leading content is provided
3398
+ */
3399
+ headerLeading?: ElementRef;
3400
+ /**
3401
+ * Detect if header main content is provided
3402
+ */
3403
+ headerMain?: ElementRef;
3404
+ /**
3405
+ * Flag to track if content has been initialized
3406
+ */
3407
+ hasCustomLoadingState: boolean;
3408
+ hasCustomErrorState: boolean;
3409
+ constructor(cdr: ChangeDetectorRef);
3410
+ ngAfterContentInit(): void;
3411
+ /**
3412
+ * Determine if header should be shown based on showHeader input and content detection
3413
+ */
3414
+ shouldShowHeader(): boolean;
3415
+ /**
3416
+ * Check if a content child slot has actual content
3417
+ */
3418
+ private hasContentInSlot;
3419
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<DsMobileModalBaseComponent, never>;
3420
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<DsMobileModalBaseComponent, "ds-mobile-modal-base", never, { "showHeader": { "alias": "showHeader"; "required": false; "isSignal": true; }; }, {}, ["customLoadingState", "customErrorState", "headerLeading", "headerMain"], ["[header-leading]", "[header-main]", "[loading-state]", "[error-state]", "*", "[fixed-bottom]", "[footer]"], true, never>;
3421
+ }
3422
+
2811
3423
  /**
2812
3424
  * Post data interface for the modal
2813
3425
  *
@@ -2929,13 +3541,14 @@ interface CommentData {
2929
3541
  * }
2930
3542
  * ```
2931
3543
  */
2932
- declare class DsMobilePostDetailModalComponent implements AfterViewInit, OnDestroy {
2933
- private modalController;
3544
+ declare class DsMobilePostDetailModalComponent implements OnInit, AfterViewInit {
2934
3545
  private lightbox;
2935
3546
  private bottomSheet;
2936
3547
  postData: PostDetailData;
2937
3548
  currentUserName: string;
2938
3549
  currentUserInitialsInput: string;
3550
+ loading: boolean;
3551
+ error: string | undefined;
2939
3552
  onSubmitComment?: (payload: {
2940
3553
  postId: string;
2941
3554
  text: string;
@@ -2951,16 +3564,6 @@ declare class DsMobilePostDetailModalComponent implements AfterViewInit, OnDestr
2951
3564
  onDeleteComment?: (payload: {
2952
3565
  commentId: string;
2953
3566
  }) => void;
2954
- /**
2955
- * Loading state - when true, shows loading indicator
2956
- * Set this to true while fetching post data from your API
2957
- */
2958
- loading: boolean;
2959
- /**
2960
- * Error state - when set, shows error message
2961
- * Set this to an error message string if API call fails
2962
- */
2963
- error?: string;
2964
3567
  commentInput?: ElementRef<HTMLTextAreaElement>;
2965
3568
  post: _angular_core.WritableSignal<PostDetailData>;
2966
3569
  commentText: _angular_core.WritableSignal<string>;
@@ -2987,19 +3590,9 @@ declare class DsMobilePostDetailModalComponent implements AfterViewInit, OnDestr
2987
3590
  initials: string;
2988
3591
  role: string;
2989
3592
  }[]>;
2990
- constructor(modalController: ModalController, lightbox: DsMobileLightboxService, bottomSheet: DsMobileBottomSheetService);
3593
+ constructor(lightbox: DsMobileLightboxService, bottomSheet: DsMobileBottomSheetService);
2991
3594
  ngOnInit(): void;
2992
3595
  ngAfterViewInit(): void;
2993
- ngOnDestroy(): void;
2994
- /**
2995
- * Set up keyboard event listeners to adjust composer position
2996
- * The CSS uses --keyboard-height variable to translate the composer up
2997
- */
2998
- private setupKeyboardListeners;
2999
- /**
3000
- * Clean up keyboard event listeners
3001
- */
3002
- private cleanupKeyboardListeners;
3003
3596
  /**
3004
3597
  * Show the keyboard when user interacts with input
3005
3598
  */
@@ -3041,10 +3634,6 @@ declare class DsMobilePostDetailModalComponent implements AfterViewInit, OnDestr
3041
3634
  active: boolean;
3042
3635
  count: number;
3043
3636
  }): void;
3044
- /**
3045
- * Close the modal
3046
- */
3047
- close(): void;
3048
3637
  /**
3049
3638
  * Submit a comment
3050
3639
  */
@@ -3058,7 +3647,83 @@ declare class DsMobilePostDetailModalComponent implements AfterViewInit, OnDestr
3058
3647
  */
3059
3648
  handleCommentLongPress(authorName: string, content: string, isOwnComment: boolean): Promise<void>;
3060
3649
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<DsMobilePostDetailModalComponent, never>;
3061
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<DsMobilePostDetailModalComponent, "ds-mobile-post-detail-modal", never, { "postData": { "alias": "postData"; "required": false; }; "currentUserName": { "alias": "currentUserName"; "required": false; }; "currentUserInitialsInput": { "alias": "currentUserInitialsInput"; "required": false; }; "onSubmitComment": { "alias": "onSubmitComment"; "required": false; }; "onToggleCommentLike": { "alias": "onToggleCommentLike"; "required": false; }; "onEditComment": { "alias": "onEditComment"; "required": false; }; "onDeleteComment": { "alias": "onDeleteComment"; "required": false; }; "loading": { "alias": "loading"; "required": false; }; "error": { "alias": "error"; "required": false; }; }, {}, never, never, true, never>;
3650
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<DsMobilePostDetailModalComponent, "ds-mobile-post-detail-modal", never, { "postData": { "alias": "postData"; "required": false; }; "currentUserName": { "alias": "currentUserName"; "required": false; }; "currentUserInitialsInput": { "alias": "currentUserInitialsInput"; "required": false; }; "loading": { "alias": "loading"; "required": false; }; "error": { "alias": "error"; "required": false; }; "onSubmitComment": { "alias": "onSubmitComment"; "required": false; }; "onToggleCommentLike": { "alias": "onToggleCommentLike"; "required": false; }; "onEditComment": { "alias": "onEditComment"; "required": false; }; "onDeleteComment": { "alias": "onDeleteComment"; "required": false; }; }, {}, never, never, true, never>;
3651
+ }
3652
+
3653
+ /**
3654
+ * BaseModalService
3655
+ *
3656
+ * Abstract base class for all modal services in the application.
3657
+ * Enforces consistent modal configuration and presentation across all modals.
3658
+ *
3659
+ * **Features:**
3660
+ * - Standardized modal presentation (stacked effect with gap at top)
3661
+ * - Consistent backdrop and dismissal behavior
3662
+ * - Automatic safe area handling
3663
+ * - Native iOS-style animations
3664
+ *
3665
+ * **Why use this:**
3666
+ * - Ensures all modals have the same look and feel
3667
+ * - Prevents inconsistencies in modal configuration
3668
+ * - Single source of truth for modal settings
3669
+ * - Makes it impossible to forget critical configuration
3670
+ *
3671
+ * @example
3672
+ * ```typescript
3673
+ * @Injectable({ providedIn: 'root' })
3674
+ * export class MyModalService extends BaseModalService {
3675
+ * async open(data: MyData) {
3676
+ * const modal = await this.createModal(
3677
+ * MyModalComponent,
3678
+ * { data }
3679
+ * );
3680
+ * await modal.present();
3681
+ * }
3682
+ * }
3683
+ * ```
3684
+ */
3685
+ declare abstract class BaseModalService {
3686
+ protected modalController: ModalController;
3687
+ constructor(modalController: ModalController);
3688
+ /**
3689
+ * Create a modal with standardized configuration
3690
+ *
3691
+ * This method enforces consistent modal behavior across the app:
3692
+ * - Uses 'ds-modal-base' CSS class for consistent styling
3693
+ * - iOS mode for native feel
3694
+ * - presentingElement for stacked modal effect
3695
+ * - Standard backdrop and dismissal settings
3696
+ *
3697
+ * @param component The component to display in the modal
3698
+ * @param componentProps Props to pass to the component
3699
+ * @param customOptions Optional overrides for specific modal needs
3700
+ * @returns Promise resolving to the created modal
3701
+ *
3702
+ * @example
3703
+ * ```typescript
3704
+ * const modal = await this.createModal(
3705
+ * PostDetailComponent,
3706
+ * { postId: '123', loading: false }
3707
+ * );
3708
+ * await modal.present();
3709
+ * ```
3710
+ */
3711
+ protected createModal<T>(component: Type<T>, componentProps?: Record<string, any>, customOptions?: Partial<ModalOptions$1>): Promise<HTMLIonModalElement>;
3712
+ /**
3713
+ * Close the currently open modal
3714
+ *
3715
+ * @param data Optional data to pass back when dismissing
3716
+ * @returns Promise that resolves when the modal is dismissed
3717
+ */
3718
+ close(data?: any): Promise<boolean>;
3719
+ /**
3720
+ * Get the top-most modal if one exists
3721
+ *
3722
+ * @returns Promise that resolves to the modal element or undefined
3723
+ */
3724
+ getTop(): Promise<HTMLIonModalElement | undefined>;
3725
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<BaseModalService, never>;
3726
+ static ɵprov: _angular_core.ɵɵInjectableDeclaration<BaseModalService>;
3062
3727
  }
3063
3728
 
3064
3729
  /**
@@ -3104,8 +3769,7 @@ declare class DsMobilePostDetailModalComponent implements AfterViewInit, OnDestr
3104
3769
  * }
3105
3770
  * ```
3106
3771
  */
3107
- declare class DsMobilePostDetailModalService {
3108
- private modalController;
3772
+ declare class DsMobilePostDetailModalService extends BaseModalService {
3109
3773
  constructor(modalController: ModalController);
3110
3774
  /**
3111
3775
  * Open the post detail modal
@@ -3135,19 +3799,6 @@ declare class DsMobilePostDetailModalService {
3135
3799
  currentUserName?: string;
3136
3800
  currentUserInitials?: string;
3137
3801
  }): Promise<void>;
3138
- /**
3139
- * Close the currently open post detail modal
3140
- *
3141
- * @param data Optional data to pass back when dismissing
3142
- * @returns Promise that resolves when the modal is dismissed
3143
- */
3144
- close(data?: any): Promise<boolean>;
3145
- /**
3146
- * Get the top-most modal if one exists
3147
- *
3148
- * @returns Promise that resolves to the modal element or undefined
3149
- */
3150
- getTop(): Promise<HTMLIonModalElement | undefined>;
3151
3802
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<DsMobilePostDetailModalService, never>;
3152
3803
  static ɵprov: _angular_core.ɵɵInjectableDeclaration<DsMobilePostDetailModalService>;
3153
3804
  }
@@ -3161,12 +3812,21 @@ interface ChatMessage {
3161
3812
  senderId: string;
3162
3813
  senderName: string;
3163
3814
  senderRole?: string;
3164
- timestamp: string;
3815
+ timestamp: Date;
3165
3816
  avatarInitials?: string;
3166
3817
  avatarType?: 'initials' | 'photo' | 'icon';
3167
3818
  avatarSrc?: string;
3168
3819
  isOwnMessage: boolean;
3169
3820
  attachments?: ChatAttachment[];
3821
+ fileAttachments?: AttachmentData[];
3822
+ }
3823
+ /**
3824
+ * Message group interface for grouped timestamp display
3825
+ */
3826
+ interface MessageGroup {
3827
+ timestamp: Date;
3828
+ displayTimestamp: string;
3829
+ messages: ChatMessage[];
3170
3830
  }
3171
3831
  /**
3172
3832
  * Chat participant interface
@@ -3184,27 +3844,58 @@ interface ChatParticipant {
3184
3844
  *
3185
3845
  * Represents the data needed to display a chat conversation.
3186
3846
  *
3187
- * @example
3847
+ * @example
3188
3848
  * ```typescript
3189
3849
  * const chatData: ChatModalData = {
3190
3850
  * participant: {
3191
- * id: '123',
3851
+ * id: 'u-123',
3192
3852
  * name: 'Ricki Meihlen',
3193
3853
  * role: 'Inquiry assignee',
3194
- * avatarInitials: 'RM'
3854
+ * avatarInitials: 'RM',
3855
+ * avatarType: 'initials'
3195
3856
  * },
3857
+ * currentUserId: 'u-456',
3858
+ * currentUserInitials: 'SD',
3859
+ * currentUserAvatarType: 'initials',
3860
+ * autoFocus: true,
3196
3861
  * messages: [
3197
3862
  * {
3198
- * id: '1',
3199
- * content: 'We have received your case...',
3200
- * senderId: '123',
3863
+ * id: 'm-1',
3864
+ * content: 'We have received your case. Please see the attached photo.',
3865
+ * senderId: 'u-123',
3201
3866
  * senderName: 'Ricki Meihlen',
3867
+ * senderRole: 'Case worker',
3202
3868
  * timestamp: '12:34',
3203
3869
  * isOwnMessage: false,
3204
- * avatarInitials: 'RM'
3870
+ * avatarInitials: 'RM',
3871
+ * avatarType: 'initials',
3872
+ * attachments: [
3873
+ * {
3874
+ * id: 'a-1',
3875
+ * type: 'image',
3876
+ * url: 'https://example.com/photo.jpg',
3877
+ * name: 'photo.jpg',
3878
+ * thumbnail: 'https://example.com/photo_thumb.jpg'
3879
+ * },
3880
+ * {
3881
+ * id: 'a-2',
3882
+ * type: 'pdf',
3883
+ * url: 'https://example.com/report.pdf',
3884
+ * name: 'report.pdf'
3885
+ * }
3886
+ * ]
3887
+ * },
3888
+ * {
3889
+ * id: 'm-2',
3890
+ * content: 'Thanks — I will take a look.',
3891
+ * senderId: 'u-456',
3892
+ * senderName: 'You',
3893
+ * timestamp: '12:36',
3894
+ * isOwnMessage: true,
3895
+ * avatarInitials: 'SD',
3896
+ * avatarType: 'initials'
3205
3897
  * }
3206
- * ],
3207
- * currentUserId: '456'
3898
+ * ]
3208
3899
  * };
3209
3900
  * ```
3210
3901
  */
@@ -3253,9 +3944,8 @@ interface ChatModalData {
3253
3944
  * }
3254
3945
  * ```
3255
3946
  */
3256
- declare class DsMobileChatModalComponent implements OnInit, AfterViewInit, OnDestroy {
3257
- private modalController;
3258
- private lightbox;
3947
+ declare class DsMobileChatModalComponent implements OnInit, AfterViewInit {
3948
+ private lightboxService;
3259
3949
  chatData: ChatModalData;
3260
3950
  /**
3261
3951
  * Loading state - when true, shows loading indicator
@@ -3271,18 +3961,25 @@ declare class DsMobileChatModalComponent implements OnInit, AfterViewInit, OnDes
3271
3961
  currentUserAvatarType: _angular_core.WritableSignal<"initials" | "photo" | "icon">;
3272
3962
  currentUserAvatarSrc: _angular_core.WritableSignal<string>;
3273
3963
  autoFocus: _angular_core.WritableSignal<boolean>;
3274
- constructor(modalController: ModalController, lightbox: DsMobileLightboxService);
3964
+ /**
3965
+ * Selected message ID for showing timestamp
3966
+ */
3967
+ selectedMessageId: _angular_core.WritableSignal<string | null>;
3968
+ /**
3969
+ * Timeout for auto-hiding timestamp
3970
+ */
3971
+ private timestampTimeout?;
3972
+ /**
3973
+ * Computed signal for grouped messages with timestamp headers
3974
+ */
3975
+ messageGroups: _angular_core.Signal<MessageGroup[]>;
3976
+ constructor(lightboxService: DsMobileLightboxService);
3275
3977
  ngOnInit(): void;
3276
3978
  ngAfterViewInit(): void;
3277
- ngOnDestroy(): void;
3278
3979
  /**
3279
3980
  * Scroll to bottom of messages
3280
3981
  */
3281
3982
  private scrollToBottom;
3282
- /**
3283
- * Close the modal
3284
- */
3285
- close(): void;
3286
3983
  /**
3287
3984
  * Handle message sent from composer
3288
3985
  */
@@ -3291,15 +3988,54 @@ declare class DsMobileChatModalComponent implements OnInit, AfterViewInit, OnDes
3291
3988
  isReply?: boolean;
3292
3989
  replyTo?: string;
3293
3990
  isEdit?: boolean;
3991
+ attachments?: AttachmentData[];
3294
3992
  }): void;
3295
3993
  /**
3296
3994
  * Handle attachment click
3297
3995
  */
3298
3996
  handleAttachmentClick(attachment: ChatAttachment): void;
3997
+ /**
3998
+ * Handle composer attachment button click
3999
+ */
4000
+ handleComposerAttachmentClick(): void;
4001
+ /**
4002
+ * Get file variant for card-inline-file component
4003
+ */
4004
+ getFileVariant(type: string): 'pdf' | 'doc';
4005
+ /**
4006
+ * Handle file attachment click
4007
+ */
4008
+ handleFileAttachmentClick(fileAttachment: AttachmentData): void;
4009
+ /**
4010
+ * Handle image attachment click - opens lightbox
4011
+ */
4012
+ handleImageClick(attachment: AttachmentData, message: ChatMessage): Promise<void>;
3299
4013
  /**
3300
4014
  * Handle message long press
3301
4015
  */
3302
4016
  handleMessageLongPress(message: ChatMessage): void;
4017
+ /**
4018
+ * Handle message click to show/hide timestamp
4019
+ */
4020
+ handleMessageClick(messageId: string): void;
4021
+ /**
4022
+ * Format message timestamp for display (EU 24-hour format, Danish)
4023
+ */
4024
+ formatMessageTimestamp(date: Date): string;
4025
+ /**
4026
+ * Group messages by time threshold
4027
+ * Messages within the threshold and on the same day are grouped together
4028
+ */
4029
+ private groupMessagesByTime;
4030
+ /**
4031
+ * Determine if a new message group should be started
4032
+ */
4033
+ private shouldStartNewGroup;
4034
+ /**
4035
+ * Format group timestamp header with smart date display
4036
+ * Uses 24-hour EU time format with Danish locale
4037
+ */
4038
+ private formatGroupTimestamp;
3303
4039
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<DsMobileChatModalComponent, never>;
3304
4040
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<DsMobileChatModalComponent, "ds-mobile-chat-modal", never, { "chatData": { "alias": "chatData"; "required": false; }; "loading": { "alias": "loading"; "required": false; }; "error": { "alias": "error"; "required": false; }; }, {}, never, never, true, never>;
3305
4041
  }
@@ -3359,8 +4095,7 @@ declare class DsMobileChatModalComponent implements OnInit, AfterViewInit, OnDes
3359
4095
  * }
3360
4096
  * ```
3361
4097
  */
3362
- declare class DsMobileChatModalService {
3363
- private modalController;
4098
+ declare class DsMobileChatModalService extends BaseModalService {
3364
4099
  constructor(modalController: ModalController);
3365
4100
  /**
3366
4101
  * Open the chat modal
@@ -3373,21 +4108,190 @@ declare class DsMobileChatModalService {
3373
4108
  loading?: boolean;
3374
4109
  error?: string;
3375
4110
  }): Promise<void>;
4111
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<DsMobileChatModalService, never>;
4112
+ static ɵprov: _angular_core.ɵɵInjectableDeclaration<DsMobileChatModalService>;
4113
+ }
4114
+
4115
+ /**
4116
+ * Photo interface for inquiry (deprecated - use AttachmentData)
4117
+ * @deprecated Use AttachmentData from attachment-preview component instead
4118
+ */
4119
+ interface InquiryPhoto {
4120
+ id: string;
4121
+ src: string;
4122
+ alt?: string;
4123
+ }
4124
+ /**
4125
+ * New inquiry form data
4126
+ */
4127
+ interface NewInquiryData {
4128
+ title: string;
4129
+ description: string;
4130
+ attachments: AttachmentData[];
4131
+ category?: string;
4132
+ }
4133
+ /**
4134
+ * DsMobileNewInquiryModalComponent
4135
+ *
4136
+ * Modal component for creating new inquiries.
4137
+ * Uses ds-mobile-modal-base for consistent layout and behavior.
4138
+ *
4139
+ * Features:
4140
+ * - Title and description fields
4141
+ * - Photo upload with preview
4142
+ * - Submit button at bottom
4143
+ * - Form validation
4144
+ * - Camera/photo picker integration
4145
+ *
4146
+ * This component is typically not used directly - use DsMobileNewInquiryModalService instead.
4147
+ *
4148
+ * @example
4149
+ * ```typescript
4150
+ * // Don't instantiate directly - use the service:
4151
+ * constructor(private inquiryModal: DsMobileNewInquiryModalService) {}
4152
+ *
4153
+ * createInquiry() {
4154
+ * this.inquiryModal.open({
4155
+ * onSubmit: (data) => console.log('Inquiry created:', data)
4156
+ * });
4157
+ * }
4158
+ * ```
4159
+ */
4160
+ declare class DsMobileNewInquiryModalComponent implements OnInit, AfterViewInit {
4161
+ titleInputRef?: ElementRef<HTMLElement>;
4162
+ titleInput?: DsTextareaComponent;
4163
+ fileInput?: ElementRef<HTMLInputElement>;
3376
4164
  /**
3377
- * Close the currently open chat modal
3378
- *
3379
- * @param data Optional data to pass back when dismissing
3380
- * @returns Promise that resolves when the modal is dismissed
4165
+ * Loading state for the modal
3381
4166
  */
3382
- close(data?: any): Promise<boolean>;
4167
+ loading: boolean;
3383
4168
  /**
3384
- * Get the top-most modal if one exists
4169
+ * Error message to display
4170
+ */
4171
+ error?: string;
4172
+ /**
4173
+ * Callback function when form is submitted
4174
+ */
4175
+ onSubmit?: (data: NewInquiryData) => void | Promise<void>;
4176
+ /**
4177
+ * Form title field
4178
+ */
4179
+ title: string;
4180
+ /**
4181
+ * Form description field
4182
+ */
4183
+ description: string;
4184
+ /**
4185
+ * Attachments array (replaces photos)
4186
+ */
4187
+ attachments: _angular_core.WritableSignal<AttachmentData[]>;
4188
+ /**
4189
+ * Form validation state
4190
+ */
4191
+ isFormValid: _angular_core.WritableSignal<boolean>;
4192
+ /**
4193
+ * Submitting state
4194
+ */
4195
+ isSubmitting: _angular_core.WritableSignal<boolean>;
4196
+ ngOnInit(): void;
4197
+ ngAfterViewInit(): void;
4198
+ /**
4199
+ * Auto-resize the title textarea based on content
4200
+ */
4201
+ private autoResizeTitleTextarea;
4202
+ /**
4203
+ * Handle title change with auto-resize
4204
+ */
4205
+ handleTitleChange(value: string): void;
4206
+ /**
4207
+ * Validate form fields
4208
+ */
4209
+ validateForm(): void;
4210
+ /**
4211
+ * Add a new photo from camera/library
4212
+ */
4213
+ addPhoto(): Promise<void>;
4214
+ /**
4215
+ * Remove an attachment
4216
+ */
4217
+ removeAttachment(attachmentId: string): void;
4218
+ /**
4219
+ * Handle attachment button click
4220
+ */
4221
+ handleAddAttachment(): void;
4222
+ /**
4223
+ * Detect file type from file name or mime type
4224
+ */
4225
+ private detectFileType;
4226
+ /**
4227
+ * Format file size for display
4228
+ */
4229
+ private formatFileSize;
4230
+ /**
4231
+ * Handle file selection from file input
4232
+ */
4233
+ handleFileSelect(event: Event): void;
4234
+ /**
4235
+ * Handle form submission
4236
+ */
4237
+ handleSubmit(): Promise<void>;
4238
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<DsMobileNewInquiryModalComponent, never>;
4239
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<DsMobileNewInquiryModalComponent, "ds-mobile-new-inquiry-modal", never, { "loading": { "alias": "loading"; "required": false; }; "error": { "alias": "error"; "required": false; }; "onSubmit": { "alias": "onSubmit"; "required": false; }; }, {}, never, never, true, never>;
4240
+ }
4241
+
4242
+ /**
4243
+ * Options for opening the new inquiry modal
4244
+ */
4245
+ interface NewInquiryModalOptions {
4246
+ /** Callback function when inquiry is submitted */
4247
+ onSubmit?: (data: NewInquiryData) => void | Promise<void>;
4248
+ /** Initial loading state */
4249
+ loading?: boolean;
4250
+ /** Initial error message */
4251
+ error?: string;
4252
+ }
4253
+ /**
4254
+ * DsMobileNewInquiryModalService
4255
+ *
4256
+ * Service for displaying the new inquiry creation modal.
4257
+ * Built on Ionic's modal system with native gestures and animations.
4258
+ *
4259
+ * Features:
4260
+ * - Full-screen modal with form
4261
+ * - Title and description inputs
4262
+ * - Photo upload with camera/gallery
4263
+ * - Form validation
4264
+ * - Submit handling
4265
+ * - Loading and error states
4266
+ *
4267
+ * @example
4268
+ * ```typescript
4269
+ * constructor(private inquiryModal: DsMobileNewInquiryModalService) {}
4270
+ *
4271
+ * async createNewInquiry() {
4272
+ * await this.inquiryModal.open({
4273
+ * onSubmit: async (data) => {
4274
+ * console.log('Creating inquiry:', data);
4275
+ * // Call your API to create the inquiry
4276
+ * await this.apiService.createInquiry(data);
4277
+ * // Close the modal
4278
+ * await this.inquiryModal.close();
4279
+ * }
4280
+ * });
4281
+ * }
4282
+ * ```
4283
+ */
4284
+ declare class DsMobileNewInquiryModalService extends BaseModalService {
4285
+ constructor(modalController: ModalController);
4286
+ /**
4287
+ * Open the new inquiry modal
3385
4288
  *
3386
- * @returns Promise that resolves to the modal element or undefined
4289
+ * @param options Modal options including onSubmit callback
4290
+ * @returns Promise that resolves when the modal is presented
3387
4291
  */
3388
- getTop(): Promise<HTMLIonModalElement | undefined>;
3389
- static ɵfac: _angular_core.ɵɵFactoryDeclaration<DsMobileChatModalService, never>;
3390
- static ɵprov: _angular_core.ɵɵInjectableDeclaration<DsMobileChatModalService>;
4292
+ open(options?: NewInquiryModalOptions): Promise<void>;
4293
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<DsMobileNewInquiryModalService, never>;
4294
+ static ɵprov: _angular_core.ɵɵInjectableDeclaration<DsMobileNewInquiryModalService>;
3391
4295
  }
3392
4296
 
3393
4297
  /**
@@ -3513,8 +4417,7 @@ interface ContactItem {
3513
4417
  *
3514
4418
  * This component is typically not used directly - use DsMobileHandbookDetailModalService instead.
3515
4419
  */
3516
- declare class DsMobileHandbookDetailModalComponent {
3517
- private modalController;
4420
+ declare class DsMobileHandbookDetailModalComponent implements OnInit {
3518
4421
  handbookData: HandbookDetailData;
3519
4422
  /**
3520
4423
  * Loading state - when true, shows loading indicator
@@ -3525,7 +4428,6 @@ declare class DsMobileHandbookDetailModalComponent {
3525
4428
  */
3526
4429
  error?: string;
3527
4430
  handbook: _angular_core.WritableSignal<HandbookDetailData>;
3528
- constructor(modalController: ModalController);
3529
4431
  ngOnInit(): void;
3530
4432
  /**
3531
4433
  * Split handbook items to enforce content structure rules:
@@ -3540,10 +4442,6 @@ declare class DsMobileHandbookDetailModalComponent {
3540
4442
  * Get all display items with enforced content structure rules applied
3541
4443
  */
3542
4444
  getDisplayItems(): HandbookItem[];
3543
- /**
3544
- * Close the modal
3545
- */
3546
- close(): void;
3547
4445
  /**
3548
4446
  * Handle contact click
3549
4447
  */
@@ -3594,8 +4492,7 @@ declare class DsMobileHandbookDetailModalComponent {
3594
4492
  * }
3595
4493
  * ```
3596
4494
  */
3597
- declare class DsMobileHandbookDetailModalService {
3598
- private modalController;
4495
+ declare class DsMobileHandbookDetailModalService extends BaseModalService {
3599
4496
  constructor(modalController: ModalController);
3600
4497
  /**
3601
4498
  * Open the handbook detail modal
@@ -3608,19 +4505,6 @@ declare class DsMobileHandbookDetailModalService {
3608
4505
  loading?: boolean;
3609
4506
  error?: string;
3610
4507
  }): Promise<void>;
3611
- /**
3612
- * Close the currently open handbook detail modal
3613
- *
3614
- * @param data Optional data to pass back when dismissing
3615
- * @returns Promise that resolves when the modal is dismissed
3616
- */
3617
- close(data?: any): Promise<boolean>;
3618
- /**
3619
- * Get the top-most modal if one exists
3620
- *
3621
- * @returns Promise that resolves to the modal element or undefined
3622
- */
3623
- getTop(): Promise<HTMLIonModalElement | undefined>;
3624
4508
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<DsMobileHandbookDetailModalService, never>;
3625
4509
  static ɵprov: _angular_core.ɵɵInjectableDeclaration<DsMobileHandbookDetailModalService>;
3626
4510
  }
@@ -3815,7 +4699,7 @@ declare class DsTextInputComponent implements ControlValueAccessor {
3815
4699
  hasError: _angular_core.InputSignal<boolean>;
3816
4700
  errorMessage: _angular_core.InputSignal<string>;
3817
4701
  autocomplete: _angular_core.InputSignal<string>;
3818
- inputmode: _angular_core.InputSignal<"search" | "text" | "numeric" | "url" | "email" | "tel" | undefined>;
4702
+ inputmode: _angular_core.InputSignal<"search" | "text" | "url" | "numeric" | "email" | "tel" | undefined>;
3819
4703
  autoClearError: _angular_core.InputSignal<boolean>;
3820
4704
  validator: _angular_core.InputSignal<((value: string) => boolean) | null>;
3821
4705
  valueChange: _angular_core.OutputEmitterRef<string>;
@@ -3842,6 +4726,68 @@ declare class DsTextInputComponent implements ControlValueAccessor {
3842
4726
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<DsTextInputComponent, "ds-text-input", never, { "type": { "alias": "type"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "readonly": { "alias": "readonly"; "required": false; "isSignal": true; }; "required": { "alias": "required"; "required": false; "isSignal": true; }; "hasError": { "alias": "hasError"; "required": false; "isSignal": true; }; "errorMessage": { "alias": "errorMessage"; "required": false; "isSignal": true; }; "autocomplete": { "alias": "autocomplete"; "required": false; "isSignal": true; }; "inputmode": { "alias": "inputmode"; "required": false; "isSignal": true; }; "autoClearError": { "alias": "autoClearError"; "required": false; "isSignal": true; }; "validator": { "alias": "validator"; "required": false; "isSignal": true; }; }, { "valueChange": "valueChange"; "blur": "blur"; "focus": "focus"; "errorCleared": "errorCleared"; }, never, never, true, never>;
3843
4727
  }
3844
4728
 
4729
+ /**
4730
+ * DsMobileFabComponent
4731
+ *
4732
+ * Floating Action Button component for mobile interfaces.
4733
+ * A prominent circular button that floats above the content.
4734
+ *
4735
+ * Features:
4736
+ * - Configurable positioning (bottom-right, bottom-left, bottom-center)
4737
+ * - Uses design system theming variables
4738
+ * - Handles iOS safe areas
4739
+ * - Accessible with ARIA labels
4740
+ * - Smooth entrance animation
4741
+ *
4742
+ * @example
4743
+ * ```html
4744
+ * <ds-mobile-fab
4745
+ * icon="remixAddLine"
4746
+ * [position]="'bottom-right'"
4747
+ * (fabClick)="handleAddClick()"
4748
+ * ariaLabel="Add new inquiry">
4749
+ * </ds-mobile-fab>
4750
+ * ```
4751
+ */
4752
+ declare class DsMobileFabComponent {
4753
+ /**
4754
+ * Icon name from the design system icon library
4755
+ * @default 'remixAddLine'
4756
+ */
4757
+ icon: _angular_core.InputSignal<string>;
4758
+ /**
4759
+ * Position of the FAB on the screen
4760
+ * @default 'bottom-right'
4761
+ */
4762
+ position: _angular_core.InputSignal<"bottom-right" | "bottom-left" | "bottom-center">;
4763
+ /**
4764
+ * Size of the FAB button
4765
+ * Note: FAB is always 56px circular, but this affects the icon size
4766
+ * @default 'md'
4767
+ */
4768
+ size: _angular_core.InputSignal<"sm" | "md" | "lg">;
4769
+ /**
4770
+ * ARIA label for accessibility
4771
+ * @required - Always provide a descriptive label
4772
+ */
4773
+ ariaLabel: _angular_core.InputSignal<string>;
4774
+ /**
4775
+ * Whether the FAB is disabled
4776
+ * @default false
4777
+ */
4778
+ disabled: _angular_core.InputSignal<boolean>;
4779
+ /**
4780
+ * Emitted when the FAB is clicked
4781
+ */
4782
+ fabClick: _angular_core.OutputEmitterRef<void>;
4783
+ /**
4784
+ * Handle button click
4785
+ */
4786
+ handleClick(): void;
4787
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<DsMobileFabComponent, never>;
4788
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<DsMobileFabComponent, "ds-mobile-fab", never, { "icon": { "alias": "icon"; "required": false; "isSignal": true; }; "position": { "alias": "position"; "required": false; "isSignal": true; }; "size": { "alias": "size"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "ariaLabel"; "required": true; "isSignal": true; }; "disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; }, { "fabClick": "fabClick"; }, never, never, true, never>;
4789
+ }
4790
+
3845
4791
  interface WhitelabelConfig {
3846
4792
  logoUrl: string;
3847
4793
  logoMarkUrl: string;
@@ -4004,6 +4950,105 @@ declare class UserService {
4004
4950
  static ɵprov: _angular_core.ɵɵInjectableDeclaration<UserService>;
4005
4951
  }
4006
4952
 
4953
+ /**
4954
+ * Post and Comment Models
4955
+ * Unified data structures for community posts
4956
+ */
4957
+ interface Comment {
4958
+ authorName: string;
4959
+ authorRole: string;
4960
+ timestamp: string;
4961
+ avatarInitials: string;
4962
+ avatarSrc?: string;
4963
+ avatarType?: 'photo' | 'initials' | 'icon';
4964
+ content: string;
4965
+ likeCount: number;
4966
+ isLiked?: boolean;
4967
+ isOwnComment: boolean;
4968
+ }
4969
+ interface Post {
4970
+ id: string;
4971
+ authorName: string;
4972
+ authorRole: string;
4973
+ timestamp: string;
4974
+ avatarType: 'photo' | 'initials' | 'icon';
4975
+ avatarSrc?: string;
4976
+ avatarInitials?: string;
4977
+ avatarIconName?: string;
4978
+ content: string;
4979
+ imageSrc?: string;
4980
+ imageAlt?: string;
4981
+ isLiked: boolean;
4982
+ likeCount: number;
4983
+ commentCount: number;
4984
+ comments?: Comment[];
4985
+ isPinned?: boolean;
4986
+ showBadge?: boolean;
4987
+ hasInlinePhotos?: boolean;
4988
+ inlinePhotos?: string[];
4989
+ inlinePhotoCount?: number;
4990
+ }
4991
+
4992
+ /**
4993
+ * PostsService
4994
+ *
4995
+ * Centralized service for managing community posts.
4996
+ * Provides a single source of truth for post data, including comments.
4997
+ *
4998
+ * Features:
4999
+ * - CRUD operations for posts
5000
+ * - Infinite scroll pagination
5001
+ * - Post search/filter (future)
5002
+ * - Comment management (future)
5003
+ */
5004
+ declare class PostsService {
5005
+ private postsState;
5006
+ posts: _angular_core.Signal<Post[]>;
5007
+ private currentPage;
5008
+ private hasMore;
5009
+ constructor();
5010
+ /**
5011
+ * Get a post by ID
5012
+ */
5013
+ getPostById(id: string): Post | undefined;
5014
+ /**
5015
+ * Add a new post (e.g., from post creator)
5016
+ * Adds to the beginning of the list
5017
+ */
5018
+ addPost(post: Post): void;
5019
+ /**
5020
+ * Update an existing post
5021
+ */
5022
+ updatePost(id: string, updates: Partial<Post>): void;
5023
+ /**
5024
+ * Delete a post by ID
5025
+ */
5026
+ deletePost(id: string): void;
5027
+ /**
5028
+ * Load more posts for infinite scroll
5029
+ * Returns true if more posts were loaded, false if no more posts
5030
+ */
5031
+ loadMorePosts(): Promise<boolean>;
5032
+ /**
5033
+ * Check if there are more posts to load
5034
+ */
5035
+ hasMorePosts(): boolean;
5036
+ /**
5037
+ * Reset pagination (e.g., on pull-to-refresh)
5038
+ */
5039
+ resetPagination(): void;
5040
+ /**
5041
+ * Get initial posts (shown on page load)
5042
+ */
5043
+ private getInitialPosts;
5044
+ /**
5045
+ * Get additional posts for infinite scroll
5046
+ */
5047
+ private getAdditionalPosts;
5048
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<PostsService, never>;
5049
+ static ɵprov: _angular_core.ɵɵInjectableDeclaration<PostsService>;
5050
+ }
5051
+
4007
5052
  declare class MobileCommunityPageComponent {
4008
5053
  private router;
4009
5054
  private route;
@@ -4011,23 +5056,22 @@ declare class MobileCommunityPageComponent {
4011
5056
  private lightbox;
4012
5057
  private postModal;
4013
5058
  userService: UserService;
4014
- userPosts: _angular_core.WritableSignal<any[]>;
4015
- showStaticPosts: _angular_core.WritableSignal<boolean>;
5059
+ private postsService;
5060
+ allPosts: _angular_core.Signal<Post[]>;
4016
5061
  hasAnyPosts: _angular_core.Signal<boolean>;
4017
- constructor(router: Router, route: ActivatedRoute, bottomSheet: DsMobileBottomSheetService, lightbox: DsMobileLightboxService, postModal: DsMobilePostDetailModalService, userService: UserService);
5062
+ hasMorePosts: _angular_core.Signal<boolean>;
5063
+ constructor(router: Router, route: ActivatedRoute, bottomSheet: DsMobileBottomSheetService, lightbox: DsMobileLightboxService, postModal: DsMobilePostDetailModalService, userService: UserService, postsService: PostsService);
5064
+ /**
5065
+ * Handle infinite scroll event
5066
+ * Loads more posts when user scrolls to bottom
5067
+ */
5068
+ onInfiniteScroll(event: any): Promise<void>;
4018
5069
  handleRefresh(event: any): void;
4019
5070
  /**
4020
5071
  * Open post detail modal
4021
- * This provides a better UX than route navigation:
4022
- * - Maintains scroll position
4023
- * - Native iOS-style modal feel
4024
- * - Proper close button that works
5072
+ * Gets post data from service and opens modal
4025
5073
  */
4026
5074
  openPost(postId: string, focusComment?: boolean): Promise<void>;
4027
- /**
4028
- * Open user-created post detail modal
4029
- */
4030
- openUserPost(index: number, focusComment?: boolean): Promise<void>;
4031
5075
  openPostCreator(): Promise<void>;
4032
5076
  /**
4033
5077
  * Open an image in the lightbox viewer
@@ -4038,7 +5082,7 @@ declare class MobileCommunityPageComponent {
4038
5082
  /**
4039
5083
  * Handle long press on a post to show action sheet
4040
5084
  */
4041
- handlePostLongPress(postIdOrIndex: string | number, isOwnPost: boolean): Promise<void>;
5085
+ handlePostLongPress(postId: string, isOwnPost: boolean): Promise<void>;
4042
5086
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<MobileCommunityPageComponent, never>;
4043
5087
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<MobileCommunityPageComponent, "app-mobile-community-page", never, {}, {}, never, never, true, never>;
4044
5088
  }
@@ -4076,7 +5120,8 @@ interface Inquiry {
4076
5120
  declare class MobileInquiriesPageComponent {
4077
5121
  userService: UserService;
4078
5122
  private navCtrl;
4079
- constructor(userService: UserService, navCtrl: NavController);
5123
+ private newInquiryModal;
5124
+ constructor(userService: UserService, navCtrl: NavController, newInquiryModal: DsMobileNewInquiryModalService);
4080
5125
  filterStatus: _angular_core.WritableSignal<"open" | "closed" | "all">;
4081
5126
  tabItems: InlineTabItem[];
4082
5127
  inquiries: _angular_core.WritableSignal<Inquiry[]>;
@@ -4087,22 +5132,11 @@ declare class MobileInquiriesPageComponent {
4087
5132
  getInquiryIcon(category: string): string;
4088
5133
  openInquiryDetail(inquiryId: string): void;
4089
5134
  showInquiryActions(inquiryId: string): void;
5135
+ createNewInquiry(): Promise<void>;
4090
5136
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<MobileInquiriesPageComponent, never>;
4091
5137
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<MobileInquiriesPageComponent, "app-mobile-inquiries-page", never, {}, {}, never, never, true, never>;
4092
5138
  }
4093
5139
 
4094
- interface ActivityItem {
4095
- id: string;
4096
- type: 'assignment' | 'status_change' | 'creation';
4097
- actor?: string;
4098
- actorInitials?: string;
4099
- title: string;
4100
- description?: string;
4101
- timestamp: string;
4102
- date: string;
4103
- iconName: string;
4104
- iconBgColor?: string;
4105
- }
4106
5140
  interface MessageThread {
4107
5141
  id: string;
4108
5142
  senderName: string;
@@ -4113,28 +5147,28 @@ interface MessageThread {
4113
5147
  timestamp: string;
4114
5148
  unread: boolean;
4115
5149
  }
4116
- declare class MobileInquiryDetailPageComponent extends MobilePageBase implements AfterViewInit {
5150
+ declare class MobileInquiryDetailPageComponent {
4117
5151
  userService: UserService;
4118
- private navCtrl;
4119
- private elementRef;
4120
5152
  private lightbox;
4121
5153
  private chatModal;
4122
- ionContent?: IonContent;
4123
- private platform;
4124
- isNativePlatform: _angular_core.Signal<boolean>;
4125
5154
  inquiryTitle: string;
4126
5155
  activeTab: _angular_core.WritableSignal<string>;
4127
5156
  tabItems: InlineTabItem[];
4128
- activities: ActivityItem[];
4129
5157
  messageThreads: MessageThread[];
4130
5158
  unreadMessagesCount: _angular_core.Signal<number>;
4131
5159
  photos: LightboxImage[];
4132
- constructor(userService: UserService, navCtrl: NavController, elementRef: ElementRef, lightbox: DsMobileLightboxService, chatModal: DsMobileChatModalService);
4133
- ngAfterViewInit(): void;
5160
+ constructor(userService: UserService, lightbox: DsMobileLightboxService, chatModal: DsMobileChatModalService);
4134
5161
  setActiveTab(tabId: string): void;
4135
5162
  goBack(): void;
4136
- handleScroll(event: any): void;
4137
5163
  handleRefresh(event: any): void;
5164
+ /**
5165
+ * Check if there are unread messages
5166
+ */
5167
+ hasUnreadMessages(): boolean;
5168
+ /**
5169
+ * Navigate to messages tab when banner is clicked
5170
+ */
5171
+ navigateToMessagesTab(): void;
4138
5172
  openMessage(messageId: string): Promise<void>;
4139
5173
  openPhotoLightbox(index: number): Promise<void>;
4140
5174
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<MobileInquiryDetailPageComponent, never>;
@@ -4222,6 +5256,23 @@ declare class MobilePostDetailPageComponent {
4222
5256
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<MobilePostDetailPageComponent, "app-mobile-post-detail-page", never, {}, {}, never, never, true, never>;
4223
5257
  }
4224
5258
 
5259
+ /**
5260
+ * SignInPageComponent
5261
+ *
5262
+ * Sign-in page with email authentication.
5263
+ * Features logomark, decorative city background, and form validation.
5264
+ */
5265
+ declare class SignInPageComponent {
5266
+ email: string;
5267
+ emailError: _angular_core.WritableSignal<boolean>;
5268
+ isSubmitting: _angular_core.WritableSignal<boolean>;
5269
+ emailSent: _angular_core.WritableSignal<boolean>;
5270
+ handleSubmit(): void;
5271
+ handleBackToLogin(): void;
5272
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<SignInPageComponent, never>;
5273
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<SignInPageComponent, "app-sign-in", never, {}, {}, never, never, true, never>;
5274
+ }
5275
+
4225
5276
  /**
4226
5277
  * Whitelabel Demo Page
4227
5278
  *
@@ -4247,23 +5298,26 @@ declare class WhitelabelDemoPage implements OnInit {
4247
5298
  }
4248
5299
 
4249
5300
  /**
4250
- * Custom page transition - iOS-style push/pop
5301
+ * Custom page transition - iOS-style push/pop with dark overlay
4251
5302
  *
4252
5303
  * FORWARD (navigating TO detail):
4253
5304
  * - Entering page (detail): slides in from RIGHT, z-index 10 (on top)
4254
5305
  * - Leaving page (list): slides LEFT slightly, z-index 9 (underneath)
5306
+ * - Dark overlay: fades in on leaving page (opacity 0 to 0.70)
4255
5307
  *
4256
5308
  * REVERSE (swipe back FROM detail):
4257
5309
  * - Entering page (list): slides in from LEFT, z-index 9 (underneath)
4258
5310
  * - Leaving page (detail): slides out to RIGHT, z-index 10 (on top)
5311
+ * - Dark overlay: fades out on entering page (main page underneath, opacity 0.70 to 0)
4259
5312
  */
4260
5313
  declare const customPageTransition: (_: HTMLElement, opts: any) => Animation;
4261
5314
  /**
4262
5315
  * Custom back transition - iOS style where page slides out to reveal page underneath
4263
5316
  * The entering page (inquiries) slides in from the LEFT underneath
4264
5317
  * The leaving page (detail) slides out to the RIGHT on top
5318
+ * Dark overlay: fades out on entering page (main page underneath, opacity 0.70 to 0)
4265
5319
  */
4266
5320
  declare const customBackTransition: (_: HTMLElement, opts: any) => Animation;
4267
5321
 
4268
- export { ActionCommentComponent, ActionLikeComponent, ContentRowComponent, DsAvatarWithBadgeComponent, DsMobileActionsBottomSheetComponent, DsMobileBottomSheetService, DsMobileChatModalComponent, DsMobileChatModalService, DsMobileActionsBottomSheetComponent as DsMobileCommentActionsBottomSheetComponent, DsMobileCommentComponent, DsMobileContactListItemComponent, DsMobileContentComponent, DsMobileContentSectionComponent, DsMobileHandbookDetailModalComponent, DsMobileHandbookDetailModalService, DsMobileHandbookFolderComponent, DsMobileHandbookFolderMiniComponent, DsMobileHeaderContentComponent, DsMobileHeaderContentTileComponent, DsMobileInlinePhotoComponent, DsMobileInlineTabsComponent, DsMobileInteractiveListItemInquiryComponent, DsMobileInteractiveListItemMessageComponent, DsMobileInteractiveListItemPostComponent, DsMobileLightboxImageComponent as DsMobileLightboxComponent, DsMobileLightboxFooterComponent, DsMobileLightboxHeaderComponent, DsMobileLightboxImageComponent, DsMobileLightboxPdfComponent, DsMobileLightboxService, DsMobileListItemComponent, DsMobileListItemStaticComponent, DsMobileLongPressDirective, DsMobileMessageBubbleComponent, DsMobileMessageComposerComponent, DsMobileModalService, DsMobilePageDetailsComponent, DsMobilePageMainComponent, DsMobileActionsBottomSheetComponent as DsMobilePostActionsBottomSheetComponent, DsMobilePostComposerComponent, DsMobilePostCreateBottomSheetComponent, DsMobilePostDetailModalComponent, DsMobilePostDetailModalService, DsMobileTabBarComponent, DsMobileTabsComponent, DsTextInputComponent, MobileCommunityPageComponent, MobileHandbookPageComponent, MobileHomePageComponent, MobileInquiriesPageComponent, MobileInquiryDetailPageComponent, MobilePageBase, MobilePostDetailPageComponent, MobileTabsExampleComponent, PostActionsComponent, PostAttachmentsComponent, PostContentComponent, PostCreatePageComponent, PostMediaComponent, PostPdfAttachmentComponent, PostTextComponent, SectionHeaderComponent, TileContentComponent, TileIconComponent, TileLabelComponent, TileValueComponent, UserService, WhitelabelDemoPage, WhitelabelService, customBackTransition, customPageTransition };
4269
- export type { ActionGroup, ActionItem, ActionResult, AttachmentItem, AvatarSize, AvatarType, BadgePosition, BottomSheetOptions, ChatAttachment, ChatMessage, ChatModalData, ChatParticipant, ActionResult as CommentActionResult, CommentData, ContactItem, ContentWidth, HandbookDetailData, HandbookItem, InlineTabItem, LightboxAuthor, LightboxImage, LightboxImageOptions, LightboxMediaFile, LightboxMediaType, LightboxOptions, LightboxPdf, LightboxPdfOptions, ModalOptions, ActionResult as PostActionResult, PostDetailData, TabConfig, WhitelabelConfig };
5322
+ export { ActionCommentComponent, ActionLikeComponent, ContentRowComponent, DsAvatarWithBadgeComponent, DsMobileActionsBottomSheetComponent, DsMobileAttachmentPreviewComponent, DsMobileBottomSheetService, DsMobileCardInlineBannerComponent, DsMobileCardInlineComponent, DsMobileCardInlineContactComponent, DsMobileCardInlineFileComponent, DsMobileChatModalComponent, DsMobileChatModalService, DsMobileActionsBottomSheetComponent as DsMobileCommentActionsBottomSheetComponent, DsMobileCommentComponent, DsMobileContactListItemComponent, DsMobileContentComponent, DsMobileContentSectionComponent, DsMobileFabComponent, DsMobileHandbookDetailModalComponent, DsMobileHandbookDetailModalService, DsMobileHandbookFolderComponent, DsMobileHandbookFolderMiniComponent, DsMobileHeaderContentComponent, DsMobileHeaderContentTileComponent, DsMobileInlinePhotoComponent, DsMobileInlineTabsComponent, DsMobileInteractiveListItemInquiryComponent, DsMobileInteractiveListItemMessageComponent, DsMobileInteractiveListItemPostComponent, DsMobileLightboxImageComponent as DsMobileLightboxComponent, DsMobileLightboxFooterComponent, DsMobileLightboxHeaderComponent, DsMobileLightboxImageComponent, DsMobileLightboxPdfComponent, DsMobileLightboxService, DsMobileListItemComponent, DsMobileListItemStaticComponent, DsMobileLongPressDirective, DsMobileMessageBubbleComponent, DsMobileMessageComposerComponent, DsMobileModalBaseComponent, DsMobileModalService, DsMobileNewInquiryModalComponent, DsMobileNewInquiryModalService, DsMobilePageDetailsComponent, DsMobilePageMainComponent, DsMobileActionsBottomSheetComponent as DsMobilePostActionsBottomSheetComponent, DsMobilePostComposerComponent, DsMobilePostCreateBottomSheetComponent, DsMobilePostDetailModalComponent, DsMobilePostDetailModalService, DsMobileTabBarComponent, DsMobileTabsComponent, DsTextInputComponent, MobileCommunityPageComponent, MobileHandbookPageComponent, MobileHomePageComponent, MobileInquiriesPageComponent, MobileInquiryDetailPageComponent, MobileModalBase, MobilePageBase, MobilePostDetailPageComponent, MobileTabsExampleComponent, PostActionsComponent, PostAttachmentsComponent, PostContentComponent, PostCreatePageComponent, PostMediaComponent, PostPdfAttachmentComponent, PostTextComponent, SectionHeaderComponent, SignInPageComponent, TileContentComponent, TileIconComponent, TileLabelComponent, TileValueComponent, UserService, WhitelabelDemoPage, WhitelabelService, customBackTransition, customPageTransition };
5323
+ export type { ActionGroup, ActionItem, ActionResult, AttachmentData, AttachmentFileType, AttachmentItem, AvatarSize, AvatarType, BadgePosition, BottomSheetOptions, ChatAttachment, ChatMessage, ChatModalData, ChatParticipant, Comment, ActionResult as CommentActionResult, CommentData, ContactItem, ContentWidth, HandbookDetailData, HandbookItem, InlineTabItem, InquiryPhoto, LightboxAuthor, LightboxImage, LightboxImageOptions, LightboxMediaFile, LightboxMediaType, LightboxOptions, LightboxPdf, LightboxPdfOptions, ModalOptions, NewInquiryData, NewInquiryModalOptions, Post, ActionResult as PostActionResult, PostDetailData, TabConfig, WhitelabelConfig };