@propbinder/mobile-design 0.2.36 → 0.2.40

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,5 +1,5 @@
1
1
  import * as _angular_core from '@angular/core';
2
- import { OnDestroy, OnInit, ElementRef, EventEmitter, TemplateRef, AfterViewInit, OnChanges, Injector, SimpleChanges, AfterContentInit, ChangeDetectorRef, ApplicationRef, EnvironmentInjector, Type } from '@angular/core';
2
+ import { OnDestroy, OnInit, ElementRef, EventEmitter, TemplateRef, AfterViewInit, OnChanges, Injector, SimpleChanges, ChangeDetectorRef, AfterContentInit, ApplicationRef, EnvironmentInjector, Type } from '@angular/core';
3
3
  import { ModalController, IonContent, NavController, GestureController, ModalOptions as ModalOptions$1 } from '@ionic/angular/standalone';
4
4
  import { Style } from '@capacitor/status-bar';
5
5
  import { ImpactStyle } from '@capacitor/haptics';
@@ -9,6 +9,7 @@ import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
9
9
  import { Router, ActivatedRoute } from '@angular/router';
10
10
  import * as rxjs from 'rxjs';
11
11
  import * as _propbinder_mobile_design from '@propbinder/mobile-design';
12
+ import { AppTrackingStatus } from 'capacitor-plugin-app-tracking-transparency';
12
13
  import { Animation } from '@ionic/angular';
13
14
 
14
15
  /**
@@ -910,7 +911,7 @@ declare class WhitelabelService {
910
911
  readonly logoUrl: _angular_core.Signal<string>;
911
912
  readonly logoMarkUrl: _angular_core.Signal<string>;
912
913
  readonly logoAlt: _angular_core.Signal<string>;
913
- readonly logoSize: _angular_core.Signal<"sm" | "md" | "lg" | "xl">;
914
+ readonly logoSize: _angular_core.Signal<"md" | "sm" | "lg" | "xl">;
914
915
  readonly logoHeight: _angular_core.Signal<number>;
915
916
  readonly appIconSurface: _angular_core.Signal<string>;
916
917
  readonly appIconContent: _angular_core.Signal<string>;
@@ -1291,7 +1292,7 @@ declare class DsMobileSectionComponent {
1291
1292
  */
1292
1293
  handleLinkClick(): void;
1293
1294
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<DsMobileSectionComponent, never>;
1294
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<DsMobileSectionComponent, "ds-mobile-section", never, { "headline": { "alias": "headline"; "required": false; "isSignal": true; }; "icon": { "alias": "icon"; "required": false; "isSignal": true; }; "linkText": { "alias": "linkText"; "required": false; "isSignal": true; }; "padding": { "alias": "padding"; "required": false; "isSignal": true; }; "gap": { "alias": "gap"; "required": false; "isSignal": true; }; "contentGap": { "alias": "contentGap"; "required": false; "isSignal": true; }; "showBorder": { "alias": "showBorder"; "required": false; "isSignal": true; }; "overflow": { "alias": "overflow"; "required": false; "isSignal": true; }; }, { "linkClick": "linkClick"; }, never, ["*"], true, never>;
1295
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<DsMobileSectionComponent, "ds-mobile-section", never, { "headline": { "alias": "headline"; "required": false; "isSignal": true; }; "icon": { "alias": "icon"; "required": false; "isSignal": true; }; "linkText": { "alias": "linkText"; "required": false; "isSignal": true; }; "padding": { "alias": "padding"; "required": false; "isSignal": true; }; "gap": { "alias": "gap"; "required": false; "isSignal": true; }; "contentGap": { "alias": "contentGap"; "required": false; "isSignal": true; }; "showBorder": { "alias": "showBorder"; "required": false; "isSignal": true; }; "overflow": { "alias": "overflow"; "required": false; "isSignal": true; }; }, { "linkClick": "linkClick"; }, never, ["[header-action]", "*"], true, never>;
1295
1296
  }
1296
1297
 
