@propbinder/mobile-design 0.2.50 → 0.2.53

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 (221) hide show
  1. package/fesm2022/propbinder-mobile-design.mjs +26206 -0
  2. package/fesm2022/propbinder-mobile-design.mjs.map +1 -0
  3. package/index.d.ts +8193 -0
  4. package/package.json +39 -3
  5. package/ng-package.json +0 -24
  6. package/src/animations/page-transitions.ts +0 -165
  7. package/src/components/action-list-item/ds-mobile-action-list-item.ts +0 -102
  8. package/src/components/action-list-item/index.ts +0 -2
  9. package/src/components/app-icon/ds-app-icon.ts +0 -133
  10. package/src/components/app-icon/index.ts +0 -2
  11. package/src/components/attachment-preview/ds-mobile-attachment-preview.css +0 -139
  12. package/src/components/attachment-preview/ds-mobile-attachment-preview.ts +0 -164
  13. package/src/components/attachment-preview/index.ts +0 -1
  14. package/src/components/avatar-with-badge/ds-avatar-with-badge.ts +0 -142
  15. package/src/components/avatar-with-badge/index.ts +0 -2
  16. package/src/components/booking-modal/ds-mobile-booking-confirmation-wrapper.ts +0 -71
  17. package/src/components/booking-modal/ds-mobile-booking-modal.service.ts +0 -121
  18. package/src/components/booking-modal/ds-mobile-booking-modal.ts +0 -598
  19. package/src/components/booking-modal/ds-mobile-booking-summary.ts +0 -161
  20. package/src/components/booking-modal/index.ts +0 -4
  21. package/src/components/bottom-sheet/ds-mobile-actions-bottom-sheet.ts +0 -266
  22. package/src/components/bottom-sheet/ds-mobile-bottom-sheet-header.ts +0 -146
  23. package/src/components/bottom-sheet/ds-mobile-bottom-sheet-wrapper.ts +0 -156
  24. package/src/components/bottom-sheet/ds-mobile-bottom-sheet.css +0 -101
  25. package/src/components/bottom-sheet/ds-mobile-bottom-sheet.service.ts +0 -169
  26. package/src/components/bottom-sheet/ds-mobile-confirmation-sheet.ts +0 -211
  27. package/src/components/bottom-sheet/ds-mobile-post-create-bottom-sheet.ts +0 -578
  28. package/src/components/bottom-sheet/ds-mobile-profile-actions-sheet.ts +0 -614
  29. package/src/components/bottom-sheet/index.ts +0 -8
  30. package/src/components/bottom-sheet/modal-shadow-fix.ts +0 -42
  31. package/src/components/card-inline/ds-mobile-card-inline.ts +0 -301
  32. package/src/components/card-inline/index.ts +0 -2
  33. package/src/components/card-inline-banner/ds-mobile-card-inline-banner.ts +0 -118
  34. package/src/components/card-inline-banner/index.ts +0 -1
  35. package/src/components/card-inline-contact/ds-mobile-card-inline-contact.ts +0 -120
  36. package/src/components/card-inline-contact/index.ts +0 -1
  37. package/src/components/card-inline-file/ds-mobile-card-inline-file.ts +0 -141
  38. package/src/components/card-inline-file/index.ts +0 -1
  39. package/src/components/chat-modal/ds-mobile-chat-modal.css +0 -159
  40. package/src/components/chat-modal/ds-mobile-chat-modal.service.ts +0 -105
  41. package/src/components/chat-modal/ds-mobile-chat-modal.ts +0 -918
  42. package/src/components/chat-modal/index.ts +0 -8
  43. package/src/components/comment/ds-mobile-comment.ts +0 -568
  44. package/src/components/comment/index.ts +0 -2
  45. package/src/components/contact-list-item/ds-mobile-contact-list-item.ts +0 -182
  46. package/src/components/contact-list-item/index.ts +0 -2
  47. package/src/components/content/ds-mobile-content.ts +0 -139
  48. package/src/components/content/index.ts +0 -2
  49. package/src/components/dropdown/ds-mobile-dropdown.css +0 -199
  50. package/src/components/dropdown/ds-mobile-dropdown.ts +0 -340
  51. package/src/components/dropdown/index.ts +0 -2
  52. package/src/components/ds-mobile-tabs.css +0 -407
  53. package/src/components/ds-mobile-tabs.ts +0 -216
  54. package/src/components/empty-state/ds-mobile-empty-state.ts +0 -120
  55. package/src/components/empty-state/index.ts +0 -2
  56. package/src/components/fab/ds-mobile-fab.ts +0 -315
  57. package/src/components/fab/index.ts +0 -1
  58. package/src/components/facility-creation-modal/ds-mobile-facility-creation-confirmation-wrapper.ts +0 -121
  59. package/src/components/facility-creation-modal/ds-mobile-facility-creation-modal.css +0 -189
  60. package/src/components/facility-creation-modal/ds-mobile-facility-creation-modal.service.ts +0 -135
  61. package/src/components/facility-creation-modal/ds-mobile-facility-creation-modal.ts +0 -656
  62. package/src/components/facility-creation-modal/index.ts +0 -9
  63. package/src/components/facility-creation-modal/sheets/ds-mobile-access-sheet.ts +0 -105
  64. package/src/components/facility-creation-modal/sheets/ds-mobile-price-sheet.ts +0 -188
  65. package/src/components/facility-creation-modal/sheets/ds-mobile-when-can-book-sheet.ts +0 -460
  66. package/src/components/facility-creation-modal/sheets/ds-mobile-who-can-book-sheet.ts +0 -134
  67. package/src/components/facility-detail-modal/ds-mobile-facility-detail-modal.service.ts +0 -69
  68. package/src/components/facility-detail-modal/ds-mobile-facility-detail-modal.ts +0 -379
  69. package/src/components/facility-detail-modal/index.ts +0 -2
  70. package/src/components/file-attachment/ds-mobile-file-attachment.ts +0 -164
  71. package/src/components/file-attachment/index.ts +0 -2
  72. package/src/components/handbook-detail-modal/ds-mobile-handbook-detail-modal.css +0 -214
  73. package/src/components/handbook-detail-modal/ds-mobile-handbook-detail-modal.service.ts +0 -84
  74. package/src/components/handbook-detail-modal/ds-mobile-handbook-detail-modal.ts +0 -424
  75. package/src/components/handbook-detail-modal/index.ts +0 -3
  76. package/src/components/handbook-folder/ds-mobile-handbook-folder-mini.ts +0 -175
  77. package/src/components/handbook-folder/ds-mobile-handbook-folder.ts +0 -533
  78. package/src/components/handbook-folder/index.ts +0 -4
  79. package/src/components/header-content/ds-mobile-header-content.ts +0 -222
  80. package/src/components/header-content/index.ts +0 -2
  81. package/src/components/illustration/ds-mobile-illustration.ts +0 -124
  82. package/src/components/illustration/index.ts +0 -2
  83. package/src/components/index.ts +0 -124
  84. package/src/components/inline-photo/ds-mobile-inline-photo.ts +0 -361
  85. package/src/components/inline-photo/index.ts +0 -1
  86. package/src/components/inline-tabs/ds-mobile-inline-tabs.ts +0 -132
  87. package/src/components/inline-tabs/index.ts +0 -2
  88. package/src/components/interactive-list-item-booking/ds-mobile-interactive-list-item-booking.ts +0 -350
  89. package/src/components/interactive-list-item-booking/index.ts +0 -1
  90. package/src/components/interactive-list-item-inquiry/ds-mobile-interactive-list-item-inquiry.ts +0 -321
  91. package/src/components/interactive-list-item-inquiry/index.ts +0 -2
  92. package/src/components/interactive-list-item-message/ds-mobile-interactive-list-item-message.ts +0 -237
  93. package/src/components/interactive-list-item-message/index.ts +0 -2
  94. package/src/components/interactive-list-item-post/ds-mobile-interactive-list-item-post.ts +0 -549
  95. package/src/components/interactive-list-item-post/ds-mobile-post-pdf-attachment.ts +0 -124
  96. package/src/components/interactive-list-item-post/index.ts +0 -13
  97. package/src/components/lightbox/ds-mobile-lightbox-footer.ts +0 -315
  98. package/src/components/lightbox/ds-mobile-lightbox-header.ts +0 -202
  99. package/src/components/lightbox/ds-mobile-lightbox-image.ts +0 -484
  100. package/src/components/lightbox/ds-mobile-lightbox-pdf.css +0 -377
  101. package/src/components/lightbox/ds-mobile-lightbox-pdf.ts +0 -374
  102. package/src/components/lightbox/ds-mobile-lightbox.css +0 -587
  103. package/src/components/lightbox/ds-mobile-lightbox.service.ts +0 -296
  104. package/src/components/lightbox/ds-mobile-lightbox.ts +0 -529
  105. package/src/components/lightbox/index.ts +0 -22
  106. package/src/components/list-item/ds-mobile-list-item.ts +0 -603
  107. package/src/components/list-item/index.ts +0 -2
  108. package/src/components/list-item-static/ds-mobile-list-item-static.ts +0 -133
  109. package/src/components/list-item-static/index.ts +0 -2
  110. package/src/components/loader-overlay/ds-mobile-loader-overlay.css +0 -49
  111. package/src/components/loader-overlay/ds-mobile-loader-overlay.ts +0 -77
  112. package/src/components/loader-overlay/index.ts +0 -1
  113. package/src/components/logo/ds-logo.ts +0 -95
  114. package/src/components/logo/index.ts +0 -2
  115. package/src/components/message-bubble/ds-mobile-message-bubble.ts +0 -633
  116. package/src/components/message-bubble/index.ts +0 -7
  117. package/src/components/message-composer/ds-mobile-message-composer.ts +0 -1146
  118. package/src/components/message-composer/index.ts +0 -7
  119. package/src/components/modal/ds-mobile-modal.css +0 -163
  120. package/src/components/modal/ds-mobile-modal.service.ts +0 -329
  121. package/src/components/modal/index.ts +0 -8
  122. package/src/components/modal-base/ds-mobile-modal-base.css +0 -378
  123. package/src/components/modal-base/ds-mobile-modal-base.ts +0 -261
  124. package/src/components/modal-base/index.ts +0 -2
  125. package/src/components/new-inquiry-modal/ds-mobile-new-inquiry-modal.css +0 -112
  126. package/src/components/new-inquiry-modal/ds-mobile-new-inquiry-modal.service.ts +0 -93
  127. package/src/components/new-inquiry-modal/ds-mobile-new-inquiry-modal.ts +0 -442
  128. package/src/components/new-inquiry-modal/index.ts +0 -4
  129. package/src/components/offline-banner/ds-mobile-offline-banner.ts +0 -135
  130. package/src/components/offline-banner/index.ts +0 -1
  131. package/src/components/page-details/ds-mobile-page-details.css +0 -83
  132. package/src/components/page-details/ds-mobile-page-details.ts +0 -282
  133. package/src/components/page-details/index.ts +0 -2
  134. package/src/components/page-main/ds-mobile-page-main.css +0 -68
  135. package/src/components/page-main/ds-mobile-page-main.ts +0 -421
  136. package/src/components/page-main/index.ts +0 -2
  137. package/src/components/post-composer/ds-mobile-post-composer.ts +0 -140
  138. package/src/components/post-composer/index.ts +0 -2
  139. package/src/components/post-detail-modal/ds-mobile-post-detail-modal.css +0 -390
  140. package/src/components/post-detail-modal/ds-mobile-post-detail-modal.service.ts +0 -108
  141. package/src/components/post-detail-modal/ds-mobile-post-detail-modal.ts +0 -722
  142. package/src/components/post-detail-modal/index.ts +0 -9
  143. package/src/components/property-banner/ds-mobile-property-banner.ts +0 -95
  144. package/src/components/property-banner/index.ts +0 -2
  145. package/src/components/section/ds-mobile-section.ts +0 -263
  146. package/src/components/section/index.ts +0 -2
  147. package/src/components/shared/directives/index.ts +0 -2
  148. package/src/components/shared/directives/long-press.directive.ts +0 -212
  149. package/src/components/shared/index.ts +0 -3
  150. package/src/components/shared/mobile-modal-base.ts +0 -457
  151. package/src/components/shared/mobile-page-base.ts +0 -204
  152. package/src/components/swiper/ds-mobile-swiper-with-nav.ts +0 -160
  153. package/src/components/swiper/ds-mobile-swiper.ts +0 -327
  154. package/src/components/swiper/index.ts +0 -3
  155. package/src/components/system-message-banner/ds-mobile-system-message-banner.ts +0 -129
  156. package/src/components/system-message-banner/index.ts +0 -2
  157. package/src/components/tab-bar/ds-mobile-tab-bar.css +0 -533
  158. package/src/components/tab-bar/ds-mobile-tab-bar.ts +0 -735
  159. package/src/components/tab-bar/index.ts +0 -2
  160. package/src/components/tabs/ds-mobile-tabs.css +0 -25
  161. package/src/components/tabs/ds-mobile-tabs.ts +0 -89
  162. package/src/components/tabs/index.ts +0 -2
  163. package/src/components/text-input/ds-text-input.ts +0 -287
  164. package/src/components/text-input/index.ts +0 -2
  165. package/src/examples/booking.page.ts +0 -434
  166. package/src/examples/community.page.ts +0 -776
  167. package/src/examples/handbook.page.ts +0 -324
  168. package/src/examples/home.page.ts +0 -347
  169. package/src/examples/index.ts +0 -12
  170. package/src/examples/inquiries.example.ts +0 -273
  171. package/src/examples/inquiry-detail.example.css +0 -189
  172. package/src/examples/inquiry-detail.example.ts +0 -415
  173. package/src/examples/mobile-tabs-example.component.ts +0 -208
  174. package/src/examples/post-create.page.ts +0 -311
  175. package/src/examples/post-detail.page.ts +0 -296
  176. package/src/examples/sign-in.page.ts +0 -291
  177. package/src/examples/whitelabel-demo-modal.component.ts +0 -1094
  178. package/src/examples/whitelabel-demo-modal.service.ts +0 -77
  179. package/src/models/index.ts +0 -7
  180. package/src/models/post.model.ts +0 -41
  181. package/src/pages/community.page.ts +0 -769
  182. package/src/pages/handbook.page.ts +0 -388
  183. package/src/pages/home.page.ts +0 -303
  184. package/src/pages/index.ts +0 -11
  185. package/src/pages/inquiries.example.ts +0 -273
  186. package/src/pages/inquiry-detail.example.css +0 -189
  187. package/src/pages/inquiry-detail.example.ts +0 -415
  188. package/src/pages/mobile-tabs-example.component.ts +0 -179
  189. package/src/pages/post-create.page.ts +0 -311
  190. package/src/pages/post-detail.page.ts +0 -296
  191. package/src/pages/sign-in.page.ts +0 -291
  192. package/src/pages/whitelabel-demo-modal.component.ts +0 -1094
  193. package/src/pages/whitelabel-demo-modal.service.ts +0 -77
  194. package/src/public-api.ts +0 -6
  195. package/src/services/base-modal.service.ts +0 -101
  196. package/src/services/index.ts +0 -11
  197. package/src/services/posts.service.ts +0 -542
  198. package/src/services/tracking-permission.service.ts +0 -88
  199. package/src/services/user.service.ts +0 -60
  200. package/src/services/whitelabel.service.ts +0 -675
  201. package/tsconfig.lib.json +0 -17
  202. package/tsconfig.lib.prod.json +0 -9
  203. package/tsconfig.spec.json +0 -13
  204. /package/{src/assets → assets}/fonts/Brockmann-Bold.otf +0 -0
  205. /package/{src/assets → assets}/fonts/Brockmann-BoldItalic.otf +0 -0
  206. /package/{src/assets → assets}/fonts/Brockmann-Medium.otf +0 -0
  207. /package/{src/assets → assets}/fonts/Brockmann-MediumItalic.otf +0 -0
  208. /package/{src/assets → assets}/fonts/Brockmann-Regular.otf +0 -0
  209. /package/{src/assets → assets}/fonts/Brockmann-RegularItalic.otf +0 -0
  210. /package/{src/assets → assets}/fonts/Brockmann-SemiBold.otf +0 -0
  211. /package/{src/assets → assets}/fonts/Brockmann-SemiBoldItalic.otf +0 -0
  212. /package/{src/assets → assets}/fonts/Brockmann_desktop_license.pdf +0 -0
  213. /package/{src/assets → assets}/fonts/brockmann-medium-webfont.woff2 +0 -0
  214. /package/{src/assets → assets}/fonts/brockmann-mediumitalic-webfont.woff2 +0 -0
  215. /package/{src/assets → assets}/fonts/brockmann-regular-webfont.woff2 +0 -0
  216. /package/{src/assets → assets}/fonts/brockmann-regularitalic-webfont.woff2 +0 -0
  217. /package/{src/assets → assets}/fonts/brockmann-semibold-webfont.woff2 +0 -0
  218. /package/{src/assets → assets}/fonts/brockmann-semibolditalic-webfont.woff2 +0 -0
  219. /package/{src/styles → styles}/ionic.css +0 -0
  220. /package/{src/components/shared → styles}/mobile-common.css +0 -0
  221. /package/{src/components/shared → styles}/mobile-page-base.css +0 -0
