@propbinder/mobile-design 0.0.1 → 0.0.2

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.
Files changed (123) hide show
  1. package/ng-package.json +7 -0
  2. package/package.json +12 -39
  3. package/src/animations/page-transitions.ts +86 -0
  4. package/src/assets/fonts/Brockmann-Bold.otf +0 -0
  5. package/src/assets/fonts/Brockmann-BoldItalic.otf +0 -0
  6. package/src/assets/fonts/Brockmann-Medium.otf +0 -0
  7. package/src/assets/fonts/Brockmann-MediumItalic.otf +0 -0
  8. package/src/assets/fonts/Brockmann-Regular.otf +0 -0
  9. package/src/assets/fonts/Brockmann-RegularItalic.otf +0 -0
  10. package/src/assets/fonts/Brockmann-SemiBold.otf +0 -0
  11. package/src/assets/fonts/Brockmann-SemiBoldItalic.otf +0 -0
  12. package/src/assets/fonts/Brockmann_desktop_license.pdf +0 -0
  13. package/src/assets/fonts/brockmann-medium-webfont.woff2 +0 -0
  14. package/src/assets/fonts/brockmann-regular-webfont.woff2 +0 -0
  15. package/src/assets/fonts/brockmann-semibold-webfont.woff2 +0 -0
  16. package/src/components/action-list-item/ds-mobile-action-list-item.ts +83 -0
  17. package/src/components/action-list-item/index.ts +2 -0
  18. package/src/components/app-layout/ds-mobile-app-layout.css +343 -0
  19. package/src/components/app-layout/ds-mobile-app-layout.ts +271 -0
  20. package/src/components/app-layout/index.ts +2 -0
  21. package/src/components/avatar-with-badge/ds-avatar-with-badge.ts +130 -0
  22. package/src/components/avatar-with-badge/index.ts +2 -0
  23. package/src/components/bottom-sheet/ds-mobile-actions-bottom-sheet.ts +273 -0
  24. package/src/components/bottom-sheet/ds-mobile-bottom-sheet.css +110 -0
  25. package/src/components/bottom-sheet/ds-mobile-bottom-sheet.service.ts +167 -0
  26. package/src/components/bottom-sheet/ds-mobile-post-create-bottom-sheet.ts +656 -0
  27. package/src/components/bottom-sheet/index.ts +3 -0
  28. package/src/components/comment/ds-mobile-comment.ts +516 -0
  29. package/src/components/comment/index.ts +2 -0
  30. package/src/components/contact-list-item/ds-mobile-contact-list-item.ts +182 -0
  31. package/src/components/contact-list-item/index.ts +2 -0
  32. package/src/components/content/ds-mobile-content.ts +158 -0
  33. package/src/components/content/index.ts +2 -0
  34. package/src/components/ds-mobile-tabs.css +372 -0
  35. package/src/components/ds-mobile-tabs.ts +217 -0
  36. package/src/components/file-attachment/ds-mobile-file-attachment.ts +164 -0
  37. package/src/components/file-attachment/index.ts +2 -0
  38. package/src/components/handbook-detail-modal/ds-mobile-handbook-detail-modal.service.ts +98 -0
  39. package/src/components/handbook-detail-modal/ds-mobile-handbook-detail-modal.ts +514 -0
  40. package/src/components/handbook-detail-modal/index.ts +3 -0
  41. package/src/components/handbook-folder/ds-mobile-handbook-folder-mini.ts +130 -0
  42. package/src/components/handbook-folder/ds-mobile-handbook-folder.ts +444 -0
  43. package/src/components/handbook-folder/index.ts +4 -0
  44. package/src/components/header-content/ds-mobile-header-content.ts +211 -0
  45. package/src/components/header-content/index.ts +2 -0
  46. package/src/components/index.ts +45 -0
  47. package/src/components/inline-photo/ds-mobile-inline-photo.ts +269 -0
  48. package/src/components/inline-photo/index.ts +1 -0
  49. package/src/components/interactive-list-item-inquiry/ds-mobile-interactive-list-item-inquiry.css +60 -0
  50. package/src/components/interactive-list-item-inquiry/ds-mobile-interactive-list-item-inquiry.ts +280 -0
  51. package/src/components/interactive-list-item-inquiry/index.ts +2 -0
  52. package/src/components/interactive-list-item-message/ds-mobile-interactive-list-item-message.ts +197 -0
  53. package/src/components/interactive-list-item-message/index.ts +2 -0
  54. package/src/components/interactive-list-item-post/ds-mobile-interactive-list-item-post.css +70 -0
  55. package/src/components/interactive-list-item-post/ds-mobile-interactive-list-item-post.ts +594 -0
  56. package/src/components/interactive-list-item-post/ds-mobile-post-pdf-attachment.ts +124 -0
  57. package/src/components/interactive-list-item-post/index.ts +13 -0
  58. package/src/components/lightbox/ds-mobile-lightbox-footer.ts +331 -0
  59. package/src/components/lightbox/ds-mobile-lightbox-header.ts +173 -0
  60. package/src/components/lightbox/ds-mobile-lightbox-image.ts +464 -0
  61. package/src/components/lightbox/ds-mobile-lightbox-pdf.css +375 -0
  62. package/src/components/lightbox/ds-mobile-lightbox-pdf.ts +374 -0
  63. package/src/components/lightbox/ds-mobile-lightbox.css +587 -0
  64. package/src/components/lightbox/ds-mobile-lightbox.service.ts +293 -0
  65. package/src/components/lightbox/ds-mobile-lightbox.ts +529 -0
  66. package/src/components/lightbox/index.ts +22 -0
  67. package/src/components/list-item/ds-mobile-list-item.ts +499 -0
  68. package/src/components/list-item/index.ts +2 -0
  69. package/src/components/list-item-static/ds-mobile-list-item-static.ts +133 -0
  70. package/src/components/list-item-static/index.ts +2 -0
  71. package/src/components/logo/ds-logo.ts +85 -0
  72. package/src/components/logo/index.ts +2 -0
  73. package/src/components/modal/ds-mobile-modal.css +163 -0
  74. package/src/components/modal/ds-mobile-modal.service.ts +329 -0
  75. package/src/components/modal/index.ts +8 -0
  76. package/src/components/page-details/ds-mobile-page-details.css +285 -0
  77. package/src/components/page-details/ds-mobile-page-details.ts +128 -0
  78. package/src/components/page-details/index.ts +2 -0
  79. package/src/components/page-main/ds-mobile-page-main.css +346 -0
  80. package/src/components/page-main/ds-mobile-page-main.ts +331 -0
  81. package/src/components/page-main/index.ts +2 -0
  82. package/src/components/post-card/ds-mobile-post-card.ts +685 -0
  83. package/src/components/post-card/ds-mobile-post-pdf-attachment.ts +124 -0
  84. package/src/components/post-card/index.ts +11 -0
  85. package/src/components/post-composer/ds-mobile-post-composer.ts +140 -0
  86. package/src/components/post-composer/index.ts +2 -0
  87. package/src/components/post-detail-modal/ds-mobile-post-detail-modal.service.ts +104 -0
  88. package/src/components/post-detail-modal/ds-mobile-post-detail-modal.ts +1273 -0
  89. package/src/components/post-detail-modal/index.ts +9 -0
  90. package/src/components/shared/directives/index.ts +2 -0
  91. package/src/components/shared/directives/long-press.directive.ts +208 -0
  92. package/src/components/shared/index.ts +3 -0
  93. package/src/components/shared/mobile-common.css +94 -0
  94. package/src/components/shared/mobile-page-base.css +315 -0
  95. package/src/components/shared/mobile-page-base.ts +70 -0
  96. package/src/components/swiper/ds-mobile-swiper.ts +123 -0
  97. package/src/components/swiper/index.ts +2 -0
  98. package/src/components/tab-bar/ds-mobile-tab-bar.ts +132 -0
  99. package/src/components/tab-bar/index.ts +2 -0
  100. package/src/components/tabs/ds-mobile-tabs.css +405 -0
  101. package/src/components/tabs/ds-mobile-tabs.ts +204 -0
  102. package/src/components/tabs/index.ts +2 -0
  103. package/src/pages/community.page.ts +768 -0
  104. package/src/pages/handbook.page.ts +298 -0
  105. package/src/pages/home.page.ts +192 -0
  106. package/src/pages/index.ts +9 -0
  107. package/src/pages/inquiries.example.ts +212 -0
  108. package/src/pages/inquiry-detail.example.css +434 -0
  109. package/src/pages/inquiry-detail.example.ts +416 -0
  110. package/src/pages/mobile-tabs-example.component.ts +146 -0
  111. package/src/pages/post-create.page.ts +311 -0
  112. package/src/pages/post-detail.page.ts +295 -0
  113. package/src/pages/whitelabel-demo.page.ts +548 -0
  114. package/src/public-api.ts +5 -0
  115. package/src/services/user.service.ts +35 -0
  116. package/src/services/whitelabel.service.ts +171 -0
  117. package/src/styles/ionic.css +673 -0
  118. package/tsconfig.lib.json +17 -0
  119. package/tsconfig.lib.prod.json +9 -0
  120. package/tsconfig.spec.json +13 -0
  121. package/fesm2022/propbinder-mobile-design.mjs +0 -8294
  122. package/fesm2022/propbinder-mobile-design.mjs.map +0 -1
  123. package/index.d.ts +0 -2860
