@capillarytech/creatives-library 9.0.15-alpha.0 → 9.0.15-alpha.3

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 (132) hide show
  1. package/constants/unified.js +29 -0
  2. package/global-styles.js +1 -1
  3. package/package.json +1 -1
  4. package/services/tests/api.test.js +35 -20
  5. package/utils/commonUtils.js +19 -1
  6. package/utils/rcsPayloadUtils.js +92 -0
  7. package/utils/templateVarUtils.js +201 -0
  8. package/utils/tests/rcsPayloadUtils.test.js +226 -0
  9. package/utils/tests/templateVarUtils.test.js +204 -0
  10. package/v2Components/CapActionButton/constants.js +8 -1
  11. package/v2Components/CapActionButton/index.js +202 -144
  12. package/v2Components/CapActionButton/index.scss +232 -14
  13. package/v2Components/CapActionButton/messages.js +19 -3
  14. package/v2Components/CapActionButton/tests/index.test.js +42 -18
  15. package/v2Components/CapImageUpload/index.js +2 -2
  16. package/v2Components/CapTagList/index.js +10 -0
  17. package/v2Components/CommonTestAndPreview/CustomValuesEditor.js +70 -48
  18. package/v2Components/CommonTestAndPreview/DeliverySettings/DeliverySettings.scss +8 -2
  19. package/v2Components/CommonTestAndPreview/DeliverySettings/ModifyDeliverySettings.js +214 -21
  20. package/v2Components/CommonTestAndPreview/DeliverySettings/constants.js +16 -0
  21. package/v2Components/CommonTestAndPreview/DeliverySettings/index.js +83 -9
  22. package/v2Components/CommonTestAndPreview/DeliverySettings/messages.js +30 -0
  23. package/v2Components/CommonTestAndPreview/DeliverySettings/utils/parseSenderDetailsResponse.js +60 -11
  24. package/v2Components/CommonTestAndPreview/SendTestMessage.js +10 -5
  25. package/v2Components/CommonTestAndPreview/UnifiedPreview/RcsPreviewContent.js +202 -22
  26. package/v2Components/CommonTestAndPreview/UnifiedPreview/_unifiedPreview.scss +381 -80
  27. package/v2Components/CommonTestAndPreview/UnifiedPreview/index.js +155 -8
  28. package/v2Components/CommonTestAndPreview/_commonTestAndPreview.scss +11 -0
  29. package/v2Components/CommonTestAndPreview/constants.js +38 -2
  30. package/v2Components/CommonTestAndPreview/index.js +761 -222
  31. package/v2Components/CommonTestAndPreview/messages.js +45 -3
  32. package/v2Components/CommonTestAndPreview/previewApiUtils.js +59 -0
  33. package/v2Components/CommonTestAndPreview/sagas.js +25 -6
  34. package/v2Components/CommonTestAndPreview/tests/CommonTestAndPreview.addTestCustomer.test.js +1 -0
  35. package/v2Components/CommonTestAndPreview/tests/CustomValuesEditor.test.js +284 -267
  36. package/v2Components/CommonTestAndPreview/tests/DeliverySettings/ModifyDeliverySettings.test.js +231 -65
  37. package/v2Components/CommonTestAndPreview/tests/DeliverySettings/index.test.js +118 -5
  38. package/v2Components/CommonTestAndPreview/tests/DeliverySettings/utils/parseSenderDetailsResponse.test.js +341 -0
  39. package/v2Components/CommonTestAndPreview/tests/PreviewSection.test.js +8 -1
  40. package/v2Components/CommonTestAndPreview/tests/SendTestMessage.test.js +34 -13
  41. package/v2Components/CommonTestAndPreview/tests/UnifiedPreview/RcsPreviewContent.test.js +281 -283
  42. package/v2Components/CommonTestAndPreview/tests/UnifiedPreview/index.test.js +199 -1
  43. package/v2Components/CommonTestAndPreview/tests/index.test.js +133 -4
  44. package/v2Components/CommonTestAndPreview/tests/previewApiUtils.test.js +67 -0
  45. package/v2Components/CommonTestAndPreview/tests/sagas.test.js +31 -24
  46. package/v2Components/CommonTestAndPreview/utils.js +84 -0
  47. package/v2Components/SmsFallback/SmsFallbackLocalSelector.js +91 -0
  48. package/v2Components/SmsFallback/constants.js +94 -0
  49. package/v2Components/SmsFallback/index.js +958 -0
  50. package/v2Components/SmsFallback/index.scss +266 -0
  51. package/v2Components/SmsFallback/messages.js +78 -0
  52. package/v2Components/SmsFallback/smsFallbackUtils.js +120 -0
  53. package/v2Components/SmsFallback/tests/SmsFallbackLocalSelector.test.js +50 -0
  54. package/v2Components/SmsFallback/tests/rcsSmsFallback.acceptance.test.js +147 -0
  55. package/v2Components/SmsFallback/tests/smsFallbackHandlers.test.js +304 -0
  56. package/v2Components/SmsFallback/tests/smsFallbackUi.test.js +208 -0
  57. package/v2Components/SmsFallback/tests/smsFallbackUtils.test.js +309 -0
  58. package/v2Components/SmsFallback/tests/useLocalTemplateList.test.js +422 -0
  59. package/v2Components/SmsFallback/useLocalTemplateList.js +92 -0
  60. package/v2Components/TemplatePreview/_templatePreview.scss +45 -25
  61. package/v2Components/TemplatePreview/constants.js +2 -0
  62. package/v2Components/TemplatePreview/index.js +147 -32
  63. package/v2Components/TemplatePreview/tests/index.test.js +142 -0
  64. package/v2Components/TestAndPreviewSlidebox/CustomValuesEditor.js +6 -6
  65. package/v2Components/TestAndPreviewSlidebox/index.js +13 -1
  66. package/v2Components/TestAndPreviewSlidebox/sagas.js +11 -4
  67. package/v2Components/TestAndPreviewSlidebox/tests/saga.test.js +3 -1
  68. package/v2Components/VarSegmentMessageEditor/constants.js +2 -0
  69. package/v2Components/VarSegmentMessageEditor/index.js +125 -0
  70. package/v2Components/VarSegmentMessageEditor/index.scss +46 -0
  71. package/v2Containers/CommunicationFlow/Tests/CommunicationFlow.test.js +4 -1
  72. package/v2Containers/CommunicationFlow/index.js +3 -3
  73. package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/Tests/DeliverySettingsSection.test.js +4 -0
  74. package/v2Containers/CommunicationFlow/steps/DeliverySettingsStep/Tests/SenderDetails.test.js +20 -20
  75. package/v2Containers/CreativesContainer/CreativesSlideBoxWrapper.js +17 -0
  76. package/v2Containers/CreativesContainer/SlideBoxContent.js +37 -4
  77. package/v2Containers/CreativesContainer/SlideBoxFooter.js +14 -5
  78. package/v2Containers/CreativesContainer/SlideBoxHeader.js +36 -5
  79. package/v2Containers/CreativesContainer/constants.js +11 -0
  80. package/v2Containers/CreativesContainer/embeddedSlideboxUtils.js +79 -0
  81. package/v2Containers/CreativesContainer/index.js +323 -104
  82. package/v2Containers/CreativesContainer/index.scss +83 -1
  83. package/v2Containers/CreativesContainer/tests/SlideBoxContent.localTemplates.test.js +90 -0
  84. package/v2Containers/CreativesContainer/tests/SlideBoxFooter.test.js +79 -34
  85. package/v2Containers/CreativesContainer/tests/SlideBoxHeader.test.js +79 -16
  86. package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxContent.test.js.snap +8 -0
  87. package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxHeader.test.js.snap +333 -90
  88. package/v2Containers/CreativesContainer/tests/__snapshots__/index.test.js.snap +20 -15
  89. package/v2Containers/CreativesContainer/tests/embeddedSlideboxUtils.test.js +258 -0
  90. package/v2Containers/CreativesContainer/tests/index.test.js +71 -9
  91. package/v2Containers/CreativesContainer/tests/useLocalTemplatesProp.test.js +125 -0
  92. package/v2Containers/MobilePush/Create/test/saga.test.js +2 -2
  93. package/v2Containers/Rcs/constants.js +131 -11
  94. package/v2Containers/Rcs/index.js +2685 -832
  95. package/v2Containers/Rcs/index.scss +443 -8
  96. package/v2Containers/Rcs/messages.js +45 -6
  97. package/v2Containers/Rcs/rcsLibraryHydrationUtils.js +227 -0
  98. package/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +74176 -39409
  99. package/v2Containers/Rcs/tests/__snapshots__/utils.test.js.snap +10 -74
  100. package/v2Containers/Rcs/tests/index.test.js +151 -40
  101. package/v2Containers/Rcs/tests/mockData.js +38 -0
  102. package/v2Containers/Rcs/tests/rcsLibraryHydrationUtils.test.js +318 -0
  103. package/v2Containers/Rcs/tests/utils.test.js +643 -30
  104. package/v2Containers/Rcs/utils.js +466 -12
  105. package/v2Containers/Sms/Create/index.js +115 -48
  106. package/v2Containers/Sms/smsFormDataHelpers.js +67 -0
  107. package/v2Containers/Sms/tests/smsFormDataHelpers.test.js +253 -0
  108. package/v2Containers/SmsTrai/Create/index.js +9 -4
  109. package/v2Containers/SmsTrai/Edit/constants.js +2 -0
  110. package/v2Containers/SmsTrai/Edit/index.js +678 -169
  111. package/v2Containers/SmsTrai/Edit/index.scss +126 -0
  112. package/v2Containers/SmsTrai/Edit/messages.js +14 -4
  113. package/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +5615 -3014
  114. package/v2Containers/SmsWrapper/index.js +37 -8
  115. package/v2Containers/TagList/index.js +6 -0
  116. package/v2Containers/Templates/TemplatesActionBar.js +101 -0
  117. package/v2Containers/Templates/_templates.scss +196 -12
  118. package/v2Containers/Templates/actions.js +11 -0
  119. package/v2Containers/Templates/constants.js +2 -0
  120. package/v2Containers/Templates/index.js +131 -59
  121. package/v2Containers/Templates/sagas.js +57 -13
  122. package/v2Containers/Templates/tests/TemplatesActionBar.test.js +120 -0
  123. package/v2Containers/Templates/tests/__snapshots__/index.test.js.snap +1060 -1015
  124. package/v2Containers/Templates/tests/sagas.test.js +199 -16
  125. package/v2Containers/Templates/tests/smsTemplatesListApi.test.js +180 -0
  126. package/v2Containers/Templates/utils/smsTemplatesListApi.js +79 -0
  127. package/v2Containers/TemplatesV2/TemplatesV2.style.js +72 -1
  128. package/v2Containers/TemplatesV2/index.js +86 -23
  129. package/v2Containers/TemplatesV2/tests/TemplatesV2.localTemplates.test.js +131 -0
  130. package/v2Containers/WeChat/MapTemplates/test/saga.test.js +9 -9
  131. package/v2Containers/Whatsapp/index.js +3 -20
  132. package/v2Containers/Whatsapp/tests/__snapshots__/index.test.js.snap +578 -34
