@capillarytech/creatives-library 9.0.41-alpha.0 → 9.0.41

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@capillarytech/creatives-library",
3
3
  "author": "meharaj",
4
- "version": "9.0.41-alpha.0",
4
+ "version": "9.0.41",
5
5
  "description": "Capillary creatives ui",
6
6
  "main": "./index.js",
7
7
  "module": "./index.es.js",
@@ -3,18 +3,13 @@ import PropTypes from 'prop-types';
3
3
  import CapRow from '@capillarytech/cap-ui-library/CapRow';
4
4
  import CapLabel from '@capillarytech/cap-ui-library/CapLabel';
5
5
  import CapImage from '@capillarytech/cap-ui-library/CapImage';
6
-
7
- const getTrimmedText = (value = '') => (value ?? '').trim();
8
- const hasTrimmedText = (value = '') => Boolean(getTrimmedText(value));
9
-
10
- const getCarouselButtonsWithTitles = (card) => (
11
- (card?.buttons ?? []).filter((button) => hasTrimmedText(button?.title)).slice(0, 2)
12
- );
13
-
14
- const getCarouselButtonSlotCount = (cards = []) => {
15
- const buttonCounts = cards.map((card) => getCarouselButtonsWithTitles(card).length);
16
- return Math.min(2, Math.max(0, ...buttonCounts, 0));
17
- };
6
+ import {
7
+ getTrimmedText,
8
+ hasTrimmedText,
9
+ getCarouselButtonsWithTitles,
10
+ getCarouselButtonSlotCount,
11
+ } from '../utils';
12
+ import { DEFAULT_CAROUSEL_TITLE_LINE_HEIGHT_PX } from '../constants';
18
13
 
