@propbinder/mobile-design 0.1.14 → 0.1.16

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
@@ -2,6 +2,7 @@ import * as _angular_core from '@angular/core';
2
2
  import { AfterViewInit, ElementRef, OnDestroy, EventEmitter, OnInit, ApplicationRef, EnvironmentInjector, Type } from '@angular/core';
3
3
  import { IonContent, NavController, ModalController, GestureController } from '@ionic/angular/standalone';
4
4
  import { ImpactStyle } from '@capacitor/haptics';
5
+ import { ControlValueAccessor } from '@angular/forms';
5
6
  import { Router, ActivatedRoute } from '@angular/router';
6
7
  import { Animation } from '@ionic/angular';
7
8
 
@@ -105,6 +106,7 @@ declare class DsMobilePageMainComponent extends MobilePageBase implements AfterV
105
106
  private platform;
106
107
  private modalController;
107
108
  private router;
109
+ private whitelabelDemoModal;
108
110
  isNativePlatform: _angular_core.Signal<boolean>;
109
111
  title: _angular_core.InputSignal<string>;
110
112
  headerTitle: _angular_core.InputSignal<string>;
@@ -375,226 +377,6 @@ declare class TileValueComponent {
375
377
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<TileValueComponent, "tile-value", never, {}, {}, never, ["*"], true, never>;
376
378
  }
377
379
 