@@ -2,7 +2,7 @@
2
2
 
3
3
  /**
4
4
  * UnifiedPreview Styles
5
- *
5
+ *
6
6
  * Consistent styling for preview across all channels
7
7
  */
8
8
 
@@ -11,25 +11,24 @@
11
11
  height: 100%;
12
12
  display: flex;
13
13
  flex-direction: column;
14
- background: $CAP_WHITE;
15
14
  overflow: hidden;
16
-
15
+
17
16
  // Preview Chrome wrapper (matches old TestAndPreviewSlidebox design)
18
17
  .preview-chrome {
19
18
  background: $CAP_WHITE;
20
19
  overflow: hidden;
21
-
20
+
22
21
  .preview-divider {
23
22
  margin: 0;
24
23
  }
25
-
24
+
26
25
  .preview-header {
27
26
  display: flex;
28
27
  justify-content: space-between;
29
28
  align-items: center;
30
29
  padding: $CAP_SPACE_08 $CAP_SPACE_16 $CAP_SPACE_06 $CAP_SPACE_16;
31
30
  background: $CAP_G09;
32
-
31
+
33
32
  .preview-for {
34
33
  font-size: $FONT_SIZE_M;
35
34
  color: #595959;
@@ -39,20 +38,20 @@
39
38
  margin-left: $CAP_SPACE_04;
40
39
  }
41
40
  }
42
-
41
+
43
42
  .device-toggle {
44
43
  display: flex;
45
44
  gap: $CAP_SPACE_08;
46
45
  background-color: #e0e0e0;
47
46
  padding: $CAP_SPACE_06 $CAP_SPACE_08;
48
47
  border-radius: $CAP_SPACE_08;
49
-
48
+
50
49
  .anticon {
51
50
  padding: $CAP_SPACE_04;
52
51
  border-radius: $CAP_SPACE_04;
53
52
  cursor: pointer;
54
53
  color: #595959;
55
-
54
+
56
55
  &.active {
57
56
  background-color: $CAP_WHITE;
58
57
  color: #262626;
@@ -62,7 +61,27 @@
62
61
  }
63
62
  }
64
63
  }
65
-
64
+
65
+ &.unified-preview-rcs-tabs {
66
+ .ant-tabs-nav {
67
+ margin: 0;
68
+ padding: 0 $CAP_SPACE_16;
69
+ }
70
+
71
+ // Prevent white hover/active backgrounds from default antd styles
72
+ .ant-tabs-tab,
73
+ .ant-tabs-tab:hover,
74
+ .ant-tabs-tab-active {
75
+ background: transparent;
76
+ }
77
+
78
+ .ant-tabs-tab-btn,
79
+ .ant-tabs-tab-btn:hover,
80
+ .ant-tabs-tab-btn:active {
81
+ background: transparent;
82
+ }
83
+ }
84
+
66
85
  // Preview Content Container
67
86
  .preview-content-container {
68
87
  flex: 1;
@@ -75,25 +94,33 @@
75
94
  .preview-content-container-no-header {
76
95
  background-color: $CAP_WHITE;
77
96
  }
78
-
97
+
79
98
  // Device Frames
80
99
  .unified-preview-frame {
81
100
  width: 100%;
82
101
  display: flex;
83
102
  justify-content: center;
84
-
103
+
85
104
  .device-frame {
86
105
  background: $CAP_WHITE;
87
106
  border-radius: $CAP_SPACE_08;
88
107
  box-shadow: 0 $CAP_SPACE_04 $CAP_SPACE_12 rgba(0, 0, 0, 0.15);
89
108
  overflow: hidden;
90
109
  transition: all 0.3s ease;
91
-
110
+ // iOS Safari fails to clip a `transform`ed descendant (.rcs-carousel-panel
111
+ // uses translateX(-50%) to center itself) to this ancestor's border-radius —
112
+ // its white background bleeds past the rounded edge on real devices, even
113
+ // though overflow:hidden clips it correctly everywhere else. Forcing Safari
114
+ // onto its masking render path (instead of the buggy transform+overflow-clip
115
+ // path) fixes this; no-op on every other browser.
116
+ -webkit-mask-image: -webkit-radial-gradient(white, black);
117
+ mask-image: radial-gradient(white, black);
118
+
92
119
  // Desktop Frame
93
120
  &.device-frame-desktop {
94
121
  width: 100%;
95
122
  min-height: 42.857rem;
96
-
123
+
97
124
  .desktop-chrome {
98
125
  height: $CAP_SPACE_40;
99
126
  background: $CAP_G12;
@@ -102,30 +129,30 @@
102
129
  align-items: center;
103
130
  padding: 0 $CAP_SPACE_12;
104
131
  gap: $CAP_SPACE_12;
105
-
132
+
106
133
  .chrome-dots {
107
134
  display: flex;
108
135
  gap: $CAP_SPACE_06;
109
-
136
+
110
137
  .dot {
111
138
  width: $CAP_SPACE_12;
112
139
  height: $CAP_SPACE_12;
113
140
  border-radius: 50%;
114
-
141
+
115
142
  &.dot-close {
116
143
  background: #ff5f56;
117
144
  }
118
-
145
+
119
146
  &.dot-minimize {
120
147
  background: #ffbd2e;
121
148
  }
122
-
149
+
123
150
  &.dot-maximize {
124
151
  background: #27c93f;
125
152
  }
126
153
  }
127
154
  }
128
-
155
+
129
156
  .chrome-address-bar {
130
157
  flex: 1;
131
158
  background: $CAP_WHITE;
@@ -135,25 +162,25 @@
135
162
  color: #8c8c8c;
136
163
  }
137
164
  }
138
-
165
+
139
166
  .device-content {
140
167
  min-height: 40rem;
141
168
  background: $CAP_WHITE;
142
169
  }
143
170
  }
144
-
171
+
145
172
  // Tablet Frame
146
173
  &.device-frame-tablet {
147
174
  width: 54.857rem;
148
175
  max-width: 90%;
149
-
176
+
150
177
  .tablet-chrome {
151
178
  height: $CAP_SPACE_24;
152
179
  background: #333333;
153
180
  display: flex;
154
181
  align-items: center;
155
182
  justify-content: center;
156
-
183
+
157
184
  .tablet-camera {
158
185
  width: $CAP_SPACE_08;
159
186
  height: $CAP_SPACE_08;
@@ -162,19 +189,19 @@
162
189
  border: $CAP_SPACE_01 solid #666666;
163
190
  }
164
191
  }
165
-
192
+
166
193
  .device-content {
167
194
  min-height: 73.143rem;
168
195
  background: $CAP_WHITE;
169
196
  }
170
-
197
+
171
198
  .tablet-footer {
172
199
  height: 3.571rem;
173
200
  background: #333333;
174
201
  display: flex;
175
202
  align-items: center;
176
203
  justify-content: center;
177
-
204
+
178
205
  .home-button {
179
206
  width: $CAP_SPACE_40;
180
207
  height: $CAP_SPACE_40;
@@ -184,19 +211,19 @@
184
211
  }
185
212
  }
186
213
  }
187
-
214
+
188
215
  // Mobile Frame
189
216
  &.device-frame-mobile {
190
217
  width: 26.786rem;
191
218
  max-width: 90%;
192
-
219
+
193
220
  .mobile-chrome {
194
221
  height: $CAP_SPACE_24;
195
222
  background: #000000;
196
223
  display: flex;
197
224
  align-items: center;
198
225
  justify-content: center;
199
-
226
+
200
227
  .mobile-notch {
201
228
  width: 10.714rem;
202
229
  height: 1.571rem;
@@ -204,19 +231,19 @@
204
231
  border-radius: 0 0 $CAP_SPACE_12 $CAP_SPACE_12;
205
232
  }
206
233
  }
207
-
234
+
208
235
  .device-content {
209
236
  min-height: 47.643rem;
210
237
  background: $CAP_WHITE;
211
238
  }
212
-
239
+
213
240
  .mobile-footer {
214
241
  height: $CAP_SPACE_24;
215
242
  background: #000000;
216
243
  display: flex;
217
244
  align-items: center;
218
245
  justify-content: center;
219
-
246
+
220
247
  .home-indicator {
221
248
  width: $CAP_SPACE_80;
222
249
  height: $CAP_SPACE_04;
@@ -228,7 +255,7 @@
228
255
  }
229
256
  }
230
257
  }
231
-
258
+
232
259
  // Channel Preview Placeholders (Phase 5)
233
260
  .channel-preview-placeholder {
234
261
  display: flex;
@@ -238,7 +265,7 @@
238
265
  padding: $CAP_SPACE_60 $CAP_SPACE_24;
239
266
  text-align: center;
240
267
  min-height: 28.571rem;
241
-
268
+
242
269
  .question-circle {
243
270
  font-size: $CAP_SPACE_48;
244
271
  color: $CAP_COLOR_16;
@@ -249,13 +276,13 @@
249
276
  font-weight: 600;
250
277
  color: #262626;
251
278
  }
252
-
279
+
253
280
  p {
254
281
  margin-top: $CAP_SPACE_08;
255
282
  font-size: $FONT_SIZE_M;
256
283
  color: #8c8c8c;
257
284
  }
258
-
285
+
259
286
  .preview-subject {
260
287
  margin-top: $CAP_SPACE_24;
261
288
  padding: $CAP_SPACE_12 $CAP_SPACE_16;
@@ -264,26 +291,26 @@
264
291
  text-align: left;
265
292
  width: 100%;
266
293
  max-width: 35.714rem;
267
-
294
+
268
295
  strong {
269
296
  color: #595959;
270
297
  margin-right: $CAP_SPACE_08;
271
298
  }
272
299
  }
273
-
300
+
274
301
  .preview-body-placeholder {
275
302
  margin-top: $CAP_SPACE_12;
276
303
  padding: $CAP_SPACE_08 $CAP_SPACE_12;
277
304
  background: #fafafa;
278
305
  border: $CAP_SPACE_01 dashed $CAP_COLOR_16;
279
306
  border-radius: $CAP_SPACE_04;
280
-
307
+
281
308
  small {
282
309
  color: #8c8c8c;
283
310
  }
284
311
  }
285
312
  }
286
-
313
+
287
314
  // Loading State
288
315
  &.unified-preview-loading {
289
316
  .preview-loading-container {
@@ -293,14 +320,14 @@
293
320
  justify-content: center;
294
321
  gap: $CAP_SPACE_16;
295
322
  min-height: 28.571rem;
296
-
323
+
297
324
  .loading-text {
298
325
  font-size: $FONT_SIZE_M;
299
326
  color: #8c8c8c;
300
327
  }
301
328
  }
302
329
  }
303
-
330
+
304
331
  // Error State
305
332
  &.unified-preview-error {
306
333
  .preview-error-container {
@@ -311,7 +338,7 @@
311
338
  justify-content: center;
312
339
  gap: $CAP_SPACE_16;
313
340
  min-height: 28.571rem;
314
-
341
+
315
342
  .exclamation-circle {
316
343
  font-size: $CAP_SPACE_48;
317
344
  color: #ff4d4f;
@@ -321,7 +348,7 @@
321
348
  font-weight: 600;
322
349
  color: #262626;
323
350
  }
324
-
351
+
325
352
  .error-message {
326
353
  font-size: $FONT_SIZE_M;
327
354
  color: #ff4d4f;
@@ -330,7 +357,7 @@
330
357
  }
331
358
  }
332
359
  }
333
-
360
+
334
361
  // Preview Metadata
335
362
  .preview-metadata {
336
363
  padding: $CAP_SPACE_12 $CAP_SPACE_24;
@@ -340,7 +367,7 @@
340
367
  color: #8c8c8c;
341
368
  display: flex;
342
369
  gap: $CAP_SPACE_16;
343
-
370
+
344
371
  .metadata-item {
345
372
  display: flex;
346
373
  gap: $CAP_SPACE_04;
@@ -532,7 +559,7 @@
532
559
  font-weight: 600;
533
560
  color: #262626;
534
561
  }
535
-
562
+
536
563
  .error-message {
537
564
  font-size: $FONT_SIZE_M;
538
565
  color: #ff4d4f;
@@ -571,9 +598,12 @@
571
598
  transform: translateX(-50%);
572
599
  width: 100%;
573
600
  max-width: 26.786rem;
601
+ min-width: 0; // flex descendant overflow: allow shrink inside narrow screen
574
602
  height: calc(100% - 4.5rem);
575
603
  display: flex;
576
604
  flex-direction: column;
605
+ overflow-x: hidden;
606
+ box-sizing: border-box;
577
607
 
578
608
  &.sms-content-overlay-android {
579
609
  height: calc(100% - 3.8rem);
@@ -741,7 +771,7 @@
741
771
  font-weight: 600;
742
772
  color: #262626;
743
773
  }
744
-
774
+
745
775
  .sms-error-message {
746
776
  font-size: $FONT_SIZE_M;
747
777
  color: #ff4d4f;
@@ -763,13 +793,280 @@
763
793
  }
764
794
  }
765
795
 
796
+ // RCS Carousel card styles — scoped to .rcs-carousel-panel (which lives outside the
797
+ // overflow-x:hidden overlay so horizontal scroll events reach .scroll-container freely).
798
+ .rcs-device-container {
799
+ .rcs-carousel-panel {
800
+ position: absolute;
801
+ // Centered via left/right auto-margins instead of left:50% + translateX(-50%) —
802
+ // a `transform` on this element put every rounded+overflow:hidden box nested
803
+ // inside it (this panel's own corners, the card corners, the image corners...)
804
+ // in a transformed stacking context that iOS Safari fails to clip correctly,
805
+ // letting their square corners/backgrounds bleed past the rounded edges. Plain
806
+ // auto-margin centering has no such bug.
807
+ left: 0;
808
+ right: 0;
809
+ margin-left: auto;
810
+ margin-right: auto;
811
+ width: 100%;
812
+ max-width: 26.786rem;
813
+ box-sizing: border-box;
814
+ top: 4.143rem;
815
+ height: calc(100% - 2.5rem);
816
+ display: flex;
817
+ flex-direction: column;
818
+ padding-top: 5.857rem; // nav (3.428rem) + date separator (~2.429rem)
819
+ padding-bottom: $CAP_SPACE_16;
820
+ padding-left: 0.4rem;
821
+ padding-right: 0.4rem;
822
+ background-color: $CAP_WHITE;
823
+ background-clip: content-box;
824
+ border-bottom-left-radius: 2.429rem;
825
+ border-bottom-right-radius: 2.429rem;
826
+ // background-clip only clips the background fill to these rounded corners —
827
+ // it does NOT clip child content, so message/card boxes could render past the
828
+ // rounded edge regardless of browser. This doesn't affect the horizontal touch
829
+ // scroll .scroll-container needs: that workaround was about not nesting inside
830
+ // the *other* sibling overlay (.sms-content-overlay's overflow-x:hidden), not
831
+ // about this element's own overflow.
832
+ overflow: hidden;
833
+
834
+ &.rcs-carousel-panel-android {
835
+ top: 3.1rem;
836
+ border-radius: 4rem;
837
+ }
838
+
839
+ &.rcs-carousel-panel-ios {
840
+ height: calc(100% - 4.2rem);
841
+ }
842
+
843
+ .rcs-carousel-timestamp {
844
+ font-size: $FONT_SIZE_S;
845
+ color: #8c8c8c;
846
+ align-self: flex-end;
847
+ padding-right: $CAP_SPACE_04;
848
+ padding-top: $CAP_SPACE_04;
849
+ }
850
+
851
+ .msg-container-carousel {
852
+ display: flex;
853
+ flex-direction: column;
854
+ width: 100%;
855
+ padding: 0 $CAP_SPACE_16;
856
+
857
+ .scroll-container {
858
+ display: flex;
859
+ flex-wrap: nowrap;
860
+ gap: 0.75rem;
861
+ overflow-x: auto;
862
+ overflow-y: hidden;
863
+ width: 100%;
864
+ scrollbar-width: none;
865
+
866
+ &::-webkit-scrollbar {
867
+ display: none;
868
+ }
869
+ }
870
+ }
871
+
872
+ // Wraps the card + its CTA bar so both scroll horizontally together as one unit,
873
+ // while remaining two visually distinct, separately-rounded elements (Figma reference —
874
+ // the CTA bar is its own floating pill below the card, not part of it).
875
+ .rcs-carousel-item {
876
+ display: flex;
877
+ flex-direction: column;
878
+ gap: $CAP_SPACE_04;
879
+ // Ensure item width is stable and does not shrink to text width
880
+ flex: 0 0 15.375rem; // ~246px; fills container leaving ~50% of next card peeking
881
+ margin-right: 0; // spacing handled by scroll-container gap
882
+ }
883
+
884
+ .message-pop-carousel {
885
+ // Match TemplatePreview carousel card look (big card + subtle shadow)
886
+ background-color: $CAP_WHITE;
887
+ border: 1px solid $CAP_G07; // #dfe2e7 — keeps the card visible against the
888
+ // chat background when there's no photo yet to provide contrast (Figma empty state)
889
+ border-radius: $CAP_SPACE_04; // 4px (Figma RCS carousel card corner)
890
+ width: 100%;
891
+ padding: 0;
892
+ color: $CAP_G01;
893
+ overflow: hidden;
894
+ box-shadow: 0 0 0.625rem 0 rgba(0, 0, 0, 0.08);
895
+ position: relative;
896
+ }
897
+
898
+ .whatsapp-content {
899
+ font-family: Roboto, 'Open Sans', sans-serif;
900
+ margin: 0;
901
+ width: 100%;
902
+ }
903
+
904
+ // Height follows width × aspect-ratio; inline style from carouselPreviewDimensions overrides fallback.
905
+ .whatsapp-image.rcs-carousel-media-wrap {
906
+ width: 100%;
907
+ height: auto;
908
+ aspect-ratio: 1280 / 720; // MEDIUM_MEDIUM image fallback when dimensions not passed
909
+ display: block;
910
+ overflow: hidden;
911
+ border-radius: $CAP_SPACE_04 $CAP_SPACE_04 0 0; // 4px (Figma)
912
+ margin-bottom: 0;
913
+
914
+ // CapImage (antd Image) applies className on wrapper; ensure inner img is constrained too.
915
+ img,
916
+ .ant-image-img {
917
+ width: 100%;
918
+ height: 100%;
919
+ object-fit: cover;
920
+ border-radius: inherit;
921
+ display: block;
922
+ }
923
+
924
+ // Plain <img> in RCS carousel preview (not CapImage)
925
+ .rcs-carousel-img {
926
+ width: 100%;
927
+ height: 100%;
928
+ object-fit: cover;
929
+ border-radius: inherit;
930
+ display: block;
931
+ }
932
+ }
933
+
934
+ .video-preview {
935
+ position: relative;
936
+ width: 100%;
937
+ margin-bottom: 0;
938
+
939
+ .whatsapp-image.rcs-carousel-media-wrap {
940
+ width: 100%;
941
+ height: auto;
942
+ aspect-ratio: 796 / 448; // MEDIUM_MEDIUM video thumbnail fallback
943
+ margin-bottom: 0;
944
+
945
+ img,
946
+ .ant-image-img,
947
+ .rcs-carousel-img {
948
+ width: 100%;
949
+ height: 100%;
950
+ object-fit: cover;
951
+ border-radius: inherit;
952
+ display: block;
953
+ }
954
+ }
955
+
956
+ .icon-position {
957
+ position: absolute;
958
+ top: 50%;
959
+ left: 50%;
960
+ transform: translate(-50%, -50%);
961
+ display: flex;
962
+ align-items: center;
963
+ justify-content: center;
964
+
965
+ .video-icon {
966
+ width: $CAP_SPACE_48;
967
+ height: $CAP_SPACE_48;
968
+ }
969
+ }
970
+ }
971
+
972
+ // CapTooltip shrink-wraps its wrapper/trigger by default and forces `display: inline-block`
973
+ // inline on the trigger span, so .video-preview's width:100% collapses to content width
974
+ // unless these are stretched to fill the card (inline style needs !important to override).
975
+ .rcs-carousel-video-tooltip-wrapper {
976
+ display: block;
977
+ width: 100%;
978
+ }
979
+
980
+ .rcs-carousel-video-tooltip-trigger {
981
+ display: block !important;
982
+ width: 100%;
983
+ }
984
+
985
+ .carousel-content {
986
+ padding: 0.625rem 0.75rem; // 10px 12px
987
+ width: 100%;
988
+ background-color: $CAP_G08; // #ebecf0 (Figma: grey info panel, not white)
989
+ white-space: normal; // override scroll-container's nowrap so text can wrap
990
+ display: flex;
991
+ flex-direction: column;
992
+ border-bottom-left-radius: 0.25rem; // 4px — this is the card's own bottom edge;
993
+ border-bottom-right-radius: 0.25rem; // the CTA bar below is a separate element (Figma)
994
+
995
+ // Title/body typography via CapLabel type (label1 / label2, etc.)
996
+ .carousel-title {
997
+ margin-bottom: 0.25rem; // 4px
998
+ display: block;
999
+ overflow: visible;
1000
+ white-space: normal;
1001
+ overflow-wrap: anywhere;
1002
+ color: $CAP_G04; // #5e6c84 (Figma)
1003
+ font-weight: $FONT_WEIGHT_BOLD;
1004
+ }
1005
+
1006
+ .carousel-message {
1007
+ display: block;
1008
+ overflow: visible;
1009
+ white-space: normal;
1010
+ overflow-wrap: anywhere;
1011
+ color: $FONT_COLOR_03; // #97a0af (Figma)
1012
+ font-weight: $FONT_WEIGHT_REGULAR;
1013
+ }
1014
+
1015
+ .rcs-carousel-field-placeholder {
1016
+ color: $CAP_G05;
1017
+ font-weight: $FONT_WEIGHT_REGULAR;
1018
+ }
1019
+ }
1020
+
1021
+ // Divider between message body and suggestions — subtle gray on the gray bubble
1022
+ .whatsapp-divider {
1023
+ margin: 0;
1024
+ border-top: 1px solid $CAP_G07;
1025
+ }
1026
+
1027
+ // Inside a carousel card (white bg) dividers should stay white
1028
+ .message-pop-carousel .whatsapp-divider {
1029
+ border-top: 1px solid $CAP_WHITE;
1030
+ }
1031
+
1032
+ // Own floating pill(s) below the card (NOT part of .message-pop-carousel) — sits in
1033
+ // .rcs-carousel-item, separated from the card by that wrapper's `gap` (Figma reference).
1034
+ .rcs-carousel-cta-stack.cap-row-v2 {
1035
+ display: flex;
1036
+ flex-direction: column;
1037
+ flex-wrap: nowrap;
1038
+ width: 100%;
1039
+ gap: 0.25rem;
1040
+ box-sizing: border-box;
1041
+ align-items: stretch;
1042
+ }
1043
+
1044
+ .rcs-cta-preview--carousel-bar {
1045
+ display: flex;
1046
+ align-items: center;
1047
+ justify-content: center;
1048
+ gap: 0.375rem;
1049
+ width: 100%;
1050
+ margin: 0;
1051
+ padding: 0.625rem 0.75rem;
1052
+ box-sizing: border-box;
1053
+ background-color: $CAP_G08; // #ebecf0 (Figma: grey "Call Now" pill, not white)
1054
+ border-radius: 0.25rem;
1055
+ font-size: $FONT_SIZE_M;
1056
+ font-weight: $FONT_WEIGHT_MEDIUM;
1057
+ color: $CAP_G04; // #5e6c84 (Figma)
1058
+ text-align: center;
1059
+ }
1060
+ }
1061
+ }
1062
+
766
1063
  // WhatsApp Preview Content Styles (Phase 8)
767
1064
  // All WhatsApp styles wrapped in parent class for increased specificity
768
1065
  // This prevents other CSS (like CapLabel) from overriding WhatsApp-specific styles
769
1066
  .whatsapp-preview-wrapper {
770
1067
  // Using same CSS classes as TemplatePreview for consistency
771
1068
  // Styles are copied from TemplatePreview/_templatePreview.scss to ensure they work
772
-
1069
+
773
1070
  .shell-v2-whatsapp {
774
1071
  position: relative;
775
1072
  -webkit-transform: translate(-50%);
@@ -844,23 +1141,23 @@
844
1141
  }
845
1142
 
846
1143
  // WhatsApp message pop styles (matching TemplatePreview)
847
- &.whatsapp-message-pop {
1144
+ &.whatsapp-message-pop,
1145
+ &.whatsapp-message-pop-carousel {
848
1146
  padding: $CAP_SPACE_04 0 $CAP_SPACE_08;
849
1147
  border-radius: $CAP_SPACE_06;
850
1148
  background-color: $CAP_WHITE;
851
- width: 88%;
852
1149
  left: 0;
853
1150
  }
854
1151
 
1152
+ &.whatsapp-message-pop {
1153
+ width: 88%;
1154
+ }
1155
+
855
1156
  // WhatsApp carousel message pop styles
856
1157
  &.whatsapp-message-pop-carousel {
857
- padding: $CAP_SPACE_04 0 $CAP_SPACE_08;
858
- border-radius: $CAP_SPACE_06;
859
- background-color: $CAP_WHITE;
860
1158
  width: 10.4rem;
861
1159
  cursor: pointer;
862
1160
  flex-shrink: 0;
863
- left: 0;
864
1161
  }
865
1162
  }
866
1163
  }
@@ -925,7 +1222,7 @@
925
1222
  line-height: 1rem;
926
1223
  font-family: Roboto, 'Open Sans', sans-serif;
927
1224
  }
928
-
1225
+
929
1226
  .whatsapp-template-footer-preview {
930
1227
  // From WhatsApp/index.scss: color: $CAP_G04, but use white for preview
931
1228
  color: $CAP_G01;
@@ -1007,19 +1304,19 @@
1007
1304
  color: #8c8c8c;
1008
1305
  font-size: $FONT_SIZE_M;
1009
1306
  }
1010
-
1307
+
1011
1308
  .whatsapp-error-text {
1012
1309
  font-size: $FONT_SIZE_L;
1013
1310
  font-weight: 600;
1014
1311
  color: #262626;
1015
1312
  }
1016
-
1313
+
1017
1314
  .whatsapp-error-message {
1018
1315
  font-size: $FONT_SIZE_M;
1019
1316
  color: #ff4d4f;
1020
1317
  text-align: center;
1021
1318
  }
1022
-
1319
+
1023
1320
  .whatsapp-no-content {
1024
1321
  color: #8c8c8c;
1025
1322
  font-size: $FONT_SIZE_M;
@@ -1071,14 +1368,14 @@
1071
1368
  color: #8c8c8c;
1072
1369
  margin-top: $CAP_SPACE_04;
1073
1370
  }
1074
-
1371
+
1075
1372
  .url-preview {
1076
1373
  font-size: $FONT_SIZE_S;
1077
1374
  color: #1890ff;
1078
1375
  word-break: break-all;
1079
1376
  }
1080
1377
  }
1081
-
1378
+
1082
1379
  // InApp Preview Content Styles (Phase 10)
1083
1380
  // Styles copied from TemplatePreview/_templatePreview.scss to ensure consistency
1084
1381
  // These styles work within the SMS device container structure
@@ -1139,11 +1436,11 @@
1139
1436
  .inapp-message-container-FULLSCREEN {
1140
1437
  position: relative;
1141
1438
  background-color: $CAP_WHITE;
1142
- width: 100%;
1439
+ width: 100%;
1143
1440
  height: 100%;
1144
1441
  align-items: center;
1145
1442
  padding: 0 $CAP_SPACE_16;
1146
- border-bottom-left-radius: 2.6rem;
1443
+ border-bottom-left-radius: 2.6rem;
1147
1444
  border-bottom-right-radius: 2.6rem;
1148
1445
  .inapp-title-FULLSCREEN {
1149
1446
  align-items: center;
@@ -1973,7 +2270,7 @@
1973
2270
  max-height: 7.5rem;
1974
2271
  margin-left: $CAP_SPACE_24;
1975
2272
  }
1976
-
2273
+
1977
2274
  .mpush-gif-preview {
1978
2275
  max-width: 100%;
1979
2276
  max-height: 7.5rem;
@@ -2231,6 +2528,7 @@
2231
2528
  font-weight: 500;
2232
2529
  display: -webkit-box;
2233
2530
  -webkit-line-clamp: 1;
2531
+ line-clamp: 1;
2234
2532
  -webkit-box-orient: vertical;
2235
2533
  overflow: hidden;
2236
2534
  color: $CAP_WHITE;
@@ -2282,7 +2580,7 @@
2282
2580
  color: $FONT_COLOR_01;
2283
2581
  margin-bottom: $CAP_SPACE_12;
2284
2582
  }
2285
-
2583
+
2286
2584
  .preview-text {
2287
2585
  font-weight: 400;
2288
2586
  font-size: $FONT_SIZE_S;
@@ -2317,13 +2615,13 @@
2317
2615
  justify-content: center;
2318
2616
  padding: $CAP_SPACE_60 $CAP_SPACE_24;
2319
2617
  gap: $CAP_SPACE_16;
2320
-
2618
+
2321
2619
  .zalo-loading-text {
2322
2620
  color: #8c8c8c;
2323
2621
  font-size: $FONT_SIZE_M;
2324
2622
  }
2325
2623
  }
2326
-
2624
+
2327
2625
  // Error state
2328
2626
  .zalo-error-container {
2329
2627
  display: flex;
@@ -2332,13 +2630,13 @@
2332
2630
  justify-content: center;
2333
2631
  padding: $CAP_SPACE_60 $CAP_SPACE_24;
2334
2632
  gap: $CAP_SPACE_16;
2335
-
2633
+
2336
2634
  .zalo-error-text {
2337
2635
  font-size: $FONT_SIZE_L;
2338
2636
  font-weight: 600;
2339
2637
  color: #262626;
2340
2638
  }
2341
-
2639
+
2342
2640
  .zalo-error-message {
2343
2641
  font-size: $FONT_SIZE_M;
2344
2642
  color: #ff4d4f;
@@ -2410,36 +2708,39 @@
2410
2708
  }
2411
2709
  }
2412
2710
  }
2413
-
2711
+
2414
2712
  @media (max-width: 54.857rem) {
2415
2713
  .unified-preview {
2416
2714
  .preview-header {
2417
2715
  flex-direction: column;
2418
2716
  align-items: flex-start;
2419
2717
  gap: $CAP_SPACE_12;
2420
-
2718
+
2421
2719
  .preview-header-right {
2422
2720
  width: 100%;
2423
2721
  justify-content: flex-start;
2424
2722
  }
2425
2723
  }
2426
-
2724
+
2427
2725
  .preview-content-container {
2428
2726
  padding: $CAP_SPACE_16;
2429
2727
  }
2430
-
2728
+
2431
2729
  .device-frame {
2432
2730
  &.device-frame-desktop,
2433
2731
  &.device-frame-tablet {
2434
2732
  width: 100% !important;
2435
2733
  max-width: 100% !important;
2436
2734
  }
2437
-
2438
- &.device-frame-mobile {
2439
- width: 100% !important;
2440
- max-width: 100% !important;
2441
- }
2735
+
2736
+ // NOT stretched to 100% here like desktop/tablet — this frame simulates a
2737
+ // phone, so on a narrow (e.g. real iOS) viewport it should stay phone-width
2738
+ // and shrink via its own `max-width: 90%` rule, not stretch to fill the
2739
+ // container. The old `width: 100% !important` made the frame's white
2740
+ // background render far wider than the phone silhouette, visibly eating
2741
+ // into the grey backdrop around it, while the carousel content inside
2742
+ // stayed capped at its normal phone width — a width mismatch, not a
2743
+ // clipping bug.
2442
2744
  }
2443
2745
  }
2444
2746
  }
2445
-