19
14
  const ViberCarouselPreviewCards = ({ cards = [] }) => {
20
15
  const previewCards = Array.isArray(cards) && cards.length ? cards : [{}];
@@ -29,13 +24,13 @@ const ViberCarouselPreviewCards = ({ cards = [] }) => {
29
24
 
30
25
  useLayoutEffect(() => {
31
26
  let maxLines = 1;
32
- carouselTitleRefs.current.forEach((node) => {
27
+ carouselTitleRefs.current?.forEach((node) => {
33
28
  if (!node) {
34
29
  return;
35
30
  }
36
31
  const { lineHeight } = window.getComputedStyle(node);
37
- const parsedLineHeight = parseFloat(lineHeight) || 18;
38
- const lines = Math.min(2, Math.max(1, Math.round(node.scrollHeight / parsedLineHeight)));
32
+ const parsedLineHeight = parseFloat(lineHeight) || DEFAULT_CAROUSEL_TITLE_LINE_HEIGHT_PX;
33
+ const lines = Math.min(2, Math.max(1, Math.round(node?.scrollHeight / parsedLineHeight)));
39
34
  if (lines > maxLines) {
40
35
  maxLines = lines;
41
36
  }
@@ -44,41 +39,41 @@ const ViberCarouselPreviewCards = ({ cards = [] }) => {
44
39
  }, [previewCards]);
45
40
 
46
41
  return (
47
- <CapRow type="flex" noWrap className="viber-carousel-preview-scroll">
48
- {previewCards.map((card, index) => {
42
+ <CapRow type="flex" noWrap className="scroll">
43
+ {previewCards?.map((card, index) => {
49
44
  const cardButtons = getCarouselButtonsWithTitles(card);
50
- const titleLineClass = `viber-carousel-preview-text-wrap--${carouselTitleLineCount}-line`;
45
+ const titleLineClass = `text-wrap--${carouselTitleLineCount}-line`;
51
46
 
52
47
  return (
53
- <CapRow type="flex-column" className="viber-carousel-preview-card" key={`viber-carousel-preview-card-${index}`}>
48
+ <CapRow type="flex-column" className="card" key={`viber-carousel-card-${index}`}>
54
49
  {hasTrimmedText(card?.mediaUrl) ? (
55
50
  <CapImage
56
51
  src={card?.mediaUrl}
57
- className="viber-carousel-preview-image"
52
+ className="image"
58
53
  alt="Viber carousel card"
59
54
  />
60
55
  ) : (
61
- <CapRow className="viber-carousel-preview-image-placeholder" />
56
+ <CapRow className="image-placeholder" />
62
57
  )}
63
- <CapRow className="viber-carousel-preview-card-body">
64
- <CapRow className={`viber-carousel-preview-text-wrap ${titleLineClass}`}>
58
+ <CapRow className="card-body">
59
+ <CapRow className={`text-wrap ${titleLineClass}`}>
65
60
  {hasTrimmedText(card?.text) ? (
66
61
  <CapRow
67
- className="viber-carousel-preview-text-inner"
62
+ className="text-inner"
68
63
  ref={(node) => {
69
64
  carouselTitleRefs.current[index] = node;
70
65
  }}
71
66
  >
72
- <CapLabel type="label15" className="viber-carousel-preview-text">
67
+ <CapLabel type="label15" className="text">
73
68
  {card?.text}
74
69
  </CapLabel>
75
70
  </CapRow>
76
71
  ) : (
77
- <CapLabel type="label15" className="viber-carousel-preview-text-placeholder" />
72
+ <CapLabel type="label15" className="text-placeholder" />
78
73
  )}
79
74
  </CapRow>
80
75
  {carouselButtonSlotCount > 0 && (
81
- <CapRow className="viber-carousel-preview-buttons">
76
+ <CapRow className="buttons">
82
77
  {Array.from({ length: carouselButtonSlotCount }).map((_, btnIndex) => {
83
78
  const cardButton = cardButtons[btnIndex];
84
79
  const trimmedCardButtonTitle = cardButton
@@ -88,8 +83,8 @@ const ViberCarouselPreviewCards = ({ cards = [] }) => {
88
83
  if (!trimmedCardButtonTitle) {
89
84
  return (
90
85
  <CapRow
91
- className="viber-carousel-preview-button viber-carousel-preview-button-placeholder"
92
- key={`viber-carousel-preview-btn-placeholder-${index}-${btnIndex}`}
86
+ className="button button-placeholder"
87
+ key={`viber-carousel-btn-placeholder-${index}-${btnIndex}`}
93
88
  aria-hidden="true"
94
89
  />
95
90
  );
@@ -97,8 +92,8 @@ const ViberCarouselPreviewCards = ({ cards = [] }) => {
97
92
 
98
93
  return (
99
94
  <CapLabel
100
- className={`viber-carousel-preview-button ${btnIndex === 1 ? 'viber-carousel-preview-button-secondary' : ''}`}
101
- key={`viber-carousel-preview-btn-${index}-${btnIndex}-${trimmedCardButtonTitle}`}
95
+ className={`button ${btnIndex === 1 ? 'button-secondary' : ''}`}
96
+ key={`viber-carousel-btn-${index}-${btnIndex}-${trimmedCardButtonTitle}`}
102
97
  >
103
98
  {trimmedCardButtonTitle}
104
99
  </CapLabel>
@@ -24,15 +24,13 @@ import {
24
24
  } from '../constants';
25
25
  import messages from '../messages';
26
26
  import videoPlay from '../../../assets/videoPlay.svg';
27
+ import { getTrimmedText, hasTrimmedText } from '../utils';
27
28
  import ViberCarouselPreviewCards from './ViberCarouselPreviewCards';
28
29
 
29
30
  // Import device mockup images (same as SMS)
30
31
  const smsMobileAndroid = require('../../../assets/Android.png');
31
32
  const smsMobileIos = require('../../../assets/iOS.png');
32
33
 
33
- const getTrimmedText = (value = '') => (value ?? '').trim();
34
- const hasTrimmedText = (value = '') => Boolean(getTrimmedText(value));
35
-
36
34
  const ViberPreviewContent = ({
37
35
  content,
38
36
  device,
@@ -1,131 +1,133 @@
1
1
  // Shared Viber carousel card row (Test & Preview device preview)
2
- .viber-carousel-preview-scroll {
3
- display: flex;
4
- flex-direction: row;
5
- flex-wrap: nowrap;
6
- align-items: stretch;
7
- width: 100%;
8
- max-width: 100%;
9
- min-width: 0;
10
- overflow-x: auto;
11
- overflow-y: hidden;
12
- padding-right: $CAP_SPACE_12;
13
- scrollbar-width: none;
14
- -webkit-overflow-scrolling: touch;
15
-
16
- &::-webkit-scrollbar {
17
- display: none;
18
- }
19
-
20
- .viber-carousel-preview-card {
21
- flex: 0 0 68%;
22
- min-width: 80%;
23
- margin-right: $CAP_SPACE_08;
24
- background: $CAP_G09;
25
- border: 1px solid $CAP_G07;
26
- border-radius: $CAP_SPACE_12;
27
- overflow: hidden;
2
+ .viber-carousel-preview {
3
+ .scroll {
28
4
  display: flex;
29
- flex-direction: column;
30
- align-self: stretch;
31
-
32
- &:last-child {
33
- margin-right: 0;
5
+ flex-direction: row;
6
+ flex-wrap: nowrap;
7
+ align-items: stretch;
8
+ width: 100%;
9
+ max-width: 100%;
10
+ min-width: 0;
11
+ overflow-x: auto;
12
+ overflow-y: hidden;
13
+ padding-right: $CAP_SPACE_12;
14
+ scrollbar-width: none;
15
+ -webkit-overflow-scrolling: touch;
16
+
17
+ &::-webkit-scrollbar {
18
+ display: none;
34
19
  }
35
20
 
36
- .viber-carousel-preview-card-body {
37
- flex: 1;
38
- padding: $CAP_SPACE_08;
21
+ .card {
22
+ flex: 0 0 68%;
23
+ min-width: 80%;
24
+ margin-right: $CAP_SPACE_08;
25
+ background: $CAP_G09;
26
+ border: 1px solid $CAP_G07;
27
+ border-radius: $CAP_SPACE_12;
28
+ overflow: hidden;
39
29
  display: flex;
40
30
  flex-direction: column;
41
- min-height: 0;
42
- }
43
-
44
- .viber-carousel-preview-text-wrap {
45
- flex-shrink: 0;
46
- width: 100%;
31
+ align-self: stretch;
47
32
 
48
- &--1-line {
49
- min-height: 1.3em;
33
+ &:last-child {
34
+ margin-right: 0;
50
35
  }
51
36
 
52
- &--2-line {
53
- min-height: 2.6em;
37
+ .image {
38
+ width: 100%;
39
+ height: 10rem;
40
+ object-fit: cover;
41
+ border-radius: 0;
54
42
  }
55
- }
56
-
57
- .viber-carousel-preview-text-inner {
58
- width: 100%;
59
- }
60
-
61
- .viber-carousel-preview-buttons {
62
- display: flex;
63
- flex-direction: column;
64
- gap: $CAP_SPACE_06;
65
- width: 100%;
66
- flex-shrink: 0;
67
- }
68
-
69
- .viber-carousel-preview-image {
70
- width: 100%;
71
- height: 10rem;
72
- object-fit: cover;
73
- border-radius: 0;
74
- }
75
-
76
- .viber-carousel-preview-image-placeholder {
77
- width: 100%;
78
- height: 10rem;
79
- border-radius: 0;
80
- background: $CAP_G07;
81
- }
82
-
83
- .viber-carousel-preview-text {
84
- color: $CAP_G01;
85
- line-height: 1.3;
86
- white-space: normal;
87
- word-break: break-word;
88
- display: block;
89
- width: 100%;
90
- margin: 0;
91
- }
92
-
93
- .viber-carousel-preview-text-placeholder {
94
- width: 100%;
95
- height: 0.875rem;
96
- border-radius: $CAP_SPACE_04;
97
- background: $CAP_G07;
98
- min-height: 0.875rem;
99
- display: block;
100
- }
101
43
 
102
- .viber-carousel-preview-button {
103
- color: $CAP_WHITE;
104
- background: $CAP_PURPLE01;
105
- border-radius: $CAP_SPACE_12;
106
- text-align: center;
107
- width: 100%;
108
- display: flex;
109
- align-items: center;
110
- justify-content: center;
111
- min-height: 1.5rem;
112
- padding: $CAP_SPACE_06 $CAP_SPACE_08;
113
- white-space: normal;
114
- box-sizing: border-box;
115
- }
116
-
117
- .viber-carousel-preview-button-placeholder {
118
- visibility: hidden;
119
- pointer-events: none;
120
- padding: 0;
121
- background: transparent;
122
- border: none;
123
- }
44
+ .image-placeholder {
45
+ width: 100%;
46
+ height: 10rem;
47
+ border-radius: 0;
48
+ background: $CAP_G07;
49
+ }
124
50
 
125
- .viber-carousel-preview-button-secondary {
126
- color: $CAP_PURPLE01;
127
- background: transparent;
128
- border: none;
51
+ .card-body {
52
+ flex: 1;
53
+ padding: $CAP_SPACE_08;
54
+ display: flex;
55
+ flex-direction: column;
56
+ min-height: 0;
57
+
58
+ .text-wrap {
59
+ flex-shrink: 0;
60
+ width: 100%;
61
+
62
+ &--1-line {
63
+ min-height: 1.3em;
64
+ }
65
+
66
+ &--2-line {
67
+ min-height: 2.6em;
68
+ }
69
+
70
+ .text-inner {
71
+ width: 100%;
72
+
73
+ .text {
74
+ color: $CAP_G01;
75
+ line-height: 1.3;
76
+ white-space: normal;
77
+ word-break: break-word;
78
+ display: block;
79
+ width: 100%;
80
+ margin: 0;
81
+ }
82
+ }
83
+
84
+ .text-placeholder {
85
+ width: 100%;
86
+ height: 0.875rem;
87
+ border-radius: $CAP_SPACE_04;
88
+ background: $CAP_G07;
89
+ min-height: 0.875rem;
90
+ display: block;
91
+ }
92
+ }
93
+
94
+ .buttons {
95
+ display: flex;
96
+ flex-direction: column;
97
+ gap: $CAP_SPACE_06;
98
+ width: 100%;
99
+ flex-shrink: 0;
100
+
101
+ .button {
102
+ color: $CAP_WHITE;
103
+ background: $CAP_PURPLE01;
104
+ border-radius: $CAP_SPACE_12;
105
+ text-align: center;
106
+ width: 100%;
107
+ display: flex;
108
+ align-items: center;
109
+ justify-content: center;
110
+ min-height: 1.5rem;
111
+ padding: $CAP_SPACE_06 $CAP_SPACE_08;
112
+ white-space: normal;
113
+ box-sizing: border-box;
114
+ }
115
+
116
+ .button-placeholder {
117
+ visibility: hidden;
118
+ pointer-events: none;
119
+ padding: 0;
120
+ background: transparent;
121
+ border: none;
122
+ }
123
+
124
+ .button-secondary {
125
+ color: $CAP_PURPLE01;
126
+ background: transparent;
127
+ border: none;
128
+ }
129
+ }
130
+ }
129
131
  }
130
132
  }
131
133
  }
@@ -228,6 +228,8 @@ export const CHANNEL_NAME_MOBILE_PUSH = 'MOBILE_PUSH';
228
228
  export const DEFAULT_SENDER = 'test1';
229
229
  export const VIBER_API_SCENARIO_KEY = 'viber-api';
230
230
  export const VIBER_USER_ID_PATTERN = '{{viber_user_id}}';
231
+ /** Fallback title line-height (px) when computed style is unavailable. */
232
+ export const DEFAULT_CAROUSEL_TITLE_LINE_HEIGHT_PX = 18;
231
233
  export const UNSUBSCRIBE_TAG_NAME = 'unsubscribe';
232
234
  export const IN_APP_CHANNEL_NAME = 'in-app';
233
235
  export const MOBILE_PUSH_CHANNEL_NAME = 'mobile push';
@@ -703,10 +703,10 @@ const CommonTestAndPreview = (props) => {
703
703
  contentObj = {};
704
704
  }
705
705
  }
706
- const previewCards = formDataObj.viberPreviewContent?.cards
707
- ?? formDataObj.cards
708
- ?? contentObj.viberPreviewContent?.cards
709
- ?? contentObj.cards;
706
+ const previewCards = formDataObj?.viberPreviewContent?.cards
707
+ ?? formDataObj?.cards
708
+ ?? contentObj?.viberPreviewContent?.cards
709
+ ?? contentObj?.cards;
710
710
  const isCarousel = Boolean(
711
711
  formDataObj.type === MEDIA_TYPE_CAROUSEL
712
712
  || contentObj.type === MEDIA_TYPE_CAROUSEL
@@ -322,7 +322,7 @@ describe('ViberPreviewContent', () => {
322
322
  </TestWrapper>
323
323
  );
324
324
 
325
- expect(container.querySelector('.viber-carousel-preview-button')).toBeNull();
325
+ expect(container.querySelector('.viber-carousel-preview .button')).toBeNull();
326
326
  });
327
327
 
328
328
  it('should show carousel shell when showCarouselEditorPreview is true even if cards are empty', () => {
@@ -347,7 +347,7 @@ describe('ViberPreviewContent', () => {
347
347
  );
348
348
 
349
349
  expect(screen.queryByText('No content available')).toBeNull();
350
- expect(container.querySelector('.viber-carousel-preview-scroll')).toBeTruthy();
350
+ expect(container.querySelector('.viber-carousel-preview .scroll')).toBeTruthy();
351
351
  expect(container.querySelector('.viber-carousel-message-box-placeholder')).toBeTruthy();
352
352
  });
353
353
 
@@ -428,8 +428,8 @@ describe('ViberPreviewContent', () => {
428
428
  </TestWrapper>
429
429
  );
430
430
 
431
- expect(container.querySelector('.viber-carousel-preview-image-placeholder')).toBeTruthy();
432
- expect(container.querySelector('.viber-carousel-preview-image')).toBeNull();
431
+ expect(container.querySelector('.viber-carousel-preview .image-placeholder')).toBeTruthy();
432
+ expect(container.querySelector('.viber-carousel-preview .image')).toBeNull();
433
433
  });
434
434
 
435
435
  it('should render at most two carousel buttons per card', () => {
@@ -459,7 +459,7 @@ describe('ViberPreviewContent', () => {
459
459
  </TestWrapper>
460
460
  );
461
461
 
462
- expect(container.querySelectorAll('.viber-carousel-preview-button')).toHaveLength(2);
462
+ expect(container.querySelectorAll('.viber-carousel-preview .button')).toHaveLength(2);
463
463
  expect(screen.getByText('One')).toBeTruthy();
464
464
  expect(screen.getByText('Two')).toBeTruthy();
465
465
  expect(screen.queryByText('Three')).toBeNull();
@@ -491,10 +491,10 @@ describe('ViberPreviewContent', () => {
491
491
  </TestWrapper>
492
492
  );
493
493
 
494
- const buttons = container.querySelectorAll('.viber-carousel-preview-button');
495
- expect(buttons[0].className).toContain('viber-carousel-preview-button');
496
- expect(buttons[0].className).not.toContain('viber-carousel-preview-button-secondary');
497
- expect(buttons[1].className).toContain('viber-carousel-preview-button-secondary');
494
+ const buttons = container.querySelectorAll('.viber-carousel-preview .button');
495
+ expect(buttons[0].className).toContain('button');
496
+ expect(buttons[0].className).not.toContain('button-secondary');
497
+ expect(buttons[1].className).toContain('button-secondary');
498
498
  });
499
499
 
500
500
  it('should show carousel when only a button title is present on a card', () => {
@@ -542,7 +542,7 @@ describe('ViberPreviewContent', () => {
542
542
  </TestWrapper>
543
543
  );
544
544
 
545
- expect(container.querySelectorAll('.viber-carousel-preview-card')).toHaveLength(1);
545
+ expect(container.querySelectorAll('.viber-carousel-preview .card')).toHaveLength(1);
546
546
  });
547
547
 
548
548
  it('should show no content when CAROUSEL has empty cards and no editor preview flag', () => {
@@ -6,6 +6,10 @@ import {
6
6
  mapRcsSuggestionForTestMeta,
7
7
  typeMatches,
8
8
  unwrapEntity,
9
+ getTrimmedText,
10
+ hasTrimmedText,
11
+ getCarouselButtonsWithTitles,
12
+ getCarouselButtonSlotCount,
9
13
  } from '../utils';
10
14
 
11
15
  describe('CommonTestAndPreview/utils', () => {
@@ -148,4 +152,49 @@ describe('CommonTestAndPreview/utils', () => {
148
152
  expect(unwrapEntity(response)).toBe(response);
149
153
  });
150
154
  });
155
+
156
+ describe('getTrimmedText / hasTrimmedText', () => {
157
+ it('trims string values', () => {
158
+ expect(getTrimmedText(' hello ')).toBe('hello');
159
+ });
160
+
161
+ it('treats null/undefined as empty', () => {
162
+ expect(getTrimmedText(null)).toBe('');
163
+ expect(getTrimmedText(undefined)).toBe('');
164
+ expect(hasTrimmedText(' ')).toBe(false);
165
+ expect(hasTrimmedText('ok')).toBe(true);
166
+ });
167
+ });
168
+
169
+ describe('getCarouselButtonsWithTitles', () => {
170
+ it('returns up to 2 buttons with non-empty titles', () => {
171
+ expect(getCarouselButtonsWithTitles({
172
+ buttons: [
173
+ { title: ' A ' },
174
+ { title: '' },
175
+ { title: 'B' },
176
+ { title: 'C' },
177
+ ],
178
+ })).toEqual([{ title: ' A ' }, { title: 'B' }]);
179
+ });
180
+
181
+ it('returns empty array when card has no titled buttons', () => {
182
+ expect(getCarouselButtonsWithTitles({})).toEqual([]);
183
+ expect(getCarouselButtonsWithTitles(undefined)).toEqual([]);
184
+ });
185
+ });
186
+
187
+ describe('getCarouselButtonSlotCount', () => {
188
+ it('returns the max titled-button count across cards, capped at 2', () => {
189
+ expect(getCarouselButtonSlotCount([
190
+ { buttons: [{ title: 'A' }] },
191
+ { buttons: [{ title: 'A' }, { title: 'B' }, { title: 'C' }] },
192
+ ])).toBe(2);
193
+ });
194
+
195
+ it('returns 0 when no cards have titled buttons', () => {
196
+ expect(getCarouselButtonSlotCount([])).toBe(0);
197
+ expect(getCarouselButtonSlotCount([{ buttons: [{ title: ' ' }] }])).toBe(0);
198
+ });
199
+ });
151
200
  });
@@ -116,3 +116,23 @@ export const unwrapEntity = (response) => {
116
116
  if (response.entity === null) return null;
117
117
  return response;
118
118
  };
119
+
120
+ /** Trim string-like values; null/undefined become ''. */
121
+ export const getTrimmedText = (value = '') => (value ?? '').trim();
122
+
123
+ /** True when trimmed text is non-empty. */
124
+ export const hasTrimmedText = (value = '') => Boolean(getTrimmedText(value));
125
+
126
+ /** First up to 2 carousel buttons that have a non-empty title. */
127
+ export const getCarouselButtonsWithTitles = (card) => (
128
+ (card?.buttons ?? []).filter((button) => hasTrimmedText(button?.title)).slice(0, 2)
129
+ );
130
+
131
+ /**
132
+ * Max button slots to reserve across carousel cards (0–2), so cards align
133
+ * even when some cards have fewer titled buttons.
134
+ */
135
+ export const getCarouselButtonSlotCount = (cards = []) => {
136
+ const buttonCounts = cards.map((card) => getCarouselButtonsWithTitles(card).length);
137
+ return Math.min(2, Math.max(0, ...buttonCounts, 0));
138
+ };
@@ -160,103 +160,6 @@
160
160
  line-clamp: 3;
161
161
  }
162
162
  }
163
- .viber-carousel-static-content {
164
- width: 100%;
165
- overflow: visible;
166
- display: flex;
167
- flex-direction: column;
168
- .viber-carousel-static-message-box {
169
- width: 100%;
170
- height: auto;
171
- border-radius: $CAP_SPACE_04;
172
- background: $CAP_WHITE;
173
- margin-bottom: $CAP_SPACE_08;
174
- display: flex;
175
- align-items: flex-start;
176
- }
177
- .viber-carousel-static-message {
178
- display: -webkit-box;
179
- width: 100%;
180
- color: $CAP_G01;
181
- line-height: 1.3;
182
- overflow: hidden;
183
- text-overflow: ellipsis;
184
- -webkit-line-clamp: 2;
185
- line-clamp: 2;
186
- -webkit-box-orient: vertical;
187
- white-space: normal;
188
- word-break: break-word;
189
- }
190
- .viber-carousel-static-cards {
191
- display: flex;
192
- gap: $CAP_SPACE_08;
193
- overflow: visible;
194
- }
195
- .viber-carousel-static-card {
196
- flex: 1;
197
- min-width: 0;
198
- width: 100%;
199
- background: $CAP_WHITE;
200
- border-radius: $CAP_SPACE_04;
201
- overflow: visible;
202
- display: flex;
203
- flex-direction: column;
204
- }
205
- .viber-carousel-static-image {
206
- width: 100%;
207
- max-height: 11rem;
208
- margin-bottom: $CAP_SPACE_04;
209
- border-radius: $CAP_SPACE_04;
210
- display: block;
211
- flex-shrink: 0;
212
- }
213
- .viber-carousel-static-image-placeholder {
214
- width: 100%;
215
- height: 7.143rem;
216
- border-radius: $CAP_SPACE_04;
217
- }
218
- .viber-carousel-static-image-placeholder {
219
- background: $CAP_G07;
220
- }
221
- .viber-carousel-static-text {
222
- display: block;
223
- color: $CAP_G01;
224
- margin: $CAP_SPACE_04 0;
225
- line-height: 1.3;
226
- overflow: hidden;
227
- text-overflow: ellipsis;
228
- white-space: normal;
229
- -webkit-line-clamp: 2;
230
- line-clamp: 2;
231
- -webkit-box-orient: vertical;
232
- display: -webkit-box;
233
- flex-shrink: 0;
234
- }
235
- .viber-carousel-static-buttons {
236
- display: flex;
237
- flex-direction: column;
238
- gap: $CAP_SPACE_04;
239
- flex-shrink: 0;
240
- width: 100%;
241
- }
242
- .viber-carousel-static-button {
243
- display: block;
244
- min-height: 1.5rem;
245
- border-radius: $CAP_SPACE_12;
246
- background: $CAP_PURPLE01;
247
- color: $CAP_WHITE;
248
- text-align: center;
249
- padding: 0.179rem $CAP_SPACE_08;
250
- white-space: normal;
251
- }
252
- .viber-carousel-static-button-secondary {
253
- color: $CAP_PURPLE01;
254
- background: transparent;
255
- border: none;
256
- box-shadow: none;
257
- }
258
- }
259
-
260
163
  }
261
164
 
262
165
  &.no-image .ant-card-meta {
@@ -294,9 +197,9 @@
294
197
  }
295
198
  }
296
199
 
297
- .viber-carousel-static-content,
298
- .viber-carousel-static-cards,
299
- .viber-carousel-static-card {
200
+ .content,
201
+ .cards,
202
+ .card {
300
203
  overflow: visible;
301
204
  height: auto;
302
205
  }
@@ -1383,38 +1286,118 @@
1383
1286
  line-clamp: unset;
1384
1287
  -webkit-box-orient: unset;
1385
1288
  }
1289
+ }
1386
1290
 
1387
- .viber-carousel-static-content,
1388
- .viber-carousel-static-card,
1389
- .viber-carousel-static-buttons {
1390
- display: flex;
1391
- flex-direction: column;
1291
+ .viber-carousel-static {
1292
+ .content {
1392
1293
  width: 100%;
1393
- }
1394
-
1395
- .viber-carousel-static-content,
1396
- .viber-carousel-static-cards,
1397
- .viber-carousel-static-card {
1398
1294
  overflow: visible;
1295
+ display: flex;
1296
+ flex-direction: column;
1399
1297
  height: auto;
1400
- }
1401
1298
 
1402
- .viber-carousel-static-cards {
1403
- width: 100%;
1404
- }
1299
+ .message-box {
1300
+ width: 100%;
1301
+ height: auto;
1302
+ border-radius: $CAP_SPACE_04;
1303
+ background: $CAP_WHITE;
1304
+ margin-bottom: $CAP_SPACE_08;
1305
+ display: flex;
1306
+ align-items: flex-start;
1405
1307
 
1406
- .viber-carousel-static-image {
1407
- width: 100%;
1408
- max-height: 11rem;
1409
- display: block;
1410
- flex-shrink: 0;
1411
- }
1308
+ .message {
1309
+ display: -webkit-box;
1310
+ width: 100%;
1311
+ color: $CAP_G01;
1312
+ line-height: 1.3;
1313
+ overflow: hidden;
1314
+ text-overflow: ellipsis;
1315
+ -webkit-line-clamp: 2;
1316
+ line-clamp: 2;
1317
+ -webkit-box-orient: vertical;
1318
+ white-space: normal;
1319
+ word-break: break-word;
1320
+ }
1321
+ }
1412
1322
 
1413
- .viber-carousel-static-text,
1414
- .viber-carousel-static-buttons {
1415
- width: 100%;
1416
- flex-shrink: 0;
1417
- visibility: visible;
1323
+ .cards {
1324
+ display: flex;
1325
+ gap: $CAP_SPACE_08;
1326
+ overflow: visible;
1327
+ width: 100%;
1328
+ height: auto;
1329
+
1330
+ .card {
1331
+ flex: 1;
1332
+ min-width: 0;
1333
+ width: 100%;
1334
+ background: $CAP_WHITE;
1335
+ border-radius: $CAP_SPACE_04;
1336
+ overflow: visible;
1337
+ display: flex;
1338
+ flex-direction: column;
1339
+ height: auto;
1340
+
1341
+ .image {
1342
+ width: 100%;
1343
+ max-height: 11rem;
1344
+ margin-bottom: $CAP_SPACE_04;
1345
+ border-radius: $CAP_SPACE_04;
1346
+ display: block;
1347
+ flex-shrink: 0;
1348
+ }
1349
+
1350
+ .image-placeholder {
1351
+ width: 100%;
1352
+ height: 7.143rem;
1353
+ border-radius: $CAP_SPACE_04;
1354
+ background: $CAP_G07;
1355
+ }
1356
+
1357
+ .text {
1358
+ display: -webkit-box;
1359
+ color: $CAP_G01;
1360
+ margin: $CAP_SPACE_04 0;
1361
+ line-height: 1.3;
1362
+ overflow: hidden;
1363
+ text-overflow: ellipsis;
1364
+ white-space: normal;
1365
+ -webkit-line-clamp: 2;
1366
+ line-clamp: 2;
1367
+ -webkit-box-orient: vertical;
1368
+ flex-shrink: 0;
1369
+ width: 100%;
1370
+ visibility: visible;
1371
+ }
1372
+
1373
+ .buttons {
1374
+ display: flex;
1375
+ flex-direction: column;
1376
+ gap: $CAP_SPACE_04;
1377
+ flex-shrink: 0;
1378
+ width: 100%;
1379
+ visibility: visible;
1380
+
1381
+ .button {
1382
+ display: block;
1383
+ min-height: 1.5rem;
1384
+ border-radius: $CAP_SPACE_12;
1385
+ background: $CAP_PURPLE01;
1386
+ color: $CAP_WHITE;
1387
+ text-align: center;
1388
+ padding: 0.179rem $CAP_SPACE_08;
1389
+ white-space: normal;
1390
+ }
1391
+
1392
+ .button-secondary {
1393
+ color: $CAP_PURPLE01;
1394
+ background: transparent;
1395
+ border: none;
1396
+ box-shadow: none;
1397
+ }
1398
+ }
1399
+ }
1400
+ }
1418
1401
  }
1419
1402
  }
1420
1403
  .whatsapp-doc {
@@ -2476,43 +2476,37 @@ export class Templates extends React.Component { // eslint-disable-line react/pr
2476
2476
  if (isViberCarousel) {
2477
2477
  const previewCards = Array.isArray(cards) ? cards.slice(0, 1) : [];
2478
2478
  // Bypass CapCustomCard Viber Meta + line-clamp (clips title/buttons for tall images).
2479
- // Keep VIBER in className for listing styles; cardType hits the default content path.
2479
+ // Parent class `viber-carousel-static` scopes listing styles in _templates.scss.
2480
+ // cardType hits the default content path; keep VIBER for channel card styles.
2480
2481
  templateData.cardType = 'VIBER_CAROUSEL_PREVIEW';
2481
2482
  templateData.className = 'viber-carousel-static VIBER';
2482
- templateData.style = {
2483
- height: 'auto',
2484
- minHeight: '21.125rem',
2485
- overflow: 'visible',
2486
- };
2487
- templateData.bodyStyle = {
2488
- height: 'auto',
2489
- overflow: 'visible',
2490
- paddingBottom: '12px',
2491
- };
2492
2483
  templateData.content = (
2493
- <CapRow vertical className="viber-carousel-static-content">
2494
- <CapRow className="viber-carousel-static-message-box">
2495
- <CapLabel type="label1" className="viber-carousel-static-message">
2484
+ <CapRow vertical className="content">
2485
+ <CapRow className="message-box">
2486
+ <CapLabel type="label1" className="message">
2496
2487
  {text}
2497
2488
  </CapLabel>
2498
2489
  </CapRow>
2499
- <CapRow className="viber-carousel-static-cards">
2500
- {previewCards.map((card, cardIdx) => (
2501
- <CapRow vertical className="viber-carousel-static-card" key={`viber-static-card-${cardIdx}`}>
2490
+ <CapRow className="cards">
2491
+ {previewCards?.map((card, cardIdx) => (
2492
+ <CapRow vertical className="card" key={`viber-carousel-static-card-${cardIdx}`}>
2502
2493
  {card?.mediaUrl ? (
2503
- <CapImage src={card.mediaUrl} className="viber-carousel-static-image" />
2494
+ <CapImage src={card.mediaUrl} className="image" />
2504
2495
  ) : (
2505
- <CapRow className="viber-carousel-static-image-placeholder" />
2496
+ <CapRow className="image-placeholder" />
2506
2497
  )}
2507
- <CapLabel type="label1" className="viber-carousel-static-text">
2498
+ <CapLabel type="label1" className="text">
2508
2499
  {card?.text}
2509
2500
  </CapLabel>
2510
- <CapRow vertical className="viber-carousel-static-buttons">
2511
- {(Array.isArray(card?.buttons) && card.buttons.length ? card.buttons : [{}, {}]).slice(0, 2).map((carouselButton, btnIdx) => (
2501
+ <CapRow vertical className="buttons">
2502
+ {(Array.isArray(card?.buttons) && card.buttons.length
2503
+ ? card.buttons
2504
+ : [{}, {}]
2505
+ ).slice(0, 2).map((carouselButton, btnIdx) => (
2512
2506
  <CapLabel
2513
- key={`viber-static-btn-${cardIdx}-${btnIdx}`}
2507
+ key={`viber-carousel-static-btn-${cardIdx}-${btnIdx}`}
2514
2508
  type="label1"
2515
- className={`viber-carousel-static-button ${btnIdx === 1 ? 'viber-carousel-static-button-secondary' : ''}`}
2509
+ className={`button${btnIdx === 1 ? ' button-secondary' : ''}`}
2516
2510
  >
2517
2511
  {(carouselButton?.title || '').trim()}
2518
2512
  </CapLabel>