378
- /**
379
- * DsMobilePostCardComponent
380
- *
381
- * Individual post card for community feed and post details.
382
- * Displays user posts with avatar, content, media, and action buttons.
383
- * Follows Threads-inspired design with clean layout and interactions.
384
- *
385
- * @example
386
- * ```html
387
- * <ds-mobile-post-card
388
- * [authorName]="'John Doe'"
389
- * [authorRole]="'Tenant'"
390
- * [timestamp]="'2h ago'"
391
- * [avatarInitials]="'JD'"
392
- * [clickable]="true"
393
- * (postClick)="openPost()">
394
- *
395
- * <post-content>
396
- * <post-text>This is a sample post...</post-text>
397
- * </post-content>
398
- *
399
- * <post-actions>
400
- * <action-like [active]="true" count="42" />
401
- * <action-comment count="12" />
402
- * <action-share />
403
- * </post-actions>
404
- * </ds-mobile-post-card>
405
- * ```
406
- */
407
- declare class DsMobilePostCardComponent {
408
- /**
409
- * Author's display name
410
- */
411
- authorName: _angular_core.InputSignal<string>;
412
- /**
413
- * Author's role (e.g., "Tenant", "Property Manager")
414
- */
415
- authorRole: _angular_core.InputSignal<string>;
416
- /**
417
- * Timestamp text (e.g., "2h ago", "1d ago")
418
- */
419
- timestamp: _angular_core.InputSignal<string>;
420
- /**
421
- * Avatar initials (for initials type)
422
- */
423
- avatarInitials: _angular_core.InputSignal<string>;
424
- /**
425
- * Avatar type
426
- */
427
- avatarType: _angular_core.InputSignal<"initials" | "photo" | "icon">;
428
- /**
429
- * Avatar photo source (for photo type)
430
- */
431
- avatarSrc: _angular_core.InputSignal<string>;
432
- /**
433
- * Icon name (for icon type avatars)
434
- */
435
- avatarIconName: _angular_core.InputSignal<string>;
436
- /**
437
- * Show badge on avatar (e.g., for property managers)
438
- */
439
- showBadge: _angular_core.InputSignal<boolean>;
440
- /**
441
- * Display variant
442
- * - 'feed' - Standard feed display (default)
443
- * - 'detail' - Full detail view
444
- * - 'compact' - Compact display for nested/related posts
445
- */
446
- variant: _angular_core.InputSignal<"feed" | "detail" | "compact">;
447
- /**
448
- * Whether the post card is clickable
449
- */
450
- clickable: _angular_core.InputSignal<boolean>;
451
- /**
452
- * Emits when the post card is clicked (if clickable)
453
- */
454
- postClick: _angular_core.OutputEmitterRef<void>;
455
- /**
456
- * Emits when the comment button is clicked
457
- */
458
- commentClick: _angular_core.OutputEmitterRef<void>;
459
- /**
460
- * Emits when the post card is long-pressed
461
- */
462
- longPress: _angular_core.OutputEmitterRef<void>;
463
- /**
464
- * Long press tracking
465
- */
466
- private longPressTimer;
467
- private longPressTriggered;
468
- private touchStartX;
469
- private touchStartY;
470
- private readonly LONG_PRESS_DURATION;
471
- private readonly MOVE_THRESHOLD;
472
- handlePostClick(event: Event): void;
473
- handleCommentClick(): void;
474
- /**
475
- * Handle touch start for long press detection
476
- */
477
- handleTouchStart(event: TouchEvent): void;
478
- /**
479
- * Handle touch end to clear long press timer
480
- */
481
- handleTouchEnd(event: TouchEvent): void;
482
- /**
483
- * Handle touch move to cancel long press if moved too much
484
- */
485
- handleTouchMove(event: TouchEvent): void;
486
- /**
487
- * Handle context menu (right-click on desktop) to trigger long press action
488
- */
489
- handleContextMenu(event: Event): void;
490
- static ɵfac: _angular_core.ɵɵFactoryDeclaration<DsMobilePostCardComponent, never>;
491
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<DsMobilePostCardComponent, "ds-mobile-post-card", never, { "authorName": { "alias": "authorName"; "required": true; "isSignal": true; }; "authorRole": { "alias": "authorRole"; "required": true; "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; }; "avatarIconName": { "alias": "avatarIconName"; "required": false; "isSignal": true; }; "showBadge": { "alias": "showBadge"; "required": false; "isSignal": true; }; "variant": { "alias": "variant"; "required": false; "isSignal": true; }; "clickable": { "alias": "clickable"; "required": false; "isSignal": true; }; }, { "postClick": "postClick"; "commentClick": "commentClick"; "longPress": "longPress"; }, never, ["post-menu", "post-content", "post-actions"], true, never>;
492
- }
493
- /**
494
- * PostContentComponent
495
- *
496
- * Main content section of the post.
497
- *
498
- * Contains:
499
- * - `<post-text>` - Text content
500
- * - `<post-media>` - Optional images/videos
501
- * - `<post-attachments>` - Optional file attachments
502
- */
503
- declare class PostContentComponent {
504
- static ɵfac: _angular_core.ɵɵFactoryDeclaration<PostContentComponent, never>;
505
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<PostContentComponent, "post-content", never, {}, {}, never, ["post-text", "post-media", "ds-mobile-inline-photo", "post-attachments"], true, never>;
506
- }
507
- /**
508
- * PostTextComponent
509
- *
510
- * Text content of the post.
511
- */
512
- declare class PostTextComponent {
513
- static ɵfac: _angular_core.ɵɵFactoryDeclaration<PostTextComponent, never>;
514
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<PostTextComponent, "post-text", never, {}, {}, never, ["*"], true, never>;
515
- }
516
- /**
517
- * PostMediaComponent
518
- *
519
- * Media container for images/videos.
520
- */
521
- declare class PostMediaComponent {
522
- static ɵfac: _angular_core.ɵɵFactoryDeclaration<PostMediaComponent, never>;
523
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<PostMediaComponent, "post-media", never, {}, {}, never, ["*"], true, never>;
524
- }
525
- /**
526
- * PostAttachmentsComponent
527
- *
528
- * Container for file attachments, links, etc.
529
- */
530
- declare class PostAttachmentsComponent {
531
- static ɵfac: _angular_core.ɵɵFactoryDeclaration<PostAttachmentsComponent, never>;
532
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<PostAttachmentsComponent, "post-attachments", never, {}, {}, never, ["*"], true, never>;
533
- }
534
- /**
535
- * PostActionsComponent
536
- *
537
- * Action buttons container (like, comment, share).
538
- *
539
- * Contains:
540
- * - `<action-like>` - Like button with count
541
- * - `<action-comment>` - Comment button with count
542
- * - `<action-share>` - Share button
543
- */
544
- declare class PostActionsComponent {
545
- static ɵfac: _angular_core.ɵɵFactoryDeclaration<PostActionsComponent, never>;
546
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<PostActionsComponent, "post-actions", never, {}, {}, never, ["*"], true, never>;
547
- }
548
- /**
549
- * ActionLikeComponent
550
- *
551
- * Like action button with count display and animated heart icon.
552
- */
553
- declare class ActionLikeComponent {
554
- /**
555
- * Whether the like is active (user has liked)
556
- * Using model() for two-way binding
557
- */
558
- active: _angular_core.ModelSignal<boolean>;
559
- /**
560
- * Number of likes
561
- * Using model() for two-way binding
562
- */
563
- count: _angular_core.ModelSignal<number>;
564
- /**
565
- * Emits when the like button is clicked
566
- */
567
- likeClick: _angular_core.OutputEmitterRef<{
568
- active: boolean;
569
- count: number;
570
- }>;
571
- /**
572
- * Signal to control pulse animation
573
- */
574
- isPulsing: _angular_core.WritableSignal<boolean>;
575
- handleClick(event: Event): Promise<void>;
576
- static ɵfac: _angular_core.ɵɵFactoryDeclaration<ActionLikeComponent, never>;
577
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<ActionLikeComponent, "action-like", never, { "active": { "alias": "active"; "required": false; "isSignal": true; }; "count": { "alias": "count"; "required": false; "isSignal": true; }; }, { "active": "activeChange"; "count": "countChange"; "likeClick": "likeClick"; }, never, never, true, never>;
578
- }
579
- /**
580
- * ActionCommentComponent
581
- *
582
- * Comment action button with count display.
583
- */
584
- declare class ActionCommentComponent {
585
- /**
586
- * Number of comments
587
- */
588
- count: _angular_core.InputSignal<number>;
589
- /**
590
- * Emits when the comment button is clicked
591
- */
592
- commentClick: _angular_core.OutputEmitterRef<void>;
593
- handleClick(event: Event): void;
594
- static ɵfac: _angular_core.ɵɵFactoryDeclaration<ActionCommentComponent, never>;
595
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<ActionCommentComponent, "action-comment", never, { "count": { "alias": "count"; "required": false; "isSignal": true; }; }, { "commentClick": "commentClick"; }, never, never, true, never>;
596
- }
597
-
598
380
  /**
599
381
  * DsMobileCommentComponent
600
382
  *
@@ -1188,6 +970,110 @@ declare class DsMobileInteractiveListItemPostComponent {
1188
970
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<DsMobileInteractiveListItemPostComponent, never>;
1189
971
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<DsMobileInteractiveListItemPostComponent, "ds-mobile-interactive-list-item-post", never, { "authorName": { "alias": "authorName"; "required": true; "isSignal": true; }; "authorRole": { "alias": "authorRole"; "required": true; "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; }; "avatarIconName": { "alias": "avatarIconName"; "required": false; "isSignal": true; }; "showBadge": { "alias": "showBadge"; "required": false; "isSignal": true; }; "variant": { "alias": "variant"; "required": false; "isSignal": true; }; "clickable": { "alias": "clickable"; "required": false; "isSignal": true; }; }, { "postClick": "postClick"; "commentClick": "commentClick"; "longPress": "longPress"; }, never, ["post-menu", "post-content", "post-actions"], true, never>;
1190
972
  }
973
+ /**
974
+ * PostContentComponent
975
+ *
976
+ * Main content section of the post.
977
+ *
978
+ * Contains:
979
+ * - `<post-text>` - Text content
980
+ * - `<post-media>` - Optional images/videos
981
+ * - `<post-attachments>` - Optional file attachments
982
+ */
983
+ declare class PostContentComponent {
984
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<PostContentComponent, never>;
985
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<PostContentComponent, "post-content", never, {}, {}, never, ["post-text", "post-media", "ds-mobile-inline-photo", "post-attachments"], true, never>;
986
+ }
987
+ /**
988
+ * PostTextComponent
989
+ *
990
+ * Text content of the post.
991
+ */
992
+ declare class PostTextComponent {
993
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<PostTextComponent, never>;
994
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<PostTextComponent, "post-text", never, {}, {}, never, ["*"], true, never>;
995
+ }
996
+ /**
997
+ * PostMediaComponent
998
+ *
999
+ * Media container for images/videos.
1000
+ */
1001
+ declare class PostMediaComponent {
1002
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<PostMediaComponent, never>;
1003
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<PostMediaComponent, "post-media", never, {}, {}, never, ["*"], true, never>;
1004
+ }
1005
+ /**
1006
+ * PostAttachmentsComponent
1007
+ *
1008
+ * Container for file attachments, links, etc.
1009
+ */
1010
+ declare class PostAttachmentsComponent {
1011
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<PostAttachmentsComponent, never>;
1012
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<PostAttachmentsComponent, "post-attachments", never, {}, {}, never, ["*"], true, never>;
1013
+ }
1014
+ /**
1015
+ * PostActionsComponent
1016
+ *
1017
+ * Action buttons container (like, comment, share).
1018
+ *
1019
+ * Contains:
1020
+ * - `<action-like>` - Like button with count
1021
+ * - `<action-comment>` - Comment button with count
1022
+ * - `<action-share>` - Share button
1023
+ */
1024
+ declare class PostActionsComponent {
1025
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<PostActionsComponent, never>;
1026
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<PostActionsComponent, "post-actions", never, {}, {}, never, ["*"], true, never>;
1027
+ }
1028
+ /**
1029
+ * ActionLikeComponent
1030
+ *
1031
+ * Like action button with count display and animated heart icon.
1032
+ */
1033
+ declare class ActionLikeComponent {
1034
+ /**
1035
+ * Whether the like is active (user has liked)
1036
+ * Using model() for two-way binding
1037
+ */
1038
+ active: _angular_core.ModelSignal<boolean>;
1039
+ /**
1040
+ * Number of likes
1041
+ * Using model() for two-way binding
1042
+ */
1043
+ count: _angular_core.ModelSignal<number>;
1044
+ /**
1045
+ * Emits when the like button is clicked
1046
+ */
1047
+ likeClick: _angular_core.OutputEmitterRef<{
1048
+ active: boolean;
1049
+ count: number;
1050
+ }>;
1051
+ /**
1052
+ * Signal to control pulse animation
1053
+ */
1054
+ isPulsing: _angular_core.WritableSignal<boolean>;
1055
+ handleClick(event: Event): Promise<void>;
1056
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<ActionLikeComponent, never>;
1057
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<ActionLikeComponent, "action-like", never, { "active": { "alias": "active"; "required": false; "isSignal": true; }; "count": { "alias": "count"; "required": false; "isSignal": true; }; }, { "active": "activeChange"; "count": "countChange"; "likeClick": "likeClick"; }, never, never, true, never>;
1058
+ }
1059
+ /**
1060
+ * ActionCommentComponent
1061
+ *
1062
+ * Comment action button with count display.
1063
+ */
1064
+ declare class ActionCommentComponent {
1065
+ /**
1066
+ * Number of comments
1067
+ */
1068
+ count: _angular_core.InputSignal<number>;
1069
+ /**
1070
+ * Emits when the comment button is clicked
1071
+ */
1072
+ commentClick: _angular_core.OutputEmitterRef<void>;
1073
+ handleClick(event: Event): void;
1074
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<ActionCommentComponent, never>;
1075
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<ActionCommentComponent, "action-comment", never, { "count": { "alias": "count"; "required": false; "isSignal": true; }; }, { "commentClick": "commentClick"; }, never, never, true, never>;
1076
+ }
1191
1077
 
1192
1078
  /**
1193
1079
  * PostPdfAttachmentComponent
@@ -1404,156 +1290,18 @@ declare class DsMobileContactListItemComponent {
1404
1290
  /**
1405
1291
  * Whether the contact item is clickable
1406
1292
  */
1407
- clickable: _angular_core.InputSignal<boolean>;
1408
- /**
1409
- * Whether to show chevron icon
1410
- */
1411
- showChevron: _angular_core.InputSignal<boolean>;
1412
- /**
1413
- * Emits when the contact item is clicked (if clickable)
1414
- */
1415
- contactClick: _angular_core.OutputEmitterRef<void>;
1416
- handleContactClick(): void;
1417
- static ɵfac: _angular_core.ɵɵFactoryDeclaration<DsMobileContactListItemComponent, never>;
1418
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<DsMobileContactListItemComponent, "ds-mobile-contact-list-item", 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; }; "clickable": { "alias": "clickable"; "required": false; "isSignal": true; }; "showChevron": { "alias": "showChevron"; "required": false; "isSignal": true; }; }, { "contactClick": "contactClick"; }, never, never, true, never>;
1419
- }
1420
-
1421
- interface TabConfig$1 {
1422
- id: string;
1423
- label: string;
1424
- route: string;
1425
- icon: string;
1426
- iconActive: string;
1427
- }
1428
- /**
1429
- * DsMobileTabBarComponent
1430
- *
1431
- * Responsive navigation tab bar that adapts from mobile to desktop:
1432
- * - Mobile (< 768px): Bottom tab bar with icons + labels
1433
- * - Desktop (≥ 768px): Top navigation bar with logo, tabs, and avatar
1434
- *
1435
- * Use this component INSIDE your own `ion-tabs` when Angular routing
1436
- * requires `ion-tabs` to be a direct child in your component.
1437
- *
1438
- * @example
1439
- * ```html
1440
- * <!-- In your component with child routes -->
1441
- * <ion-tabs>
1442
- * <ds-mobile-tab-bar
1443
- * [tabs]="tabs"
1444
- * [avatarInitials]="'JD'"
1445
- * (avatarClick)="handleAvatarClick()"
1446
- * />
1447
- * </ion-tabs>
1448
- * ```
1449
- */
1450
- declare class DsMobileTabBarComponent implements OnInit, AfterViewInit, OnDestroy {
1451
- private elementRef;
1452
- tabs: TabConfig$1[];
1453
- avatarType: 'initials' | 'photo' | 'icon';
1454
- avatarInitials: string;
1455
- avatarSrc: string;
1456
- avatarIconName: string;
1457
- avatarClick: EventEmitter<void>;
1458
- activeTab: _angular_core.WritableSignal<string>;
1459
- isDesktop: _angular_core.WritableSignal<boolean>;
1460
- private mutationObserver?;
1461
- private resizeObserver?;
1462
- private mediaQuery?;
1463
- constructor(elementRef: ElementRef);
1464
- ngOnInit(): void;
1465
- ngAfterViewInit(): void;
1466
- ngOnDestroy(): void;
1467
- private setupBreakpointDetection;
1468
- private handleBreakpointChange;
1469
- private setupTitleRemovalObserver;
1470
- private removeTitleAttributes;
1471
- trackByTabId(index: number, tab: TabConfig$1): string;
1472
- isTabActive(tabId: string): boolean;
1473
- handleAvatarClick(): void;
1474
- static ɵfac: _angular_core.ɵɵFactoryDeclaration<DsMobileTabBarComponent, never>;
1475
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<DsMobileTabBarComponent, "ds-mobile-tab-bar", 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>;
1476
- }
1477
-
1478
- /**
1479
- * DsMobileTabsComponent
1480
- *
1481
- * Responsive tab navigation that adapts from mobile to desktop:
1482
- * - Mobile (< 768px): Bottom tab bar with icons + labels
1483
- * - Desktop (≥ 768px): Top navigation bar with logo, tabs, and avatar
1484
- *
1485
- * Wraps ion-tabs to maintain native routing functionality while
1486
- * providing a responsive navigation experience with branding.
1487
- *
1488
- * NOTE: This component wraps `ion-tabs` internally. If your Angular
1489
- * routing requires `ion-tabs` to be a direct child in your component
1490
- * (e.g., when using `ion-router-outlet` in app.html), use the
1491
- * `DsMobileTabBarComponent` directly inside your own `ion-tabs` instead.
1492
- *
1493
- * @example
1494
- * ```html
1495
- * <ds-mobile-tabs
1496
- * [tabs]="tabsConfig"
1497
- * [avatarInitials]="'JD'"
1498
- * (avatarClick)="handleAvatarClick()"
1499
- * />
1500
- * ```
1501
- */
1502
- declare class DsMobileTabsComponent implements OnInit {
1503
- tabs: TabConfig$1[];
1504
- avatarType: 'initials' | 'photo' | 'icon';
1505
- avatarInitials: string;
1506
- avatarSrc: string;
1507
- avatarIconName: string;
1508
- avatarClick: EventEmitter<void>;
1509
- constructor();
1510
- ngOnInit(): void;
1511
- trackByTabId(index: number, tab: TabConfig$1): string;
1512
- handleAvatarClick(): void;
1513
- static ɵfac: _angular_core.ɵɵFactoryDeclaration<DsMobileTabsComponent, never>;
1514
- 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>;
1515
- }
1516
-
1517
- interface InlineTabItem {
1518
- id: string;
1519
- label: string;
1520
- badge?: number;
1521
- }
1522
- /**
1523
- * DsMobileInlineTabsComponent
1524
- *
1525
- * Pill-style inline tabs for filtering/switching views
1526
- * Used in the purple header section of pages
1527
- *
1528
- * @example
1529
- * ```html
1530
- * <ds-mobile-inline-tabs
1531
- * [tabs]="[
1532
- * { id: 'all', label: 'All' },
1533
- * { id: 'open', label: 'Open' },
1534
- * { id: 'closed', label: 'Closed' }
1535
- * ]"
1536
- * [activeTab]="'all'"
1537
- * (tabChange)="handleTabChange($event)">
1538
- * </ds-mobile-inline-tabs>
1539
- * ```
1540
- */
1541
- declare class DsMobileInlineTabsComponent {
1542
- /**
1543
- * Array of tab items to display
1544
- */
1545
- tabs: _angular_core.InputSignal<InlineTabItem[]>;
1293
+ clickable: _angular_core.InputSignal<boolean>;
1546
1294
  /**
1547
- * Currently active tab ID
1295
+ * Whether to show chevron icon
1548
1296
  */
1549
- activeTab: _angular_core.InputSignal<string>;
1297
+ showChevron: _angular_core.InputSignal<boolean>;
1550
1298
  /**
1551
- * Emitted when a tab is clicked
1299
+ * Emits when the contact item is clicked (if clickable)
1552
1300
  */
1553
- tabChange: _angular_core.OutputEmitterRef<string>;
1554
- handleTabClick(tabId: string): void;
1555
- static ɵfac: _angular_core.ɵɵFactoryDeclaration<DsMobileInlineTabsComponent, never>;
1556
- 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>;
1301
+ contactClick: _angular_core.OutputEmitterRef<void>;
1302
+ handleContactClick(): void;
1303
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<DsMobileContactListItemComponent, never>;
1304
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<DsMobileContactListItemComponent, "ds-mobile-contact-list-item", 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; }; "clickable": { "alias": "clickable"; "required": false; "isSignal": true; }; "showChevron": { "alias": "showChevron"; "required": false; "isSignal": true; }; }, { "contactClick": "contactClick"; }, never, never, true, never>;
1557
1305
  }