@@ -1,633 +0,0 @@
1
- import { Component, input, output, computed } from '@angular/core';
2
- import { CommonModule } from '@angular/common';
3
- import { DsAvatarComponent } from '@propbinder/design-system';
4
- import { DsIconComponent } from '@propbinder/design-system';
5
-
6
- /**
7
- * Chat attachment interface
8
- */
9
- export interface ChatAttachment {
10
- id: string;
11
- type: 'image' | 'pdf' | 'file';
12
- url: string;
13
- name: string;
14
- size?: number;
15
- thumbnail?: string;
16
- }
17
-
18
- /**
19
- * DsMobileMessageBubbleComponent
20
- *
21
- * Individual message bubble component for chat conversations.
22
- * Supports left-aligned (sender) and right-aligned (user) messages with different styling.
23
- *
24
- * Features:
25
- * - Left/right alignment based on sender
26
- * - Avatar display (left for sender, right for user)
27
- * - Message content with text wrapping
28
- * - Timestamp display
29
- * - Read receipt indicator (for user's messages)
30
- * - Attachment support
31
- * - Long press support for actions
32
- *
33
- * @example
34
- * ```html
35
- * <!-- Sender's message (left-aligned) -->
36
- * <ds-mobile-message-bubble
37
- * [isOwnMessage]="false"
38
- * [senderName]="'Ricki Meihlen'"
39
- * [content]="'We have received your case...'"
40
- * [timestamp]="'12:34'"
41
- * [avatarInitials]="'RM'">
42
- * </ds-mobile-message-bubble>
43
- *
44
- * <!-- User's message (right-aligned) -->
45
- * <ds-mobile-message-bubble
46
- * [isOwnMessage]="true"
47
- * [senderName]="'You'"
48
- * [content]="'Thank you!'"
49
- * [timestamp]="'12:35'"
50
- * [readStatus]="true"
51
- * [avatarInitials]="'JD'">
52
- * </ds-mobile-message-bubble>
53
- * ```
54
- */
55
- @Component({
56
- selector: 'ds-mobile-message-bubble',
57
- standalone: true,
58
- imports: [CommonModule, DsAvatarComponent, DsIconComponent],
59
- host: {
60
- '[class.is-own-message]': 'isOwnMessage()',
61
- '[class.has-attachments]': 'attachments() && attachments()!.length > 0',
62
- '[class.cluster-single]': 'clusterPosition() === "single"',
63
- '[class.cluster-first]': 'clusterPosition() === "first"',
64
- '[class.cluster-middle]': 'clusterPosition() === "middle"',
65
- '[class.cluster-last]': 'clusterPosition() === "last"',
66
- '[class.tapped]': 'isTapped',
67
- '[class.is-new-message]': 'isNewMessage()',
68
- '(touchstart)': 'handleTouchStart($event)',
69
- '(touchend)': 'handleTouchEnd($event)',
70
- '(touchmove)': 'handleTouchMove($event)',
71
- '(contextmenu)': 'handleContextMenu($event)'
72
- },
73
- styles: [`
74
- :host {
75
- display: flex;
76
- gap: 8px;
77
- margin-bottom: 4px;
78
- width: 100%;
79
- align-items: flex-end;
80
- box-sizing: border-box;
81
- }
82
-
83
- /* Adjust spacing for clustered messages */
84
- :host.cluster-single {
85
- margin-bottom: 12px; /* More space after standalone messages */
86
- }
87
-
88
- :host.cluster-first {
89
- margin-bottom: 2px; /* Tight spacing in cluster */
90
- }
91
-
92
- :host.cluster-middle {
93
- margin-bottom: 2px; /* Tight spacing in cluster */
94
- }
95
-
96
- :host.cluster-last {
97
- margin-bottom: 12px; /* More space after cluster ends */
98
- }
99
-
100
- /* Left-aligned (sender's message) */
101
- :host:not(.is-own-message) {
102
- justify-content: flex-start !important;
103
- flex-direction: row !important;
104
- }
105
-
106
- /* Right-aligned (user's message) - MUST be right-aligned */
107
- :host.is-own-message {
108
- justify-content: flex-end !important;
109
- flex-direction: row-reverse !important;
110
- margin-left: auto !important;
111
- margin-right: 0 !important;
112
- }
113
-
114
- .avatar-wrapper {
115
- flex-shrink: 0;
116
- display: flex;
117
- align-items: flex-end;
118
- width: 32px; /* Reserve space for avatar even when hidden */
119
- }
120
-
121
- .avatar-wrapper.hidden {
122
- visibility: hidden; /* Use visibility instead of display to maintain space */
123
- }
124
-
125
- .message-content-wrapper {
126
- display: flex;
127
- flex-direction: column;
128
- gap: 0;
129
- max-width: 75%;
130
- min-width: 0;
131
- }
132
-
133
- /* Left-aligned message bubble */
134
- :host:not(.is-own-message) .message-content-wrapper {
135
- align-items: flex-start;
136
- }
137
-
138
- /* Right-aligned message bubble */
139
- :host.is-own-message .message-content-wrapper {
140
- align-items: flex-end !important;
141
- margin-left: auto !important;
142
- margin-right: 0 !important;
143
- }
144
-
145
- .message-bubble {
146
- padding: 8px 12px;
147
- border-radius: 20px;
148
- position: relative;
149
- word-wrap: break-word;
150
- white-space: pre-wrap;
151
- max-width: 100%;
152
- display: flex;
153
- flex-direction: column;
154
- /* Tap animation with spring bounce, including border-radius */
155
- transition:
156
- transform var(--spring-bouncy),
157
- border-radius var(--spring-bouncy);
158
- will-change: transform, border-radius;
159
- }
160
-
161
- /* Scale down on tap */
162
- :host.tapped .message-bubble {
163
- transform: scale(0.96);
164
- }
165
-
166
- /* Cluster position border radius overrides */
167
- /* Order: top-left, top-right, bottom-right, bottom-left */
168
-
169
- /* Single message in cluster - 20px all around (default) */
170
-
171
- /* Own messages (right side) - tight corners on the RIGHT */
172
- /* First message in cluster - 20px 20px 4px 20px */
173
- :host.is-own-message.cluster-first .message-bubble {
174
- border-radius: 20px 20px 4px 20px;
175
- }
176
-
177
- /* Middle message in cluster - 20px 4px 4px 20px */
178
- :host.is-own-message.cluster-middle .message-bubble {
179
- border-radius: 20px 4px 4px 20px;
180
- }
181
-
182
- /* Last message in cluster - 20px 4px 20px 20px */
183
- :host.is-own-message.cluster-last .message-bubble {
184
- border-radius: 20px 4px 20px 20px;
185
- }
186
-
187
- /* Sender messages (left side, grey) - tight corners on the LEFT */
188
- /* First message in cluster - 20px 20px 20px 4px */
189
- :host:not(.is-own-message).cluster-first .message-bubble {
190
- border-radius: 20px 20px 20px 4px;
191
- }
192
-
193
- /* Middle message in cluster - 4px 20px 20px 4px */
194
- :host:not(.is-own-message).cluster-middle .message-bubble {
195
- border-radius: 4px 20px 20px 4px;
196
- }
197
-
198
- /* Last message in cluster - 4px 20px 20px 20px */
199
- :host:not(.is-own-message).cluster-last .message-bubble {
200
- border-radius: 4px 20px 20px 20px;
201
- }
202
-
203
- /* Sender's message - neutral secondary background, no border */
204
- :host:not(.is-own-message) .message-bubble {
205
- background: var(--color-background-neutral-secondary, #f5f5f5);
206
- }
207
-
208
- /* User's message - brand primary surface background */
209
- :host.is-own-message .message-bubble {
210
- background: var(--color-accent, var(--color-accent, #6B5FF5));
211
- color: var(--color-on-accent, #ffffff);
212
- }
213
-
214
- .message-text {
215
- font-family: 'Brockmann', sans-serif;
216
- font-size: var(--font-size-sm);
217
- font-weight: 400;
218
- line-height: 20px;
219
- letter-spacing: -0.3px;
220
- margin: 0;
221
- }
222
-
223
- :host:not(.is-own-message) .message-text {
224
- color: var(--color-text-primary, #1a1a1a);
225
- }
226
-
227
- :host.is-own-message .message-text {
228
- color: var(--color-on-accent, #ffffff);
229
- }
230
-
231
- /* Attachments container */
232
- .attachments {
233
- display: flex;
234
- flex-wrap: wrap;
235
- gap: 8px;
236
- margin-top: 8px;
237
- }
238
-
239
- :host:not(.is-own-message) .attachments {
240
- justify-content: flex-start;
241
- }
242
-
243
- :host.is-own-message .attachments {
244
- justify-content: flex-end;
245
- }
246
-
247
- .attachment-item {
248
- display: flex;
249
- align-items: center;
250
- gap: 8px;
251
- padding: 8px 12px;
252
- background: var(--color-background-neutral-secondary, #f5f5f5);
253
- border-radius: 8px;
254
- border: 1px solid var(--border-color-default, #e5e5e5);
255
- cursor: pointer;
256
- transition: background 0.2s ease;
257
- }
258
-
259
- :host.is-own-message .attachment-item {
260
- background: rgba(255, 255, 255, 0.2);
261
- border-color: rgba(255, 255, 255, 0.3);
262
- }
263
-
264
- .attachment-item:active {
265
- background: var(--color-background-neutral-secondary-hover, #ebebeb);
266
- }
267
-
268
- :host.is-own-message .attachment-item:active {
269
- background: rgba(255, 255, 255, 0.3);
270
- }
271
-
272
- .attachment-icon {
273
- flex-shrink: 0;
274
- width: 24px;
275
- height: 24px;
276
- display: flex;
277
- align-items: center;
278
- justify-content: center;
279
- border-radius: 4px;
280
- background: var(--color-background-neutral-primary, #ffffff);
281
- }
282
-
283
- :host.is-own-message .attachment-icon {
284
- background: rgba(255, 255, 255, 0.3);
285
- }
286
-
287
- .attachment-name {
288
- font-family: 'Brockmann', sans-serif;
289
- font-size: var(--font-size-xs);
290
- font-weight: 500;
291
- line-height: 16px;
292
- color: var(--color-text-primary, #1a1a1a);
293
- max-width: 150px;
294
- overflow: hidden;
295
- text-overflow: ellipsis;
296
- white-space: nowrap;
297
- }
298
-
299
- :host.is-own-message .attachment-name {
300
- color: var(--color-text-on-brand, #ffffff);
301
- }
302
-
303
- /* Timestamp inside bubble */
304
- .message-footer {
305
- display: flex;
306
- align-items: center;
307
- gap: 4px;
308
- align-self: flex-end; /* Always align to right within bubble */
309
- height: 0;
310
- margin-top: 0;
311
- opacity: 0;
312
- overflow: hidden;
313
- transform: scale(0.95);
314
- /* Spring bounce animation using design system variable */
315
- transition:
316
- height var(--spring-bouncy),
317
- margin-top var(--spring-bouncy),
318
- opacity var(--spring-bouncy),
319
- transform var(--spring-bouncy);
320
- }
321
-
322
- /* Visible state - fade in and expand */
323
- .message-footer.visible {
324
- height: 14px;
325
- margin-top: 4px;
326
- opacity: 1;
327
- transform: scale(1);
328
- }
329
-
330
- /* Timestamp always right-aligned for both message types */
331
- :host:not(.is-own-message) .message-footer {
332
- align-self: flex-end; /* Right-align timestamp for sender's messages */
333
- }
334
-
335
- .timestamp {
336
- font-family: 'Brockmann', sans-serif;
337
- font-size: 11px;
338
- font-weight: 400;
339
- line-height: 14px;
340
- white-space: nowrap;
341
- }
342
-
343
- /* Timestamp color for sender's messages (grey background) */
344
- :host:not(.is-own-message) .timestamp {
345
- color: var(--color-text-tertiary, #a0a0a0);
346
- }
347
-
348
- /* Timestamp color for user's messages (brand background) */
349
- :host.is-own-message .timestamp {
350
- color: var(--color-on-accent, #ffffff);
351
- opacity: 0.7;
352
- }
353
-
354
- /* Long press tracking */
355
- :host {
356
- user-select: none;
357
- -webkit-tap-highlight-color: transparent;
358
- }
359
-
360
- /* New message animation - bouncy appearance with scale, opacity, and translateY */
361
- :host.is-new-message {
362
- animation: message-appear var(--spring-bouncy) forwards;
363
- }
364
-
365
- @keyframes message-appear {
366
- 0% {
367
- opacity: 0;
368
- transform: translateY(20px) scale(0.92);
369
- }
370
- 100% {
371
- opacity: 1;
372
- transform: translateY(0) scale(1);
373
- }
374
- }
375
- `],
376
- template: `
377
- @if (!isOwnMessage()) {
378
- <div class="avatar-wrapper" [class.hidden]="!showAvatar()">
379
- <ds-avatar
380
- [initials]="avatarInitials()"
381
- [type]="avatarType()"
382
- [src]="avatarSrc()"
383
- size="sm" />
384
- </div>
385
- }
386
-
387
- <div class="message-content-wrapper" (click)="handleClick($event)">
388
- <div class="message-bubble">
389
- <!-- Only show text if content is not empty -->
390
- @if (content().trim()) {
391
- <p class="message-text">{{ content() }}</p>
392
- }
393
-
394
- <!-- Attachments -->
395
- @if (attachments() && attachments()!.length > 0) {
396
- <div class="attachments">
397
- @for (attachment of attachments(); track attachment.id) {
398
- <div
399
- class="attachment-item"
400
- (click)="handleAttachmentClick(attachment); $event.stopPropagation()">
401
- <div class="attachment-icon">
402
- @if (attachment.type === 'image') {
403
- <ds-icon name="remixImageLine" size="16px" />
404
- } @else if (attachment.type === 'pdf') {
405
- <ds-icon name="remixFilePdfLine" size="16px" />
406
- } @else {
407
- <ds-icon name="remixFileLine" size="16px" />
408
- }
409
- </div>
410
- <span class="attachment-name">{{ attachment.name }}</span>
411
- </div>
412
- }
413
- </div>
414
- }
415
-
416
- <!-- Timestamp inside bubble, animated on tap -->
417
- <div class="message-footer" [class.visible]="showTimestamp()">
418
- <span class="timestamp">{{ timestamp() }}</span>
419
- </div>
420
- </div>
421
- </div>
422
- `
423
- })
424
- export class DsMobileMessageBubbleComponent {
425
- /**
426
- * Message content text
427
- */
428
- content = input.required<string>();
429
-
430
- /**
431
- * Whether this is the current user's message (right-aligned)
432
- */
433
- isOwnMessage = input<boolean>(false);
434
-
435
- /**
436
- * Sender's name (for display purposes)
437
- */
438
- senderName = input<string>('');
439
-
440
- /**
441
- * Timestamp text (e.g., "12:34", "08-12-2025 13:18")
442
- */
443
- timestamp = input.required<string>();
444
-
445
- /**
446
- * Whether to show the timestamp below the bubble
447
- */
448
- showTimestamp = input<boolean>(false);
449
-
450
- /**
451
- * Avatar initials
452
- */
453
- avatarInitials = input<string>('');
454
-
455
- /**
456
- * Avatar type
457
- */
458
- avatarType = input<'initials' | 'photo' | 'icon'>('initials');
459
-
460
- /**
461
- * Avatar photo source (for photo type)
462
- */
463
- avatarSrc = input<string>('');
464
-
465
- /**
466
- * Whether to show the avatar (for clustering logic)
467
- */
468
- showAvatar = input<boolean>(true);
469
-
470
- /**
471
- * Cluster position for border radius styling
472
- */
473
- clusterPosition = input<'single' | 'first' | 'middle' | 'last'>('single');
474
-
475
- /**
476
- * Whether to show read receipt (only for user's messages)
477
- */
478
- /**
479
- * Message attachments
480
- */
481
- attachments = input<ChatAttachment[] | undefined>(undefined);
482
-
483
- /**
484
- * Whether the message is clickable
485
- */
486
- clickable = input<boolean>(false);
487
-
488
- /**
489
- * Whether this is a newly sent message (triggers appearance animation)
490
- */
491
- isNewMessage = input<boolean>(false);
492
-
493
- /**
494
- * Emits when attachment is clicked
495
- */
496
- attachmentClick = output<ChatAttachment>();
497
-
498
- /**
499
- * Emits when the message is long-pressed
500
- */
501
- longPress = output<void>();
502
-
503
- /**
504
- * Emits when the message is clicked (to toggle timestamp)
505
- */
506
- messageClick = output<void>();
507
-
508
- /**
509
- * Long press tracking
510
- */
511
- private longPressTimer: any = null;
512
- private longPressTriggered = false;
513
- private touchStartX = 0;
514
- private touchStartY = 0;
515
- private readonly LONG_PRESS_DURATION = 500; // ms
516
- private readonly MOVE_THRESHOLD = 10; // px
517
- private clickStartTime = 0;
518
-
519
- /**
520
- * Tap animation state
521
- */
522
- isTapped = false;
523
-
524
- /**
525
- * Handle attachment click
526
- */
527
- handleAttachmentClick(attachment: ChatAttachment): void {
528
- this.attachmentClick.emit(attachment);
529
- }
530
-
531
- /**
532
- * Handle click (for web/mouse support)
533
- */
534
- handleClick(event: MouseEvent): void {
535
- if (!this.clickable()) return;
536
-
537
- // Prevent double-firing on touch devices
538
- // Touch events will be handled by handleTouchEnd
539
- if ((event as any).sourceCapabilities?.firesTouchEvents) {
540
- return;
541
- }
542
-
543
- // Emit message click to toggle timestamp
544
- this.messageClick.emit();
545
- }
546
-
547
- /**
548
- * Handle touch start for long press detection
549
- */
550
- handleTouchStart(event: TouchEvent): void {
551
- if (!this.clickable()) return;
552
-
553
- // Add tap scale animation
554
- this.isTapped = true;
555
-
556
- this.longPressTriggered = false;
557
- this.clickStartTime = Date.now();
558
- this.touchStartX = event.touches[0].clientX;
559
- this.touchStartY = event.touches[0].clientY;
560
-
561
- // Start long press timer
562
- this.longPressTimer = setTimeout(() => {
563
- this.longPressTriggered = true;
564
- this.longPress.emit();
565
- }, this.LONG_PRESS_DURATION);
566
- }
567
-
568
- /**
569
- * Handle touch end to clear long press timer and detect short tap
570
- */
571
- handleTouchEnd(event: TouchEvent): void {
572
- // Remove tap scale animation
573
- this.isTapped = false;
574
-
575
- const pressDuration = Date.now() - this.clickStartTime;
576
-
577
- if (this.longPressTimer) {
578
- clearTimeout(this.longPressTimer);
579
- this.longPressTimer = null;
580
- }
581
-
582
- // If long press was triggered, prevent other actions
583
- if (this.longPressTriggered) {
584
- event.preventDefault();
585
- event.stopPropagation();
586
- this.longPressTriggered = false;
587
- return;
588
- }
589
-
590
- // Short tap (less than long press duration) - show timestamp
591
- if (this.clickable() && pressDuration < this.LONG_PRESS_DURATION) {
592
- // Check if moved too much
593
- const touch = event.changedTouches[0];
594
- const deltaX = Math.abs(touch.clientX - this.touchStartX);
595
- const deltaY = Math.abs(touch.clientY - this.touchStartY);
596
-
597
- if (deltaX <= this.MOVE_THRESHOLD && deltaY <= this.MOVE_THRESHOLD) {
598
- this.messageClick.emit();
599
- event.preventDefault();
600
- }
601
- }
602
- }
603
-
604
- /**
605
- * Handle touch move to cancel long press if moved too much
606
- */
607
- handleTouchMove(event: TouchEvent): void {
608
- if (!this.longPressTimer) return;
609
-
610
- const touch = event.touches[0];
611
- const deltaX = Math.abs(touch.clientX - this.touchStartX);
612
- const deltaY = Math.abs(touch.clientY - this.touchStartY);
613
-
614
- // Cancel long press if moved too far
615
- if (deltaX > this.MOVE_THRESHOLD || deltaY > this.MOVE_THRESHOLD) {
616
- clearTimeout(this.longPressTimer);
617
- this.longPressTimer = null;
618
- this.longPressTriggered = false;
619
- // Remove tap animation if moved too far
620
- this.isTapped = false;
621
- }
622
- }
623
-
624
- /**
625
- * Handle context menu (right-click on desktop) to trigger long press action
626
- */
627
- handleContextMenu(event: Event): void {
628
- if (!this.clickable()) return;
629
- event.preventDefault();
630
- this.longPress.emit();
631
- }
632
- }
633
-
@@ -1,7 +0,0 @@
1
- export { DsMobileMessageBubbleComponent, type ChatAttachment } from './ds-mobile-message-bubble';
2
-
3
-
4
-
5
-
6
-
7
-