@@ -0,0 +1,85 @@
1
+ import { Component, Input, computed, inject } from '@angular/core';
2
+ import { CommonModule } from '@angular/common';
3
+ import { WhitelabelService } from '../../services/whitelabel.service';
4
+
5
+ export type LogoVariant = 'full' | 'mark';
6
+ export type LogoSize = 'sm' | 'md' | 'lg' | 'xl';
7
+
8
+ /**
9
+ * DsLogoComponent
10
+ *
11
+ * Displays the whitelabeled logo or logomark based on current configuration.
12
+ * Automatically pulls logo assets from WhitelabelService.
13
+ *
14
+ * @example
15
+ * Full logo in header:
16
+ * ```html
17
+ * <ds-logo variant="full" size="md" />
18
+ * ```
19
+ *
20
+ * Logomark for compact spaces:
21
+ * ```html
22
+ * <ds-logo variant="mark" size="sm" />
23
+ * ```
24
+ */
25
+ @Component({
26
+ selector: 'ds-logo',
27
+ standalone: true,
28
+ imports: [CommonModule],
29
+ styles: [`
30
+ :host {
31
+ display: inline-block;
32
+ line-height: 0;
33
+ }
34
+
35
+ .logo {
36
+ display: block;
37
+ object-fit: contain;
38
+ }
39
+
40
+ /* Size variants for full logo */
41
+ .logo--full.logo--sm { height: 24px; width: auto; }
42
+ .logo--full.logo--md { height: 32px; width: auto; }
43
+ .logo--full.logo--lg { height: 40px; width: auto; }
44
+ .logo--full.logo--xl { height: 48px; width: auto; }
45
+
46
+ /* Size variants for logomark */
47
+ .logo--mark.logo--sm { height: 20px; width: 20px; }
48
+ .logo--mark.logo--md { height: 28px; width: 28px; }
49
+ .logo--mark.logo--lg { height: 36px; width: 36px; }
50
+ .logo--mark.logo--xl { height: 44px; width: 44px; }
51
+ `],
52
+ template: `
53
+ <img
54
+ [src]="logoSrc()"
55
+ [alt]="logoAlt()"
56
+ [class]="logoClasses()"
57
+ [style.height.px]="customHeight"
58
+ [style.width.px]="customWidth"
59
+ />
60
+ `
61
+ })
62
+ export class DsLogoComponent {
63
+ private whitelabelService = inject(WhitelabelService);
64
+
65
+ @Input() variant: LogoVariant = 'full';
66
+ @Input() size: LogoSize = 'md';
67
+ @Input() customHeight?: number;
68
+ @Input() customWidth?: number;
69
+
70
+ logoSrc = computed(() => {
71
+ return this.variant === 'full'
72
+ ? this.whitelabelService.logoUrl()
73
+ : this.whitelabelService.logoMarkUrl();
74
+ });
75
+
76
+ logoAlt = computed(() => {
77
+ const alt = this.whitelabelService.logoAlt();
78
+ return this.variant === 'full' ? alt : `${alt} logo`;
79
+ });
80
+
81
+ logoClasses = computed(() => {
82
+ return `logo logo--${this.variant} logo--${this.size}`;
83
+ });
84
+ }
85
+
@@ -0,0 +1,2 @@
1
+ export * from './ds-logo';
2
+
@@ -0,0 +1,163 @@
1
+ /**
2
+ * Mobile Modal Styles
3
+ *
4
+ * Global styles for modals opened via DsMobileModalService.
5
+ * These styles are applied to all modals and handle different presentation styles.
6
+ */
7
+
8
+ /* Base modal styles */
9
+ .ds-mobile-modal {
10
+ --background: var(--color-background-neutral-primary, #ffffff);
11
+ --border-radius: 16px;
12
+ --box-shadow: 0 10px 40px rgba(0, 0, 0, 0.15);
13
+ --max-width: 640px;
14
+ --width: 100%;
15
+ }
16
+
17
+ .ds-mobile-modal::part(content) {
18
+ max-width: 640px;
19
+ margin: 0 auto;
20
+ }
21
+
22
+ /* Fullscreen presentation */
23
+ .ds-modal-fullscreen {
24
+ --width: 100%;
25
+ --height: 100%;
26
+ --border-radius: 0;
27
+ }
28
+
29
+ .ds-modal-fullscreen::part(content) {
30
+ border-radius: 0;
31
+ }
32
+
33
+ /* Card presentation (default iOS modal style) */
34
+ .ds-modal-card {
35
+ --width: 100%;
36
+ --max-width: 640px;
37
+ --height: auto;
38
+ --max-height: 90%;
39
+ --border-radius: 16px 16px 0 0;
40
+ }
41
+
42
+ .ds-modal-card::part(content) {
43
+ border-radius: 16px 16px 0 0;
44
+ box-shadow: var(--box-shadow);
45
+ max-width: 640px;
46
+ margin: 0 auto;
47
+ }
48
+
49
+ /* Sheet presentation (bottom sheet with breakpoints) */
50
+ .ds-modal-sheet {
51
+ --width: 100%;
52
+ --max-width: 640px;
53
+ --height: auto;
54
+ --border-radius: 16px 16px 0 0;
55
+ }
56
+
57
+ .ds-modal-sheet::part(content) {
58
+ border-radius: 16px 16px 0 0;
59
+ box-shadow: var(--box-shadow);
60
+ max-width: 640px;
61
+ margin: 0 auto;
62
+ }
63
+
64
+ .ds-modal-sheet::part(handle) {
65
+ background: var(--border-color-default);
66
+ width: 36px;
67
+ height: 4px;
68
+ border-radius: 2px;
69
+ margin: 8px auto 0;
70
+ }
71
+
72
+ /* Backdrop styles */
73
+ .ds-mobile-modal::part(backdrop) {
74
+ background: rgba(0, 0, 0, 0.4);
75
+ backdrop-filter: blur(4px);
76
+ }
77
+
78
+ /* Animations */
79
+ .ds-mobile-modal.modal-card-enter-active,
80
+ .ds-mobile-modal.modal-sheet-enter-active {
81
+ animation: slideUp 0.3s ease-out;
82
+ }
83
+
84
+ .ds-mobile-modal.modal-card-leave-active,
85
+ .ds-mobile-modal.modal-sheet-leave-active {
86
+ animation: slideDown 0.3s ease-in;
87
+ }
88
+
89
+ .ds-mobile-modal.modal-fullscreen-enter-active {
90
+ animation: fadeIn 0.2s ease-out;
91
+ }
92
+
93
+ .ds-mobile-modal.modal-fullscreen-leave-active {
94
+ animation: fadeOut 0.2s ease-in;
95
+ }
96
+
97
+ @keyframes slideUp {
98
+ from {
99
+ transform: translateY(100%);
100
+ }
101
+ to {
102
+ transform: translateY(0);
103
+ }
104
+ }
105
+
106
+ @keyframes slideDown {
107
+ from {
108
+ transform: translateY(0);
109
+ }
110
+ to {
111
+ transform: translateY(100%);
112
+ }
113
+ }
114
+
115
+ @keyframes fadeIn {
116
+ from {
117
+ opacity: 0;
118
+ }
119
+ to {
120
+ opacity: 1;
121
+ }
122
+ }
123
+
124
+ @keyframes fadeOut {
125
+ from {
126
+ opacity: 1;
127
+ }
128
+ to {
129
+ opacity: 0;
130
+ }
131
+ }
132
+
133
+ /* Safe area handling for notched devices */
134
+ @supports (padding: env(safe-area-inset-top)) {
135
+ .ds-modal-fullscreen::part(content) {
136
+ padding-top: env(safe-area-inset-top);
137
+ padding-bottom: env(safe-area-inset-bottom);
138
+ }
139
+ }
140
+
141
+ /* Dark mode support (if needed) */
142
+ @media (prefers-color-scheme: dark) {
143
+ .ds-mobile-modal {
144
+ --background: var(--color-background-neutral-primary-dark, #1a1a1a);
145
+ }
146
+
147
+ .ds-mobile-modal::part(backdrop) {
148
+ background: rgba(0, 0, 0, 0.6);
149
+ }
150
+ }
151
+
152
+ /* Accessibility: Reduced motion */
153
+ @media (prefers-reduced-motion: reduce) {
154
+ .ds-mobile-modal.modal-card-enter-active,
155
+ .ds-mobile-modal.modal-card-leave-active,
156
+ .ds-mobile-modal.modal-sheet-enter-active,
157
+ .ds-mobile-modal.modal-sheet-leave-active,
158
+ .ds-mobile-modal.modal-fullscreen-enter-active,
159
+ .ds-mobile-modal.modal-fullscreen-leave-active {
160
+ animation: none;
161
+ }
162
+ }
163
+
@@ -0,0 +1,329 @@
1
+ import { Injectable, Type } from '@angular/core';
2
+ import { ModalController } from '@ionic/angular/standalone';
3
+
4
+ /**
5
+ * Configuration options for modal presentation
6
+ */
7
+ export interface ModalOptions<T = any> {
8
+ /** The component to display in the modal */
9
+ component: Type<T>;
10
+ /** Props to pass to the component */
11
+ componentProps?: Record<string, any>;
12
+ /** CSS class(es) to apply to the modal */
13
+ cssClass?: string | string[];
14
+ /** Modal presentation style */
15
+ presentationStyle?: 'fullscreen' | 'card' | 'sheet';
16
+ /** Enable backdrop dismiss (tap outside to close) */
17
+ backdropDismiss?: boolean;
18
+ /** Show backdrop */
19
+ showBackdrop?: boolean;
20
+ /** Enable keyboard close (ESC key) */
21
+ keyboardClose?: boolean;
22
+ /** Enable swipe to close */
23
+ swipeToClose?: boolean;
24
+ /** Initial breakpoint (0-1) for sheet presentation */
25
+ initialBreakpoint?: number;
26
+ /** Available breakpoints for sheet presentation */
27
+ breakpoints?: number[];
28
+ /** Animation type */
29
+ animated?: boolean;
30
+ /** Mode (ios or md) */
31
+ mode?: 'ios' | 'md';
32
+ /** Whether to handle navigation back button */
33
+ handleNavigationBack?: boolean;
34
+ }
35
+
36
+ /**
37
+ * DsMobileModalService
38
+ *
39
+ * Generic service for displaying any component as a modal.
40
+ * Built on Ionic's modal system with customizable presentation styles.
41
+ *
42
+ * Features:
43
+ * - Open any component as a modal
44
+ * - Fullscreen, card, or sheet presentation styles
45
+ * - Customizable backdrop and dismissal behavior
46
+ * - Native gestures and animations
47
+ * - Type-safe component props
48
+ *
49
+ * @example
50
+ * ```typescript
51
+ * import { MobilePostDetailPageComponent } from './post-detail.page';
52
+ *
53
+ * constructor(private modal: DsMobileModalService) {}
54
+ *
55
+ * async openPostModal() {
56
+ * await this.modal.open({
57
+ * component: MobilePostDetailPageComponent,
58
+ * componentProps: {
59
+ * postId: '123',
60
+ * authorName: 'John Doe'
61
+ * },
62
+ * presentationStyle: 'card',
63
+ * backdropDismiss: true
64
+ * });
65
+ * }
66
+ * ```
67
+ *
68
+ * @example Sheet presentation with breakpoints
69
+ * ```typescript
70
+ * async openSheet() {
71
+ * await this.modal.open({
72
+ * component: CommentsComponent,
73
+ * presentationStyle: 'sheet',
74
+ * initialBreakpoint: 0.5,
75
+ * breakpoints: [0, 0.5, 0.75, 1],
76
+ * swipeToClose: true
77
+ * });
78
+ * }
79
+ * ```
80
+ */
81
+ @Injectable({
82
+ providedIn: 'root'
83
+ })
84
+ export class DsMobileModalService {
85
+ constructor(private modalController: ModalController) {}
86
+
87
+ /**
88
+ * Open a component as a modal
89
+ *
90
+ * @param options Configuration options for the modal
91
+ * @returns Promise that resolves when the modal is presented
92
+ *
93
+ * @example
94
+ * ```typescript
95
+ * await this.modal.open({
96
+ * component: MyComponent,
97
+ * componentProps: { data: 'value' },
98
+ * presentationStyle: 'fullscreen'
99
+ * });
100
+ * ```
101
+ */
102
+ async open<T = any>(options: ModalOptions<T>): Promise<HTMLIonModalElement> {
103
+ console.log('[Modal] Opening modal with options:', options);
104
+
105
+ const {
106
+ component,
107
+ componentProps,
108
+ cssClass,
109
+ presentationStyle = 'card',
110
+ backdropDismiss = true,
111
+ showBackdrop = true,
112
+ keyboardClose = true,
113
+ swipeToClose,
114
+ initialBreakpoint,
115
+ breakpoints,
116
+ animated = true,
117
+ mode = 'ios',
118
+ handleNavigationBack = true
119
+ } = options;
120
+
121
+ // Build modal configuration
122
+ const modalConfig: any = {
123
+ component,
124
+ componentProps: componentProps || {},
125
+ cssClass: this.buildCssClasses(cssClass, presentationStyle),
126
+ mode,
127
+ backdropDismiss,
128
+ showBackdrop,
129
+ animated,
130
+ keyboardClose,
131
+ presentingElement: document.querySelector('ion-router-outlet') || undefined,
132
+ handle: presentationStyle === 'sheet', // Show handle for sheet presentation
133
+ };
134
+
135
+ // Add swipe to close for sheet presentation
136
+ if (swipeToClose !== undefined) {
137
+ modalConfig.canDismiss = swipeToClose;
138
+ }
139
+
140
+ // Add breakpoints for sheet presentation
141
+ if (presentationStyle === 'sheet' && breakpoints) {
142
+ modalConfig.breakpoints = breakpoints;
143
+ if (initialBreakpoint !== undefined) {
144
+ modalConfig.initialBreakpoint = initialBreakpoint;
145
+ }
146
+ }
147
+
148
+ // Handle navigation back button
149
+ if (handleNavigationBack) {
150
+ modalConfig.canDismiss = async () => {
151
+ // You can add custom logic here if needed
152
+ return true;
153
+ };
154
+ }
155
+
156
+ const modal = await this.modalController.create(modalConfig);
157
+
158
+ console.log('[Modal] Modal created, presenting...');
159
+ await modal.present();
160
+ console.log('[Modal] Modal presented');
161
+
162
+ return modal;
163
+ }
164
+
165
+ /**
166
+ * Open a component as a fullscreen modal
167
+ *
168
+ * @param component Component to display
169
+ * @param componentProps Props to pass to the component
170
+ * @returns Promise that resolves when the modal is presented
171
+ *
172
+ * @example
173
+ * ```typescript
174
+ * await this.modal.openFullscreen(PostDetailPage, { postId: '123' });
175
+ * ```
176
+ */
177
+ async openFullscreen<T = any>(
178
+ component: Type<T>,
179
+ componentProps?: Record<string, any>
180
+ ): Promise<HTMLIonModalElement> {
181
+ return this.open({
182
+ component,
183
+ componentProps,
184
+ presentationStyle: 'fullscreen',
185
+ backdropDismiss: false,
186
+ showBackdrop: false
187
+ });
188
+ }
189
+
190
+ /**
191
+ * Open a component as a card modal
192
+ *
193
+ * @param component Component to display
194
+ * @param componentProps Props to pass to the component
195
+ * @returns Promise that resolves when the modal is presented
196
+ *
197
+ * @example
198
+ * ```typescript
199
+ * await this.modal.openCard(DetailComponent, { itemId: '456' });
200
+ * ```
201
+ */
202
+ async openCard<T = any>(
203
+ component: Type<T>,
204
+ componentProps?: Record<string, any>
205
+ ): Promise<HTMLIonModalElement> {
206
+ return this.open({
207
+ component,
208
+ componentProps,
209
+ presentationStyle: 'card',
210
+ backdropDismiss: true,
211
+ showBackdrop: true
212
+ });
213
+ }
214
+
215
+ /**
216
+ * Open a component as a bottom sheet
217
+ *
218
+ * @param component Component to display
219
+ * @param componentProps Props to pass to the component
220
+ * @param options Additional sheet options (breakpoints, etc.)
221
+ * @returns Promise that resolves when the modal is presented
222
+ *
223
+ * @example
224
+ * ```typescript
225
+ * await this.modal.openSheet(
226
+ * CommentsComponent,
227
+ * { postId: '789' },
228
+ * { initialBreakpoint: 0.5, breakpoints: [0, 0.5, 1] }
229
+ * );
230
+ * ```
231
+ */
232
+ async openSheet<T = any>(
233
+ component: Type<T>,
234
+ componentProps?: Record<string, any>,
235
+ options?: {
236
+ initialBreakpoint?: number;
237
+ breakpoints?: number[];
238
+ swipeToClose?: boolean;
239
+ }
240
+ ): Promise<HTMLIonModalElement> {
241
+ return this.open({
242
+ component,
243
+ componentProps,
244
+ presentationStyle: 'sheet',
245
+ backdropDismiss: true,
246
+ showBackdrop: true,
247
+ swipeToClose: options?.swipeToClose ?? true,
248
+ initialBreakpoint: options?.initialBreakpoint ?? 0.5,
249
+ breakpoints: options?.breakpoints ?? [0, 0.5, 0.75, 1]
250
+ });
251
+ }
252
+
253
+ /**
254
+ * Close the currently open modal
255
+ *
256
+ * @param data Optional data to pass back when dismissing
257
+ * @param role Optional role (e.g., 'cancel', 'confirm')
258
+ * @returns Promise that resolves when the modal is dismissed
259
+ *
260
+ * @example
261
+ * ```typescript
262
+ * await this.modal.dismiss({ saved: true }, 'confirm');
263
+ * ```
264
+ */
265
+ async dismiss(data?: any, role?: string): Promise<boolean> {
266
+ return this.modalController.dismiss(data, role);
267
+ }
268
+
269
+ /**
270
+ * Get the top-most modal if one exists
271
+ *
272
+ * @returns Promise that resolves to the modal element or undefined
273
+ *
274
+ * @example
275
+ * ```typescript
276
+ * const topModal = await this.modal.getTop();
277
+ * if (topModal) {
278
+ * await topModal.dismiss();
279
+ * }
280
+ * ```
281
+ */
282
+ async getTop(): Promise<HTMLIonModalElement | undefined> {
283
+ return this.modalController.getTop();
284
+ }
285
+
286
+ /**
287
+ * Get all currently open modals
288
+ *
289
+ * @returns Promise that resolves to an array of modal elements
290
+ */
291
+ async getAll(): Promise<HTMLIonModalElement[]> {
292
+ const modals: HTMLIonModalElement[] = [];
293
+ let modal = await this.modalController.getTop();
294
+
295
+ while (modal) {
296
+ modals.push(modal);
297
+ // Get the next modal in the stack
298
+ await modal.dismiss();
299
+ modal = await this.modalController.getTop();
300
+ }
301
+
302
+ return modals;
303
+ }
304
+
305
+ /**
306
+ * Build CSS classes for the modal
307
+ */
308
+ private buildCssClasses(
309
+ customClass?: string | string[],
310
+ presentationStyle?: string
311
+ ): string[] {
312
+ const classes: string[] = ['ds-mobile-modal'];
313
+
314
+ if (presentationStyle) {
315
+ classes.push(`ds-modal-${presentationStyle}`);
316
+ }
317
+
318
+ if (customClass) {
319
+ if (Array.isArray(customClass)) {
320
+ classes.push(...customClass);
321
+ } else {
322
+ classes.push(customClass);
323
+ }
324
+ }
325
+
326
+ return classes;
327
+ }
328
+ }
329
+
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Mobile Modal Module
3
+ *
4
+ * Generic service for opening any component as a modal
5
+ */
6
+
7
+ export * from './ds-mobile-modal.service';
8
+