1558
1306
 
1559
1307
  interface ActionResult {
@@ -1787,6 +1535,213 @@ declare class DsMobilePostCreateBottomSheetComponent implements AfterViewInit, O
1787
1535
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<DsMobilePostCreateBottomSheetComponent, "ds-mobile-post-create-bottom-sheet", never, {}, {}, never, never, true, never>;
1788
1536
  }
1789
1537
 
1538
+ interface TabConfig {
1539
+ id: string;
1540
+ label: string;
1541
+ route: string;
1542
+ icon: string;
1543
+ iconActive: string;
1544
+ }
1545
+ /**
1546
+ * DsMobileTabBarComponent
1547
+ *
1548
+ * Responsive navigation tab bar that adapts from mobile to desktop:
1549
+ * - Mobile (< 768px): Bottom tab bar with icons + labels
1550
+ * - Desktop (≥ 768px): Top navigation bar with logo, tabs, and avatar
1551
+ *
1552
+ * Use this component INSIDE your own `ion-tabs` when Angular routing
1553
+ * requires `ion-tabs` to be a direct child in your component.
1554
+ *
1555
+ * @example
1556
+ * ```html
1557
+ * <!-- In your component with child routes -->
1558
+ * <!-- IMPORTANT: Add class="ds-tabs-wrapper" to ion-tabs for proper styling -->
1559
+ * <ion-tabs class="ds-tabs-wrapper">
1560
+ * <ds-mobile-tab-bar
1561
+ * [tabs]="tabs"
1562
+ * [avatarInitials]="'JD'"
1563
+ * [profileMenuItems]="profileMenuItems"
1564
+ * (profileActionSelected)="handleProfileAction($event)"
1565
+ * />
1566
+ * </ion-tabs>
1567
+ * ```
1568
+ *
1569
+ * @example With profile menu configuration
1570
+ * ```typescript
1571
+ * profileMenuItems: ActionGroup[] = [
1572
+ * {
1573
+ * actions: [
1574
+ * { action: 'profile', title: 'My Profile', icon: 'remixUser3Line' },
1575
+ * { action: 'settings', title: 'Settings', icon: 'remixSettings3Line' }
1576
+ * ]
1577
+ * },
1578
+ * {
1579
+ * actions: [
1580
+ * { action: 'logout', title: 'Log Out', icon: 'remixLogoutBoxLine', destructive: true }
1581
+ * ]
1582
+ * }
1583
+ * ];
1584
+ *
1585
+ * handleProfileAction(result: ActionResult): void {
1586
+ * switch (result.action) {
1587
+ * case 'profile': // Navigate to profile
1588
+ * case 'settings': // Navigate to settings
1589
+ * case 'logout': // Handle logout
1590
+ * }
1591
+ * }
1592
+ * ```
1593
+ *
1594
+ * @note When using this component, you must add the class "ds-tabs-wrapper"
1595
+ * to your `ion-tabs` element, or manually apply these styles:
1596
+ * ```css
1597
+ * ion-tabs {
1598
+ * height: 100%;
1599
+ * background: var(--color-brand-secondary);
1600
+ * }
1601
+ * ```
1602
+ */
1603
+ declare class DsMobileTabBarComponent implements OnInit, AfterViewInit, OnDestroy {
1604
+ private elementRef;
1605
+ tabs: TabConfig[];
1606
+ avatarType: 'initials' | 'photo' | 'icon';
1607
+ avatarInitials: string;
1608
+ avatarSrc: string;
1609
+ avatarIconName: string;
1610
+ /**
1611
+ * Profile menu action groups to display when avatar is clicked.
1612
+ * If not provided, only the avatarClick event will be emitted.
1613
+ *
1614
+ * @example
1615
+ * ```typescript
1616
+ * profileMenuItems: ActionGroup[] = [
1617
+ * {
1618
+ * actions: [
1619
+ * { action: 'profile', title: 'My Profile', icon: 'remixUser3Line' },
1620
+ * { action: 'settings', title: 'Settings', icon: 'remixSettings3Line' }
1621
+ * ]
1622
+ * }
1623
+ * ];
1624
+ * ```
1625
+ */
1626
+ profileMenuItems?: ActionGroup[];
1627
+ avatarClick: EventEmitter<void>;
1628
+ /**
1629
+ * Emitted when a profile menu action is selected.
1630
+ * Parent component should handle the action logic (navigation, logout, etc.).
1631
+ */
1632
+ profileActionSelected: EventEmitter<ActionResult>;
1633
+ activeTab: _angular_core.WritableSignal<string>;
1634
+ isDesktop: _angular_core.WritableSignal<boolean>;
1635
+ private mutationObserver?;
1636
+ private slotEnforcementObserver?;
1637
+ private resizeObserver?;
1638
+ private mediaQuery?;
1639
+ private routerSubscription?;
1640
+ private router?;
1641
+ private modalController;
1642
+ constructor(elementRef: ElementRef);
1643
+ ngOnInit(): void;
1644
+ ngAfterViewInit(): void;
1645
+ private updateSlot;
1646
+ private setupSlotEnforcement;
1647
+ ngOnDestroy(): void;
1648
+ private setupBreakpointDetection;
1649
+ private handleBreakpointChange;
1650
+ private setupTitleRemovalObserver;
1651
+ private removeTitleAttributes;
1652
+ private setupActiveTabDetection;
1653
+ private updateActiveTabFromDOM;
1654
+ trackByTabId(index: number, tab: TabConfig): string;
1655
+ isTabActive(tabRoute: string): boolean;
1656
+ /**
1657
+ * Handle avatar click - opens profile menu if configured, otherwise just emits avatarClick
1658
+ */
1659
+ handleAvatarClick(): Promise<void>;
1660
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<DsMobileTabBarComponent, never>;
1661
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<DsMobileTabBarComponent, "ds-mobile-tab-bar", 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; }; "profileMenuItems": { "alias": "profileMenuItems"; "required": false; }; }, { "avatarClick": "avatarClick"; "profileActionSelected": "profileActionSelected"; }, never, never, true, never>;
1662
+ }
1663
+
1664
+ /**
1665
+ * DsMobileTabsComponent
1666
+ *
1667
+ * Responsive tab navigation that adapts from mobile to desktop:
1668
+ * - Mobile (< 768px): Bottom tab bar with icons + labels
1669
+ * - Desktop (≥ 768px): Top navigation bar with logo, tabs, and avatar
1670
+ *
1671
+ * Wraps ion-tabs to maintain native routing functionality while
1672
+ * providing a responsive navigation experience with branding.
1673
+ *
1674
+ * NOTE: This component wraps `ion-tabs` internally. If your Angular
1675
+ * routing requires `ion-tabs` to be a direct child in your component
1676
+ * (e.g., when using `ion-router-outlet` in app.html), use the
1677
+ * `DsMobileTabBarComponent` directly inside your own `ion-tabs` instead.
1678
+ *
1679
+ * @example
1680
+ * ```html
1681
+ * <ds-mobile-tabs
1682
+ * [tabs]="tabsConfig"
1683
+ * [avatarInitials]="'JD'"
1684
+ * (avatarClick)="handleAvatarClick()"
1685
+ * />
1686
+ * ```
1687
+ */
1688
+ declare class DsMobileTabsComponent implements OnInit {
1689
+ tabs: TabConfig[];
1690
+ avatarType: 'initials' | 'photo' | 'icon';
1691
+ avatarInitials: string;
1692
+ avatarSrc: string;
1693
+ avatarIconName: string;
1694
+ avatarClick: EventEmitter<void>;
1695
+ constructor();
1696
+ ngOnInit(): void;
1697
+ trackByTabId(index: number, tab: TabConfig): string;
1698
+ handleAvatarClick(): void;
1699
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<DsMobileTabsComponent, never>;
1700
+ 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>;
1701
+ }
1702
+
1703
+ interface InlineTabItem {
1704
+ id: string;
1705
+ label: string;
1706
+ badge?: number;
1707
+ }
1708
+ /**
1709
+ * DsMobileInlineTabsComponent
1710
+ *
1711
+ * Pill-style inline tabs for filtering/switching views
1712
+ * Used in the purple header section of pages
1713
+ *
1714
+ * @example
1715
+ * ```html
1716
+ * <ds-mobile-inline-tabs
1717
+ * [tabs]="[
1718
+ * { id: 'all', label: 'All' },
1719
+ * { id: 'open', label: 'Open' },
1720
+ * { id: 'closed', label: 'Closed' }
1721
+ * ]"
1722
+ * [activeTab]="'all'"
1723
+ * (tabChange)="handleTabChange($event)">
1724
+ * </ds-mobile-inline-tabs>
1725
+ * ```
1726
+ */
1727
+ declare class DsMobileInlineTabsComponent {
1728
+ /**
1729
+ * Array of tab items to display
1730
+ */
1731
+ tabs: _angular_core.InputSignal<InlineTabItem[]>;
1732
+ /**
1733
+ * Currently active tab ID
1734
+ */
1735
+ activeTab: _angular_core.InputSignal<string>;
1736
+ /**
1737
+ * Emitted when a tab is clicked
1738
+ */
1739
+ tabChange: _angular_core.OutputEmitterRef<string>;
1740
+ handleTabClick(tabId: string): void;
1741
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<DsMobileInlineTabsComponent, never>;
1742
+ 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>;
1743
+ }
1744
+
1790
1745
  /**
1791
1746
  * Media file types supported by the lightbox
1792
1747
  */