1297
1298
  /**
@@ -1862,9 +1863,15 @@ declare class DsMobileDropdownComponent {
1862
1863
  private elementRef;
1863
1864
  constructor();
1864
1865
  /**
1865
- * Content projection for custom item template
1866
+ * Content projection for custom item template (per-item renderer)
1866
1867
  */
1867
1868
  customItemTemplate?: TemplateRef<any>;
1869
+ /**
1870
+ * Content projection for fully custom popover content.
1871
+ * When provided, the item list is bypassed entirely and this template
1872
+ * is rendered directly inside the popover — use for pickers, forms, etc.
1873
+ */
1874
+ customContent?: TemplateRef<any>;
1868
1875
  /**
1869
1876
  * Optional trigger element ID for Ionic Popover positioning
1870
1877
  */
@@ -1875,7 +1882,8 @@ declare class DsMobileDropdownComponent {
1875
1882
  */
1876
1883
  keepFocusOn: _angular_core.InputSignal<ElementRef<any> | undefined>;
1877
1884
  /**
1878
- * Array of dropdown items to display
1885
+ * Array of dropdown items to display.
1886
+ * Not required when using the #customContent slot.
1879
1887
  */
1880
1888
  items: _angular_core.InputSignal<DsMobileDropdownItem[]>;
1881
1889
  /**
@@ -1906,6 +1914,12 @@ declare class DsMobileDropdownComponent {
1906
1914
  * ARIA label for the dropdown menu
1907
1915
  */
1908
1916
  ariaLabel: _angular_core.InputSignal<string>;
1917
+ /**
1918
+ * Maximum width of the popover.
1919
+ * Defaults to '192px' (standard dropdown width).
1920
+ * Override when using #customContent that requires more space (e.g. '280px' for a picker).
1921
+ */
1922
+ maxWidth: _angular_core.InputSignal<string>;
1909
1923
  /**
1910
1924
  * Emits when an item is selected
1911
1925
  */
@@ -1922,7 +1936,7 @@ declare class DsMobileDropdownComponent {
1922
1936
  * Computed offset Y for Ionic Popover
1923
1937
  * Uses CSS variable for precise control
1924
1938
  */
1925
- offsetY: _angular_core.Signal<"4px" | "-4px">;
1939
+ offsetY: _angular_core.Signal<"-4px" | "4px">;
1926
1940
  /**
1927
1941
  * Computed offset X for Ionic Popover
1928
1942
  * Negative value to shift left by trigger position + add 20px left margin
@@ -1937,7 +1951,7 @@ declare class DsMobileDropdownComponent {
1937
1951
  */
1938
1952
  handleItemClick(item: DsMobileDropdownItem, event: MouseEvent): void;
1939
1953
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<DsMobileDropdownComponent, never>;
1940
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<DsMobileDropdownComponent, "ds-mobile-dropdown", never, { "trigger": { "alias": "trigger"; "required": false; "isSignal": true; }; "keepFocusOn": { "alias": "keepFocusOn"; "required": false; "isSignal": true; }; "items": { "alias": "items"; "required": true; "isSignal": true; }; "isOpen": { "alias": "isOpen"; "required": false; "isSignal": true; }; "position": { "alias": "position"; "required": false; "isSignal": true; }; "align": { "alias": "align"; "required": false; "isSignal": true; }; "maxHeight": { "alias": "maxHeight"; "required": false; "isSignal": true; }; "emptyMessage": { "alias": "emptyMessage"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "ariaLabel"; "required": false; "isSignal": true; }; }, { "itemSelected": "itemSelected"; "closed": "closed"; }, ["customItemTemplate"], never, true, never>;
1954
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<DsMobileDropdownComponent, "ds-mobile-dropdown", never, { "trigger": { "alias": "trigger"; "required": false; "isSignal": true; }; "keepFocusOn": { "alias": "keepFocusOn"; "required": false; "isSignal": true; }; "items": { "alias": "items"; "required": false; "isSignal": true; }; "isOpen": { "alias": "isOpen"; "required": false; "isSignal": true; }; "position": { "alias": "position"; "required": false; "isSignal": true; }; "align": { "alias": "align"; "required": false; "isSignal": true; }; "maxHeight": { "alias": "maxHeight"; "required": false; "isSignal": true; }; "emptyMessage": { "alias": "emptyMessage"; "required": false; "isSignal": true; }; "ariaLabel": { "alias": "ariaLabel"; "required": false; "isSignal": true; }; "maxWidth": { "alias": "maxWidth"; "required": false; "isSignal": true; }; }, { "itemSelected": "itemSelected"; "closed": "closed"; }, ["customItemTemplate", "customContent"], never, true, never>;
1941
1955
  }
1942
1956
 
1943
1957
  /**
@@ -1965,6 +1979,8 @@ declare class DsMobileDropdownComponent {
1965
1979
  * ```
1966
1980
  */
1967
1981
  declare class DsMobileMessageComposerComponent implements AfterViewInit, OnDestroy {
1982
+ private cdr;
1983
+ constructor(cdr: ChangeDetectorRef);
1968
1984
  /**
1969
1985
  * Avatar initials
1970
1986
  */
@@ -2074,8 +2090,9 @@ declare class DsMobileMessageComposerComponent implements AfterViewInit, OnDestr
2074
2090
  mentionDropdownItems: _angular_core.Signal<DsMobileDropdownItem[]>;
2075
2091
  /**
2076
2092
  * Attachment menu items
2093
+ * Static list to prevent change detection loops
2077
2094
  */
2078
- attachmentMenuItems: _angular_core.Signal<DsMobileDropdownItem[]>;
2095
+ readonly attachmentMenuItems: DsMobileDropdownItem[];
2079
2096
  /**
2080
2097
  * Emits when a message is sent
2081
2098
  */
@@ -2182,7 +2199,7 @@ declare class DsMobileMessageComposerComponent implements AfterViewInit, OnDestr
2182
2199
  closeAttachmentMenu(event?: MouseEvent): void;
2183
2200
  /**
2184
2201
  * Handle add photo button click from menu
2185
- * Uses Capacitor Camera API to open photo library directly
2202
+ * Uses Capawesome File Picker API to open photo library directly
2186
2203
  * Allows multiple photo selection
2187
2204
  */
2188
2205
  handleAddPhoto(event?: MouseEvent): Promise<void>;
@@ -3558,6 +3575,10 @@ declare class DsMobileSwiperComponent implements AfterViewInit, OnDestroy {
3558
3575
  * Navigate to next slide
3559
3576
  */
3560
3577
  slideNext(): void;
3578
+ /**
3579
+ * Navigate to a specific slide by index
3580
+ */
3581
+ slideTo(index: number, speed?: number): void;
3561
3582
  /**
3562
3583
  * Check if at the beginning
3563
3584
  */
@@ -5950,6 +5971,11 @@ declare class DsMobileBookingModalComponent implements AfterViewInit {
5950
5971
  private modalController;
5951
5972
  facilityId: string;
5952
5973
  facilityTitle: string;
5974
+ /**
5975
+ * Number of days ahead available for booking selection.
5976
+ * Defaults to 60 (2 months). Override via componentProps when opening the modal.
5977
+ */
5978
+ daysAhead: number;
5953
5979
  swiperComponent?: DsMobileSwiperComponent;
5954
5980
  dateOptions: _angular_core.WritableSignal<DateOption[]>;
5955
5981
  timeSlots: _angular_core.WritableSignal<TimeSlot[]>;
@@ -5962,6 +5988,20 @@ declare class DsMobileBookingModalComponent implements AfterViewInit {
5962
5988
  * After view init - force swiper update to fix initial positioning
5963
5989
  */
5964
5990
  ngAfterViewInit(): void;
5991
+ /**
5992
+ * Returns true if the given date should be disabled in both the swiper and the datepicker.
5993
+ * Weekends are disabled. Index-based mock disabling (i===3, i===7) is swiper-only and
5994
+ * not representable as a date rule, so it is intentionally excluded here.
5995
+ */
5996
+ private isDateUnavailable;
5997
+ /**
5998
+ * Computed signal that returns a fresh disabled-date function whenever dateOptions()
5999
+ * changes. Returning a new function reference causes the datepicker's own isDateDisabled
6000
+ * input to update, which triggers its internal computed to re-run and re-render all
6001
+ * calendar cells with the correct disabled state.
6002
+ * The disabledSet is pre-built once per computation for O(1) per-cell lookups.
6003
+ */
6004
+ dateDisabledFn: _angular_core.Signal<(date: Date) => boolean>;
5965
6005
  /**
5966
6006
  * Generate mock date and time data
5967
6007
  */
@@ -5978,6 +6018,11 @@ declare class DsMobileBookingModalComponent implements AfterViewInit {
5978
6018
  * Handle time slot selection
5979
6019
  */
5980
6020
  selectTime(selectedSlot: TimeSlot): void;
6021
+ /**
6022
+ * Called when the datepicker overlay emits a date selection.
6023
+ * Finds the matching DateOption in the swiper, selects it, and auto-scrolls to it.
6024
+ */
6025
+ jumpToDate(date: Date | null): void;
5981
6026
  /**
5982
6027
  * Handle confirm button click
5983
6028
  */
@@ -5987,7 +6032,7 @@ declare class DsMobileBookingModalComponent implements AfterViewInit {
5987
6032
  */
5988
6033
  handleClose(): Promise<void>;
5989
6034
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<DsMobileBookingModalComponent, never>;
5990
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<DsMobileBookingModalComponent, "ds-mobile-booking-modal", never, { "facilityId": { "alias": "facilityId"; "required": false; }; "facilityTitle": { "alias": "facilityTitle"; "required": false; }; }, {}, never, never, true, never>;
6035
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<DsMobileBookingModalComponent, "ds-mobile-booking-modal", never, { "facilityId": { "alias": "facilityId"; "required": false; }; "facilityTitle": { "alias": "facilityTitle"; "required": false; }; "daysAhead": { "alias": "daysAhead"; "required": false; }; }, {}, never, never, true, never>;
5991
6036
  }
5992
6037
 
5993
6038
  /**
@@ -6014,9 +6059,10 @@ declare class DsMobileBookingModalService extends BaseModalService {
6014
6059
  * @param facilityId The ID of the facility to book
6015
6060
  * @param facilityTitle The display name of the facility
6016
6061
  * @param facilityThumbnail Optional thumbnail image URL
6062
+ * @param daysAhead Number of days ahead available for selection (defaults to 14)
6017
6063
  * @returns Promise that resolves when the booking flow is complete
6018
6064
  */
6019
- open(facilityId: string, facilityTitle: string, facilityThumbnail?: string): Promise<void>;
6065
+ open(facilityId: string, facilityTitle: string, facilityThumbnail?: string, daysAhead?: number): Promise<void>;
6020
6066
  /**
6021
6067
  * Dismiss all open modals
6022
6068
  */
@@ -6363,20 +6409,54 @@ declare class DsMobileWhoCanBookSheetComponent {
6363
6409
  * DsMobileWhenCanBookSheetComponent
6364
6410
  *
6365
6411
  * Bottom sheet for selecting when a facility can be booked (days, time range, duration).
6412
+ * "Vælg selv" opens a drum-roll IonPopover on mobile, or inline number inputs on desktop.
6366
6413
  */
6367
- declare class DsMobileWhenCanBookSheetComponent {
6414
+ declare class DsMobileWhenCanBookSheetComponent implements OnInit {
6368
6415
  private modalController;
6416
+ private platformId;
6417
+ isDesktop: _angular_core.WritableSignal<boolean>;
6369
6418
  selectedDays: _angular_core.WritableSignal<Set<string>>;
6370
6419
  startTime: _angular_core.WritableSignal<string>;
6371
6420
  endTime: _angular_core.WritableSignal<string>;
6372
6421
  selectedDuration: _angular_core.WritableSignal<string>;
6422
+ /**
6423
+ * Maximum number of days available in the "Vælg selv" picker/inputs.
6424
+ * Defaults to 30 (one full month). Override via componentProps when opening the sheet.
6425
+ */
6426
+ maxDays: _angular_core.InputSignal<number>;
6427
+ pickerOpen: _angular_core.WritableSignal<boolean>;
6428
+ customDays: _angular_core.WritableSignal<number>;
6429
+ customHours: _angular_core.WritableSignal<number>;
6430
+ customMinutes: _angular_core.WritableSignal<number>;
6431
+ customDurationLabel: _angular_core.Signal<string>;
6432
+ showInlineInputs: _angular_core.Signal<boolean>;
6373
6433
  days: string[];
6374
6434
  durations: {
6375
6435
  value: string;
6376
6436
  label: string;
6377
6437
  }[];
6438
+ daysOptions: _angular_core.Signal<number[]>;
6439
+ hours: number[];
6440
+ minuteOptions: number[];
6378
6441
  isValid: _angular_core.Signal<string | false>;
6379
6442
  constructor(modalController: ModalController);
6443
+ ngOnInit(): void;
6444
+ /**
6445
+ * Handle duration chip selection.
6446
+ * On mobile, opening "Vælg selv" triggers the IonPopover via its trigger id.
6447
+ * On desktop, it shows the inline inputs.
6448
+ */
6449
+ selectDuration(value: string): void;
6450
+ /**
6451
+ * Normalizes days/hours/minutes so values never overflow their units.
6452
+ * e.g. 0d 48t 0min → 2d 0t 0min; 0d 0t 75min → 0d 1t 15min.
6453
+ * Caps days at maxDays().
6454
+ */
6455
+ normalize(): void;
6456
+ /**
6457
+ * Called when the mobile picker popover is dismissed — normalize and commit.
6458
+ */
6459
+ onPickerDismiss(): void;
6380
6460
  /**
6381
6461
  * Toggle day selection
6382
6462
  */
@@ -6390,7 +6470,7 @@ declare class DsMobileWhenCanBookSheetComponent {
6390
6470
  */
6391
6471
  dismiss(): void;
6392
6472
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<DsMobileWhenCanBookSheetComponent, never>;
6393
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<DsMobileWhenCanBookSheetComponent, "ds-mobile-when-can-book-sheet", never, {}, {}, never, never, true, never>;
6473
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<DsMobileWhenCanBookSheetComponent, "ds-mobile-when-can-book-sheet", never, { "maxDays": { "alias": "maxDays"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
6394
6474
  }
6395
6475
 
6396
6476
  /**
@@ -7004,7 +7084,7 @@ declare class DsMobileHandbookFolderMiniComponent {
7004
7084
  * ```
7005
7085
  */
7006
7086
  declare class DsTextInputComponent implements ControlValueAccessor {
7007
- type: _angular_core.InputSignal<"search" | "text" | "email" | "password" | "tel" | "url">;
7087
+ type: _angular_core.InputSignal<"search" | "text" | "email" | "tel" | "url" | "password">;
7008
7088
  placeholder: _angular_core.InputSignal<string>;
7009
7089
  disabled: _angular_core.InputSignal<boolean>;
7010
7090
  readonly: _angular_core.InputSignal<boolean>;
@@ -7012,7 +7092,7 @@ declare class DsTextInputComponent implements ControlValueAccessor {
7012
7092
  hasError: _angular_core.InputSignal<boolean>;
7013
7093
  errorMessage: _angular_core.InputSignal<string>;
7014
7094
  autocomplete: _angular_core.InputSignal<string>;
7015
- inputmode: _angular_core.InputSignal<"search" | "text" | "numeric" | "email" | "tel" | "url" | undefined>;
7095
+ inputmode: _angular_core.InputSignal<"search" | "text" | "email" | "tel" | "url" | "numeric" | undefined>;
7016
7096
  autoClearError: _angular_core.InputSignal<boolean>;
7017
7097
  validator: _angular_core.InputSignal<((value: string) => boolean) | null>;
7018
7098
  valueChange: _angular_core.OutputEmitterRef<string>;
@@ -7083,7 +7163,7 @@ declare class DsMobileFabComponent implements AfterViewInit, OnDestroy {
7083
7163
  * Note: FAB is always 56px circular, but this affects the icon size
7084
7164
  * @default 'md'
7085
7165
  */
7086
- size: _angular_core.InputSignal<"sm" | "md" | "lg">;
7166
+ size: _angular_core.InputSignal<"md" | "sm" | "lg">;
7087
7167
  /**
7088
7168
  * ARIA label for accessibility
7089
7169
  * @required - Always provide a descriptive label
@@ -7572,11 +7652,29 @@ declare class MobileHandbookPageComponent {
7572
7652
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<MobileHandbookPageComponent, "app-mobile-handbook-page", never, {}, {}, never, never, true, never>;
7573
7653
  }
7574
7654
 
7575
- declare class MobileHomePageComponent {
7655
+ declare class TrackingPermissionService {
7656
+ private readonly trackingPromptRequestedKey;
7657
+ private readonly platform;
7658
+ private readonly trackingSettingsReminder;
7659
+ readonly showTrackingSettingsReminder: _angular_core.Signal<boolean>;
7660
+ requestOnFirstHomeEntry(): Promise<void>;
7661
+ getTrackingStatus(): Promise<AppTrackingStatus | null>;
7662
+ openAppSettings(): Promise<void>;
7663
+ shouldShowSettingsReminder(): boolean;
7664
+ refreshTrackingStatus(): Promise<void>;
7665
+ private isNativeIos;
7666
+ private hasRequestedTrackingPrompt;
7667
+ private setTrackingPromptRequested;
7668
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<TrackingPermissionService, never>;
7669
+ static ɵprov: _angular_core.ɵɵInjectableDeclaration<TrackingPermissionService>;
7670
+ }
7671
+
7672
+ declare class MobileHomePageComponent implements OnInit {
7576
7673
  private router;
7577
7674
  userService: UserService;
7578
7675
  private postsService;
7579
7676
  private postModal;
7677
+ private trackingPermissionService;
7580
7678
  pageComponent: DsMobilePageMainComponent;
7581
7679
  recentPosts: _angular_core.Signal<_propbinder_mobile_design.Post[]>;
7582
7680
  private allInquiries;
@@ -7587,7 +7685,8 @@ declare class MobileHomePageComponent {
7587
7685
  status: "open";
7588
7686
  timestamp: string;
7589
7687
  }[]>;
7590
- constructor(router: Router, userService: UserService, postsService: PostsService, postModal: DsMobilePostDetailModalService);
7688
+ constructor(router: Router, userService: UserService, postsService: PostsService, postModal: DsMobilePostDetailModalService, trackingPermissionService: TrackingPermissionService);
7689
+ ngOnInit(): void;
7591
7690
  handleRefresh(event: any): void;
7592
7691
  openPost(postId: string, focusComment?: boolean): Promise<void>;
7593
7692
  openInquiryDetail(inquiryId: string): void;
@@ -7679,6 +7778,8 @@ declare class MobileTabsExampleComponent implements OnInit {
7679
7778
  userService: UserService;
7680
7779
  private router;
7681
7780
  private whitelabelDemoModal;
7781
+ private trackingPermissionService;
7782
+ private trackedProfileMenuItems;
7682
7783
  constructor(userService: UserService, router: Router);
7683
7784
  ngOnInit(): void;
7684
7785
  tabs: TabConfig[];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@propbinder/mobile-design",
3
- "version": "0.2.36",
3
+ "version": "0.2.40",
4
4
  "peerDependencies": {
5
5
  "@angular/common": "^20.3.0 || ^21.0.0",
6
6
  "@angular/core": "^20.3.0 || ^21.0.0"