@@ -2489,32 +2444,92 @@ declare class DsMobileModalService {
2489
2444
 
2490
2445
  /**
2491
2446
  * Post data interface for the modal
2447
+ *
2448
+ * Represents a post with its content, author info, and comments.
2449
+ * Use this interface to map your API response data to the component.
2450
+ *
2451
+ * @example
2452
+ * ```typescript
2453
+ * const postData: PostDetailData = {
2454
+ * postId: '123',
2455
+ * authorName: 'John Doe',
2456
+ * authorRole: 'Tenant',
2457
+ * timestamp: '2h ago',
2458
+ * avatarInitials: 'JD',
2459
+ * content: 'Post content here...',
2460
+ * likeCount: 42,
2461
+ * commentCount: 12,
2462
+ * comments: [...]
2463
+ * };
2464
+ * ```
2492
2465
  */
2493
2466
  interface PostDetailData {
2467
+ /** Unique post identifier */
2494
2468
  postId: string;
2469
+ /** Post author name */
2495
2470
  authorName: string;
2471
+ /** Author role (e.g., 'Tenant', 'Manager') */
2496
2472
  authorRole: string;
2473
+ /** Post timestamp (e.g., '2h ago', 'Yesterday') */
2497
2474
  timestamp: string;
2475
+ /** Author avatar initials (1-2 letters) */
2498
2476
  avatarInitials?: string;
2477
+ /** Avatar display type */
2499
2478
  avatarType?: 'photo' | 'initials';
2479
+ /** Author avatar image URL */
2500
2480
  avatarSrc?: string;
2481
+ /** Post text content */
2501
2482
  content: string;
2483
+ /** Optional post image URL */
2502
2484
  imageSrc?: string;
2485
+ /** Image alt text */
2503
2486
  imageAlt?: string;
2487
+ /** Whether the current user has liked this post */
2504
2488
  isLiked?: boolean;
2489
+ /** Number of likes */
2505
2490
  likeCount?: number;
2491
+ /** Number of comments */
2506
2492
  commentCount?: number;
2493
+ /** Array of comments */
2507
2494
  comments?: CommentData[];
2495
+ /** Auto-focus comment input when modal opens */
2508
2496
  focusComment?: boolean;
2509
2497
  }
2498
+ /**
2499
+ * Comment data interface
2500
+ *
2501
+ * Represents a single comment on a post.
2502
+ *
2503
+ * @example
2504
+ * ```typescript
2505
+ * const comment: CommentData = {
2506
+ * authorName: 'Jane Smith',
2507
+ * authorRole: 'Tenant',
2508
+ * timestamp: '1h ago',
2509
+ * avatarInitials: 'JS',
2510
+ * content: 'Great post!',
2511
+ * isLiked: false,
2512
+ * likeCount: 5,
2513
+ * isOwnComment: false
2514
+ * };
2515
+ * ```
2516
+ */
2510
2517
  interface CommentData {
2518
+ /** Comment author name */
2511
2519
  authorName: string;
2520
+ /** Author role */
2512
2521
  authorRole: string;
2522
+ /** Comment timestamp */
2513
2523
  timestamp: string;
2524
+ /** Author avatar initials */
2514
2525
  avatarInitials: string;
2526
+ /** Comment text content */
2515
2527
  content: string;
2528
+ /** Whether the current user has liked this comment */
2516
2529
  isLiked?: boolean;
2530
+ /** Number of likes on this comment */
2517
2531
  likeCount?: number;
2532
+ /** Whether this comment belongs to the current user */
2518
2533
  isOwnComment?: boolean;
2519
2534
  }
2520
2535
  /**
@@ -2551,6 +2566,16 @@ declare class DsMobilePostDetailModalComponent implements AfterViewInit, OnDestr
2551
2566
  private lightbox;
2552
2567
  private bottomSheet;
2553
2568
  postData: PostDetailData;
2569
+ /**
2570
+ * Loading state - when true, shows loading indicator
2571
+ * Set this to true while fetching post data from your API
2572
+ */
2573
+ loading: boolean;
2574
+ /**
2575
+ * Error state - when set, shows error message
2576
+ * Set this to an error message string if API call fails
2577
+ */
2578
+ error?: string;
2554
2579
  commentInput?: ElementRef<HTMLTextAreaElement>;
2555
2580
  post: _angular_core.WritableSignal<PostDetailData>;
2556
2581
  commentText: _angular_core.WritableSignal<string>;
@@ -2638,7 +2663,7 @@ declare class DsMobilePostDetailModalComponent implements AfterViewInit, OnDestr
2638
2663
  */
2639
2664
  handleCommentLongPress(authorName: string, content: string, isOwnComment: boolean): Promise<void>;
2640
2665
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<DsMobilePostDetailModalComponent, never>;
2641
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<DsMobilePostDetailModalComponent, "ds-mobile-post-detail-modal", never, { "postData": { "alias": "postData"; "required": false; }; }, {}, never, never, true, never>;
2666
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<DsMobilePostDetailModalComponent, "ds-mobile-post-detail-modal", never, { "postData": { "alias": "postData"; "required": false; }; "loading": { "alias": "loading"; "required": false; }; "error": { "alias": "error"; "required": false; }; }, {}, never, never, true, never>;
2642
2667
  }
2643
2668
 
2644
2669
  /**
@@ -2691,9 +2716,13 @@ declare class DsMobilePostDetailModalService {
2691
2716
  * Open the post detail modal
2692
2717
  *
2693
2718
  * @param postData Post data to display
2719
+ * @param options Optional loading and error states
2694
2720
  * @returns Promise that resolves when the modal is presented
2695
2721
  */
2696
- open(postData: PostDetailData): Promise<void>;
2722
+ open(postData: PostDetailData, options?: {
2723
+ loading?: boolean;
2724
+ error?: string;
2725
+ }): Promise<void>;
2697
2726
  /**
2698
2727
  * Close the currently open post detail modal
2699
2728
  *
@@ -2713,30 +2742,111 @@ declare class DsMobilePostDetailModalService {
2713
2742
 
2714
2743
  /**
2715
2744
  * Handbook detail data interface
2745
+ *
2746
+ * Represents a handbook category/folder with its sections/items.
2747
+ * Use this interface to map your API response data to the component.
2748
+ *
2749
+ * @example
2750
+ * ```typescript
2751
+ * const handbookData: HandbookDetailData = {
2752
+ * title: 'Access Systems',
2753
+ * variant: 'blue',
2754
+ * iconName: 'remixKey2Line',
2755
+ * itemCount: 5,
2756
+ * items: [...]
2757
+ * };
2758
+ * ```
2716
2759
  */
2717
2760
  interface HandbookDetailData {
2761
+ /** Category/folder title */
2718
2762
  title: string;
2763
+ /** Color variant: 'success', 'warning', 'destructive', 'blue', 'light-purple', 'pink', 'salmon-orange', 'orange', 'lime-green', 'grey' */
2719
2764
  variant: string;
2765
+ /** Icon name from design system (e.g., 'remixKey2Line', 'remixLightbulbLine') */
2720
2766
  iconName: string;
2767
+ /** Total number of items/sections in this category */
2721
2768
  itemCount: number;
2769
+ /** Array of handbook sections/items */
2722
2770
  items?: HandbookItem[];
2723
2771
  }
2772
+ /**
2773
+ * Handbook section/item interface
2774
+ *
2775
+ * Represents a single section within a handbook category.
2776
+ * Each section can have a title, description, images, contacts, and attachments.
2777
+ *
2778
+ * @example
2779
+ * ```typescript
2780
+ * const item: HandbookItem = {
2781
+ * title: 'Key Box Entrance',
2782
+ * description: 'Key box located at main entrance...',
2783
+ * images: ['https://api.example.com/images/keybox.jpg'],
2784
+ * contacts: [{ name: 'Security Co', initials: 'S', phoneNumber: '+45 12345678' }],
2785
+ * attachments: [{ name: 'Manual.pdf', type: 'pdf', url: 'https://...' }]
2786
+ * };
2787
+ * ```
2788
+ */
2724
2789
  interface HandbookItem {
2790
+ /** Section title */
2725
2791
  title: string;
2792
+ /** Optional section description */
2726
2793
  description?: string;
2794
+ /** Array of image URLs to display */
2727
2795
  images?: string[];
2796
+ /** Array of file attachments */
2728
2797
  attachments?: AttachmentItem[];
2798
+ /** Array of contact information */
2729
2799
  contacts?: ContactItem[];
2730
2800
  }
2801
+ /**
2802
+ * File attachment interface
2803
+ *
2804
+ * Represents a file attachment in a handbook section.
2805
+ *
2806
+ * @example
2807
+ * ```typescript
2808
+ * const attachment: AttachmentItem = {
2809
+ * name: 'Installation_Manual.pdf',
2810
+ * type: 'pdf',
2811
+ * url: 'https://api.example.com/files/manual.pdf'
2812
+ * };
2813
+ * ```
2814
+ */
2731
2815
  interface AttachmentItem {
2816
+ /** File name to display */
2732
2817
  name: string;
2818
+ /** File type: 'pdf', 'doc', etc. (used for icon display) */
2733
2819
  type?: string;
2820
+ /** Optional URL for downloading/opening the file */
2821
+ url?: string;
2734
2822
  }
2823
+ /**
2824
+ * Contact information interface
2825
+ *
2826
+ * Represents contact information in a handbook section.
2827
+ *
2828
+ * @example
2829
+ * ```typescript
2830
+ * const contact: ContactItem = {
2831
+ * name: 'Propbinder ApS',
2832
+ * initials: 'P',
2833
+ * contactPerson: 'John Doe',
2834
+ * phoneNumber: '+45 12345678',
2835
+ * email: 'support@propbinder.dk'
2836
+ * };
2837
+ * ```
2838
+ */
2735
2839
  interface ContactItem {
2840
+ /** Company or contact name */
2736
2841
  name: string;
2842
+ /** Initials for avatar (1-2 letters) */
2737
2843
  initials: string;
2844
+ /** Optional contact person name */
2738
2845
  contactPerson?: string;
2846
+ /** Optional phone number */
2739
2847
  phoneNumber?: string;
2848
+ /** Optional email address */
2849
+ email?: string;
2740
2850
  }
2741
2851
  /**
2742
2852
  * DsMobileHandbookDetailModalComponent
@@ -2756,6 +2866,14 @@ interface ContactItem {
2756
2866
  declare class DsMobileHandbookDetailModalComponent {
2757
2867
  private modalController;
2758
2868
  handbookData: HandbookDetailData;
2869
+ /**
2870
+ * Loading state - when true, shows loading indicator
2871
+ */
2872
+ loading: boolean;
2873
+ /**
2874
+ * Error state - when set, shows error message
2875
+ */
2876
+ error?: string;
2759
2877
  handbook: _angular_core.WritableSignal<HandbookDetailData>;
2760
2878
  constructor(modalController: ModalController);
2761
2879
  ngOnInit(): void;
@@ -2785,7 +2903,7 @@ declare class DsMobileHandbookDetailModalComponent {
2785
2903
  */
2786
2904
  handleAttachmentClick(attachment: AttachmentItem): void;
2787
2905
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<DsMobileHandbookDetailModalComponent, never>;
2788
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<DsMobileHandbookDetailModalComponent, "ds-mobile-handbook-detail-modal", never, { "handbookData": { "alias": "handbookData"; "required": false; }; }, {}, never, never, true, never>;
2906
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<DsMobileHandbookDetailModalComponent, "ds-mobile-handbook-detail-modal", never, { "handbookData": { "alias": "handbookData"; "required": false; }; "loading": { "alias": "loading"; "required": false; }; "error": { "alias": "error"; "required": false; }; }, {}, never, never, true, never>;
2789
2907
  }
2790
2908
 
2791
2909
  /**
@@ -2833,9 +2951,13 @@ declare class DsMobileHandbookDetailModalService {
2833
2951
  * Open the handbook detail modal
2834
2952
  *
2835
2953
  * @param handbookData Handbook data to display
2954
+ * @param options Optional loading and error states
2836
2955
  * @returns Promise that resolves when the modal is presented
2837
2956
  */
2838
- open(handbookData: HandbookDetailData): Promise<void>;
2957
+ open(handbookData: HandbookDetailData, options?: {
2958
+ loading?: boolean;
2959
+ error?: string;
2960
+ }): Promise<void>;
2839
2961
  /**
2840
2962
  * Close the currently open handbook detail modal
2841
2963
  *
@@ -2892,16 +3014,28 @@ declare class DsMobileHandbookFolderComponent {
2892
3014
  iconName: string;
2893
3015
  /**
2894
3016
  * Number of items in the folder
3017
+ * This should match the length of the items array when data is loaded
2895
3018
  */
2896
3019
  itemCount: number;
2897
3020
  /**
2898
- * Label text displayed below the folder
3021
+ * Label text displayed below the folder (category name)
2899
3022
  */
2900
3023
  label: string;
2901
3024
  /**
2902
3025
  * Optional items data for the handbook folder
3026
+ * Pass the HandbookItem[] array from your API response here
2903
3027
  */
2904
3028
  items?: HandbookItem[];
3029
+ /**
3030
+ * Loading state - when true, shows "Loading..." indicator instead of item count
3031
+ * Set this to true while fetching data from your API
3032
+ */
3033
+ loading: boolean;
3034
+ /**
3035
+ * Error state - when set, shows "Error" indicator instead of item count
3036
+ * Set this to an error message string if API call fails
3037
+ */
3038
+ error?: string;
2905
3039
  /**
2906
3040
  * Track open/closed state for animation
2907
3041
  */
@@ -2932,6 +3066,7 @@ declare class DsMobileHandbookFolderComponent {
2932
3066
  onTouchCancel(): void;
2933
3067
  /**
2934
3068
  * Handle click - open modal
3069
+ * Only opens modal if not in loading or error state
2935
3070
  */
2936
3071
  onClick(): Promise<void>;
2937
3072
  /**
@@ -2941,7 +3076,7 @@ declare class DsMobileHandbookFolderComponent {
2941
3076
  getPageSheets(): number[];
2942
3077
  constructor(handbookModal: DsMobileHandbookDetailModalService);
2943
3078
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<DsMobileHandbookFolderComponent, never>;
2944
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<DsMobileHandbookFolderComponent, "ds-mobile-handbook-folder", never, { "variant": { "alias": "variant"; "required": false; }; "iconName": { "alias": "iconName"; "required": false; }; "itemCount": { "alias": "itemCount"; "required": false; }; "label": { "alias": "label"; "required": false; }; "items": { "alias": "items"; "required": false; }; }, {}, never, never, true, never>;
3079
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<DsMobileHandbookFolderComponent, "ds-mobile-handbook-folder", never, { "variant": { "alias": "variant"; "required": false; }; "iconName": { "alias": "iconName"; "required": false; }; "itemCount": { "alias": "itemCount"; "required": false; }; "label": { "alias": "label"; "required": false; }; "items": { "alias": "items"; "required": false; }; "loading": { "alias": "loading"; "required": false; }; "error": { "alias": "error"; "required": false; }; }, {}, never, never, true, never>;
2945
3080
  }
2946
3081
 
2947
3082
  /**
@@ -2976,6 +3111,87 @@ declare class DsMobileHandbookFolderMiniComponent {
2976
3111
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<DsMobileHandbookFolderMiniComponent, "ds-mobile-handbook-folder-mini", never, { "variant": { "alias": "variant"; "required": false; }; "iconName": { "alias": "iconName"; "required": false; }; }, {}, never, never, true, never>;
2977
3112
  }
2978
3113
 
3114
+ /**
3115
+ * DsTextInputComponent
3116
+ *
3117
+ * Mobile-first text input field component following the design system.
3118
+ * Supports email, phone, text, and other input types.
3119
+ *
3120
+ * Features:
3121
+ * - All design system states (default, hover, focus, error, disabled)
3122
+ * - Validation error state with destructive border color
3123
+ * - Automatic error clearing when input becomes valid (configurable)
3124
+ * - Built-in validation based on input type or custom validator function
3125
+ * - Accessible with proper ARIA attributes
3126
+ * - ControlValueAccessor for Angular forms integration
3127
+ *
3128
+ * @example
3129
+ * ```html
3130
+ * <!-- Basic usage -->
3131
+ * <ds-text-input
3132
+ * type="email"
3133
+ * placeholder="Enter your email"
3134
+ * [(ngModel)]="email">
3135
+ * </ds-text-input>
3136
+ *
3137
+ * <!-- With validation error and auto-clear -->
3138
+ * <ds-text-input
3139
+ * type="email"
3140
+ * placeholder="Enter your email"
3141
+ * [hasError]="emailInvalid"
3142
+ * errorMessage="Please enter a valid email"
3143
+ * [autoClearError]="true"
3144
+ * (errorCleared)="emailInvalid = false"
3145
+ * [(ngModel)]="email">
3146
+ * </ds-text-input>
3147
+ *
3148
+ * <!-- With custom validator -->
3149
+ * <ds-text-input
3150
+ * type="text"
3151
+ * placeholder="Enter phone number"
3152
+ * [validator]="phoneValidator"
3153
+ * [hasError]="phoneInvalid"
3154
+ * (errorCleared)="phoneInvalid = false"
3155
+ * [(ngModel)]="phone">
3156
+ * </ds-text-input>
3157
+ * ```
3158
+ */
3159
+ declare class DsTextInputComponent implements ControlValueAccessor {
3160
+ type: _angular_core.InputSignal<"text" | "email" | "tel" | "password" | "url" | "search">;
3161
+ placeholder: _angular_core.InputSignal<string>;
3162
+ disabled: _angular_core.InputSignal<boolean>;
3163
+ readonly: _angular_core.InputSignal<boolean>;
3164
+ required: _angular_core.InputSignal<boolean>;
3165
+ hasError: _angular_core.InputSignal<boolean>;
3166
+ errorMessage: _angular_core.InputSignal<string>;
3167
+ autocomplete: _angular_core.InputSignal<string>;
3168
+ inputmode: _angular_core.InputSignal<"text" | "email" | "tel" | "url" | "search" | "numeric" | undefined>;
3169
+ autoClearError: _angular_core.InputSignal<boolean>;
3170
+ validator: _angular_core.InputSignal<((value: string) => boolean) | null>;
3171
+ valueChange: _angular_core.OutputEmitterRef<string>;
3172
+ blur: _angular_core.OutputEmitterRef<FocusEvent>;
3173
+ focus: _angular_core.OutputEmitterRef<FocusEvent>;
3174
+ errorCleared: _angular_core.OutputEmitterRef<void>;
3175
+ private _value;
3176
+ value: _angular_core.Signal<string>;
3177
+ inputId: string;
3178
+ private onChange;
3179
+ private onTouched;
3180
+ onInput(event: Event): void;
3181
+ /**
3182
+ * Validates the input value based on type or custom validator
3183
+ */
3184
+ private validateInput;
3185
+ onBlur(): void;
3186
+ onFocus(): void;
3187
+ writeValue(value: string): void;
3188
+ registerOnChange(fn: (value: string) => void): void;
3189
+ registerOnTouched(fn: () => void): void;
3190
+ setDisabledState(isDisabled: boolean): void;
3191
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<DsTextInputComponent, never>;
3192
+ 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>;
3193
+ }
3194
+
2979
3195
  /**
2980
3196
  * User service for managing current user data globally
2981
3197
  */
@@ -3129,23 +3345,33 @@ declare class MobileInquiryDetailPageComponent extends MobilePageBase implements
3129
3345
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<MobileInquiryDetailPageComponent, "app-mobile-inquiry-detail-page", never, {}, {}, never, never, true, never>;
3130
3346
  }
3131
3347
 
3132
- interface TabConfig {
3133
- id: string;
3134
- label: string;
3135
- route: string;
3136
- icon: string;
3137
- iconActive: string;
3138
- }
3139
-
3348
+ /**
3349
+ * MobileTabsExampleComponent
3350
+ *
3351
+ * Example page using the TenantApp pattern:
3352
+ * - Uses ion-tabs as wrapper (required for Angular routing)
3353
+ * - Uses ds-mobile-tab-bar inside (not ds-mobile-tabs)
3354
+ *
3355
+ * This matches the pattern used in TenantApp for consistency.
3356
+ */
3140
3357
  declare class MobileTabsExampleComponent implements OnInit {
3141
3358
  userService: UserService;
3142
- private modalController;
3143
3359
  private router;
3144
3360
  private whitelabelDemoModal;
3145
- constructor(userService: UserService, modalController: ModalController, router: Router);
3361
+ constructor(userService: UserService, router: Router);
3146
3362
  ngOnInit(): void;
3147
3363
  tabs: TabConfig[];
3148
- handleAvatarClick(): Promise<void>;
3364
+ /**
3365
+ * Profile menu items configuration.
3366
+ * Define once here, and the tab bar component handles opening/closing the menu.
3367
+ */
3368
+ profileMenuItems: ActionGroup[];
3369
+ /**
3370
+ * Handle profile menu action selection.
3371
+ * The tab bar component handles the UI (opening/closing menu),
3372
+ * this method handles the business logic.
3373
+ */
3374
+ handleProfileAction(result: ActionResult): void;
3149
3375
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<MobileTabsExampleComponent, never>;
3150
3376
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<MobileTabsExampleComponent, "app-mobile-tabs-example", never, {}, {}, never, never, true, never>;
3151
3377
  }
@@ -3341,5 +3567,5 @@ declare const customPageTransition: (_: HTMLElement, opts: any) => Animation;
3341
3567
  */
3342
3568
  declare const customBackTransition: (_: HTMLElement, opts: any) => Animation;
3343
3569
 
3344
- export { ActionCommentComponent, ActionLikeComponent, ContentRowComponent, DsMobileActionsBottomSheetComponent, DsMobileBottomSheetService, 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, DsMobileModalService, DsMobilePageDetailsComponent, DsMobilePageMainComponent, DsMobileActionsBottomSheetComponent as DsMobilePostActionsBottomSheetComponent, DsMobilePostCardComponent, DsMobilePostComposerComponent, DsMobilePostCreateBottomSheetComponent, DsMobilePostDetailModalComponent, DsMobilePostDetailModalService, DsMobileTabBarComponent, DsMobileTabsComponent, 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 };
3345
- export type { ActionGroup, ActionItem, ActionResult, AttachmentItem, BottomSheetOptions, ActionResult as CommentActionResult, CommentData, ContactItem, ContentWidth, HandbookDetailData, HandbookItem, InlineTabItem, LightboxAuthor, LightboxImage, LightboxImageOptions, LightboxMediaFile, LightboxMediaType, LightboxOptions, LightboxPdf, LightboxPdfOptions, ModalOptions, ActionResult as PostActionResult, PostDetailData, TabConfig$1 as TabConfig, WhitelabelConfig };
3570
+ export { ActionCommentComponent, ActionLikeComponent, ContentRowComponent, DsMobileActionsBottomSheetComponent, DsMobileBottomSheetService, 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, 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 };
3571
+ export type { ActionGroup, ActionItem, ActionResult, AttachmentItem, BottomSheetOptions, ActionResult as CommentActionResult, CommentData, ContactItem, ContentWidth, HandbookDetailData, HandbookItem, InlineTabItem, LightboxAuthor, LightboxImage, LightboxImageOptions, LightboxMediaFile, LightboxMediaType, LightboxOptions, LightboxPdf, LightboxPdfOptions, ModalOptions, ActionResult as PostActionResult, PostDetailData, TabConfig, WhitelabelConfig };