@capillarytech/creatives-library 9.0.70 → 9.0.71-alpha.sprint-cap-211543.18

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 (50) hide show
  1. package/constants/unified.js +0 -1
  2. package/package.json +1 -1
  3. package/utils/common.js +0 -6
  4. package/v2Components/CapTagListWithInput/__tests__/CapTagListWithInput.test.js +58 -1
  5. package/v2Components/CapTagListWithInput/index.js +64 -35
  6. package/v2Components/CapTagListWithInput/index.scss +9 -0
  7. package/v2Components/CommonTestAndPreview/UnifiedPreview/EmailPreviewContent.js +8 -0
  8. package/v2Components/CommonTestAndPreview/UnifiedPreview/_unifiedPreview.scss +7 -0
  9. package/v2Components/CommonTestAndPreview/UnifiedPreview/index.js +1 -0
  10. package/v2Components/CommonTestAndPreview/actions.js +1 -1
  11. package/v2Components/CommonTestAndPreview/index.js +29 -13
  12. package/v2Components/CommonTestAndPreview/sagas.js +2 -1
  13. package/v2Components/CommonTestAndPreview/tests/UnifiedPreview/EmailPreviewContent.test.js +27 -0
  14. package/v2Components/CommonTestAndPreview/tests/UnifiedPreview/index.test.js +40 -0
  15. package/v2Components/CommonTestAndPreview/tests/index.test.js +95 -0
  16. package/v2Components/CommonTestAndPreview/tests/sagas.test.js +24 -0
  17. package/v2Components/EmailMobilePreview/index.js +8 -1
  18. package/v2Components/EmailMobilePreview/index.scss +12 -3
  19. package/v2Components/EmailMobilePreview/tests/index.test.js +31 -0
  20. package/v2Components/EmailPreviewV2/_emailPreviewV2.scss +35 -5
  21. package/v2Components/EmailPreviewV2/index.js +18 -6
  22. package/v2Components/EmailPreviewV2/messages.js +4 -0
  23. package/v2Components/EmailPreviewV2/tests/index.test.js +43 -0
  24. package/v2Components/FormBuilder/Classic.js +119 -10
  25. package/v2Components/FormBuilder/_formBuilder.scss +21 -0
  26. package/v2Components/FormBuilder/messages.js +12 -0
  27. package/v2Containers/Cap/tests/index.test.js +1 -0
  28. package/v2Containers/CommunicationFlow/Tests/CommunicationFlow.test.js +2 -1
  29. package/v2Containers/CommunicationFlow/Tests/constants.test.js +4 -4
  30. package/v2Containers/CommunicationFlow/constants.js +1 -0
  31. package/v2Containers/CommunicationFlow/utils/Tests/mapCommDefinitionToStepData.test.js +2 -1
  32. package/v2Containers/CommunicationFlow/utils/mapCommDefinitionToStepData.js +1 -0
  33. package/v2Containers/CreativesContainer/index.js +9 -3
  34. package/v2Containers/CreativesContainer/tests/index.test.js +81 -0
  35. package/v2Containers/Email/index.js +31 -4
  36. package/v2Containers/Email/initialSchema.js +30 -0
  37. package/v2Containers/Email/messages.js +8 -0
  38. package/v2Containers/Email/tests/index.test.js +107 -0
  39. package/v2Containers/EmailWrapper/components/EmailHTMLEditor.js +172 -8
  40. package/v2Containers/EmailWrapper/components/__tests__/EmailHTMLEditor.test.js +264 -5
  41. package/v2Containers/EmailWrapper/components/_emailHTMLEditor.scss +29 -0
  42. package/v2Containers/EmailWrapper/constants.js +5 -0
  43. package/v2Containers/EmailWrapper/messages.js +24 -0
  44. package/v2Containers/TagList/index.js +7 -0
  45. package/v2Containers/TagList/tests/TagList.test.js +42 -0
  46. package/v2Containers/Templates/constants.js +1 -0
  47. package/v2Containers/Templates/index.js +31 -27
  48. package/v2Containers/Templates/messages.js +4 -0
  49. package/v2Containers/Templates/tests/__snapshots__/index.test.js.snap +128 -4
  50. package/v2Containers/Templates/tests/archival.test.js +221 -0
@@ -377,6 +377,27 @@ describe('Email container', () => {
377
377
  const addLangCol = cols.find((c) => c.id === 'add-language-button');
378
378
  expect(addLangCol.colStyle.display).toBe('');
379
379
  });
380
+
381
+ const getStandaloneFieldIds = (schema) => _.flatMap(
382
+ schema.standalone.sections,
383
+ (section) => _.flatMap(section.inputFields, (inputField) => _.map(inputField.cols, (col) => col.id)),
384
+ );
385
+
386
+ it('keeps both template-subject and template-preheader as standalone fields for embedded/library module', () => {
387
+ const wrapper = renderEmail({ location: { query: { type: 'embedded', module: 'library' } } });
388
+
389
+ const result = wrapper.instance().removeStandAlone(_.cloneDeep(emailDefinition));
390
+
391
+ expect(getStandaloneFieldIds(result)).toEqual(['template-subject', 'template-preheader']);
392
+ });
393
+
394
+ it('drops template-name from standalone fields for embedded/library module (unchanged prior behavior)', () => {
395
+ const wrapper = renderEmail({ location: { query: { type: 'embedded', module: 'library' } } });
396
+
397
+ const result = wrapper.instance().removeStandAlone(_.cloneDeep(emailDefinition));
398
+
399
+ expect(getStandaloneFieldIds(result)).not.toContain('template-name');
400
+ });
380
401
  });
381
402
 
382
403
  describe('handleEdmSave (mode === "switchEditor")', () => {
@@ -717,4 +738,90 @@ describe('Email container', () => {
717
738
  expect(wrapper.state('savedTemplate')).toBeNull();
718
739
  });
719
740
  });
741
+
742
+ describe('pre-header field', () => {
743
+ describe('onTagSelect', () => {
744
+ it('appends the tag to template-preheader when a tag is selected from the pre-header field', () => {
745
+ const wrapper = renderEmail();
746
+ wrapper.setState({ formData: { 'template-preheader': 'Hello ' } });
747
+
748
+ wrapper.instance().onTagSelect('first_name', 1, { id: 'template-preheader' });
749
+
750
+ expect(wrapper.state('formData')['template-preheader']).toBe('Hello {{first_name}}');
751
+ });
752
+
753
+ it('does not touch template-subject when the tag is selected from the pre-header field', () => {
754
+ const wrapper = renderEmail();
755
+ wrapper.setState({ formData: { 'template-preheader': '', 'template-subject': 'Original subject' } });
756
+
757
+ wrapper.instance().onTagSelect('loyalty_points', 1, { id: 'template-preheader' });
758
+
759
+ expect(wrapper.state('formData')['template-subject']).toBe('Original subject');
760
+ expect(wrapper.state('formData')['template-preheader']).toBe('{{loyalty_points}}');
761
+ });
762
+ });
763
+
764
+ describe('setEditData', () => {
765
+ it('populates formData["template-preheader"] from versions.base.preheader', () => {
766
+ const wrapper = renderEmail();
767
+ wrapper.setState({ schema: { containers: [] } });
768
+ const instance = wrapper.instance();
769
+ const editData = {
770
+ name: 'My Template',
771
+ versions: {
772
+ base: {
773
+ subject: 'My subject',
774
+ preheader: 'My preheader text',
775
+ activeTab: 'en',
776
+ selectedLanguages: ['en'],
777
+ en: {},
778
+ },
779
+ history: [],
780
+ },
781
+ };
782
+
783
+ instance.setEditData(editData);
784
+
785
+ expect(wrapper.state('formData')['template-preheader']).toBe('My preheader text');
786
+ });
787
+
788
+ it('defaults to an empty string when versions.base.preheader is absent', () => {
789
+ const wrapper = renderEmail();
790
+ wrapper.setState({ schema: { containers: [] } });
791
+ const instance = wrapper.instance();
792
+ const editData = {
793
+ name: 'My Template',
794
+ versions: {
795
+ base: {
796
+ subject: 'My subject',
797
+ activeTab: 'en',
798
+ selectedLanguages: ['en'],
799
+ en: {},
800
+ },
801
+ history: [],
802
+ },
803
+ };
804
+
805
+ instance.setEditData(editData);
806
+
807
+ expect(wrapper.state('formData')['template-preheader']).toBe('');
808
+ });
809
+ });
810
+
811
+ describe('transformFormData', () => {
812
+ it('carries template-preheader into the returned base.preheader', () => {
813
+ const wrapper = renderEmail();
814
+ wrapper.setState({
815
+ formData: {
816
+ 'template-preheader': 'Preview snippet text',
817
+ base: { activeTab: 'en', en: { 'template-content': '<p>hi</p>' } },
818
+ },
819
+ });
820
+
821
+ const result = wrapper.instance().transformFormData(wrapper.state('formData'));
822
+
823
+ expect(result.base.preheader).toBe('Preview snippet text');
824
+ });
825
+ });
826
+ });
720
827
  });
@@ -6,7 +6,6 @@ import { injectIntl, FormattedMessage } from 'react-intl';
6
6
  import isEmpty from 'lodash/isEmpty';
7
7
  import get from 'lodash/get';
8
8
  import _ from 'lodash';
9
- import { CAP_SPACE_16 } from '@capillarytech/cap-ui-library/styled/variables';
10
9
  import CapSpin from '@capillarytech/cap-ui-library/CapSpin';
11
10
  import CapRow from '@capillarytech/cap-ui-library/CapRow';
12
11
  import CapColumn from '@capillarytech/cap-ui-library/CapColumn';
@@ -15,6 +14,9 @@ import CapDropdown from '@capillarytech/cap-ui-library/CapDropdown';
15
14
  import CapMenu from '@capillarytech/cap-ui-library/CapMenu';
16
15
  import CapIcon from '@capillarytech/cap-ui-library/CapIcon';
17
16
  import CapTooltip from '@capillarytech/cap-ui-library/CapTooltip';
17
+ import CapTooltipWithInfo from '@capillarytech/cap-ui-library/CapTooltipWithInfo';
18
+ import CapButton from '@capillarytech/cap-ui-library/CapButton';
19
+ import CapLabel from '@capillarytech/cap-ui-library/CapLabel';
18
20
  import HTMLEditor from '../../../v2Components/HtmlEditor';
19
21
  import CapTagListWithInput from '../../../v2Components/CapTagListWithInput';
20
22
  import formBuilderMessages from '../../../v2Components/FormBuilder/messages';
@@ -24,14 +26,17 @@ import { downloadHtmlFile, sanitizeFileName, getExportHtmlDisabledTooltip } from
24
26
  import history from '../../../utils/history';
25
27
  import messages from '../messages';
26
28
  import emailMessages from '../../Email/messages';
27
- import { validateTags } from '../../../utils/tagValidations';
29
+ import { validateTags, hasUnsubscribeTag } from '../../../utils/tagValidations';
28
30
  import {
29
31
  TAG, EMBEDDED, DEFAULT, FULL, LIBRARY,
30
32
  } from '../../Whatsapp/constants';
31
33
  import { EMAIL } from '../../CreativesContainer/constants';
32
34
  import { OUTBOUND } from '../../../v2Components/FormBuilder/constants';
35
+ import { PREHEADER_EXCLUDED_TAGS } from '../constants';
33
36
  import './_emailHTMLEditor.scss';
34
37
 
38
+ const { CapLabelInline } = CapLabel;
39
+
35
40
  /**
36
41
  * EmailHTMLEditor Component
37
42
  *
@@ -111,6 +116,17 @@ const EmailHTMLEditor = (props) => {
111
116
  const [savedTemplate, setSavedTemplate] = useState(null);
112
117
  const [subject, setSubject] = useState('');
113
118
  const [subjectError, setSubjectError] = useState('');
119
+ const [preheader, setPreheader] = useState('');
120
+ const [preheaderError, setPreheaderError] = useState('');
121
+ // null = show if content exists; true/false = manual "+ Pre-header"/"Remove" click.
122
+ const [preheaderRevealed, setPreheaderRevealed] = useState(null);
123
+ const isPreheaderRevealed = preheaderRevealed !== null ? preheaderRevealed : !!preheader;
124
+ const handleShowPreheaderClick = useCallback(() => setPreheaderRevealed(true), []);
125
+ const handleRemovePreheaderClick = useCallback(() => {
126
+ setPreheader('');
127
+ setPreheaderError('');
128
+ setPreheaderRevealed(false);
129
+ }, []);
114
130
  // State for template name (extracted from template data in Edit mode)
115
131
  const [extractedTemplateName, setExtractedTemplateName] = useState('');
116
132
  const [tagValidationError, setTagValidationError] = useState(null);
@@ -183,6 +199,7 @@ const EmailHTMLEditor = (props) => {
183
199
  base: true,
184
200
  },
185
201
  'template-subject': subject || '',
202
+ 'template-preheader': preheader || '',
186
203
  };
187
204
  },
188
205
  getContentForPreview: () => htmlContent || '',
@@ -206,7 +223,7 @@ const EmailHTMLEditor = (props) => {
206
223
  html: 0, label: 0, liquid: 0, total: 0,
207
224
  };
208
225
  },
209
- }), [htmlContent, subject, currentOrgDetails]);
226
+ }), [htmlContent, subject, preheader, currentOrgDetails]);
210
227
 
211
228
  // Detect edit mode: when isEditEmail is false (create flow), never treat as edit or fetch template details
212
229
  const hasParamsId = params?.id || location?.query?.id || location?.params?.id || location?.pathname?.includes('/edit/');
@@ -296,6 +313,7 @@ const EmailHTMLEditor = (props) => {
296
313
  lastTemplateIdRef.current = currentTemplateId;
297
314
  setHtmlContent('');
298
315
  setSubject('');
316
+ setPreheader('');
299
317
  setExtractedTemplateName('');
300
318
  baselineContentRef.current = null;
301
319
  setHasContentChanged(false);
@@ -324,11 +342,13 @@ const EmailHTMLEditor = (props) => {
324
342
  if (hasCompleteTemplateData && !contentInitializedRef.current) {
325
343
  let extractedContent = '';
326
344
  let extractedSubject = '';
345
+ let extractedPreheader = '';
327
346
  let extractedName = '';
328
347
 
329
348
  if (templateDataProp.base) {
330
349
  extractedContent = templateDataProp.base['template-content'] || templateDataProp.base.html_content || templateDataProp.base.emailBody || '';
331
350
  extractedSubject = templateDataProp.base.subject || templateDataProp.base.emailSubject || '';
351
+ extractedPreheader = templateDataProp.base.preheader || '';
332
352
  } else if (templateDataProp.versions && templateDataProp.versions.base) {
333
353
  const { base } = templateDataProp.versions;
334
354
  const activeTab = base.activeTab || 'en';
@@ -341,9 +361,11 @@ const EmailHTMLEditor = (props) => {
341
361
  || '';
342
362
 
343
363
  extractedSubject = base.subject || base.emailSubject || '';
364
+ extractedPreheader = base.preheader || '';
344
365
  } else {
345
366
  extractedContent = templateDataProp['template-content'] || templateDataProp.emailBody || templateDataProp.html_content || '';
346
367
  extractedSubject = templateDataProp.emailSubject || templateDataProp.subject || '';
368
+ extractedPreheader = templateDataProp.preheader || '';
347
369
  }
348
370
 
349
371
  // Extract template name from templateDataProp
@@ -354,6 +376,7 @@ const EmailHTMLEditor = (props) => {
354
376
  setHtmlContent(extractedContent);
355
377
  setLoadedHtmlContent(extractedContent);
356
378
  setSubject(extractedSubject);
379
+ setPreheader(extractedPreheader);
357
380
  setExtractedTemplateName(extractedName);
358
381
  contentInitializedRef.current = true;
359
382
  subjectInitializedRef.current = true;
@@ -425,6 +448,11 @@ const EmailHTMLEditor = (props) => {
425
448
  || get(templateDataFromRedux, 'versions.base.subject')
426
449
  || '';
427
450
 
451
+ const extractedPreheader = baseData.preheader
452
+ || get(templateDataFromRedux, 'preheader')
453
+ || get(templateDataFromRedux, 'versions.base.preheader')
454
+ || '';
455
+
428
456
  // Extract template name from Redux data
429
457
  const extractedName = templateDataFromRedux.name || '';
430
458
 
@@ -438,6 +466,7 @@ const EmailHTMLEditor = (props) => {
438
466
  if (!contentInitializedRef.current || htmlContent === loadedHtmlContent) {
439
467
  setHtmlContent(extractedContent);
440
468
  setSubject(extractedSubject);
469
+ setPreheader(extractedPreheader);
441
470
  setExtractedTemplateName(extractedName);
442
471
  }
443
472
  } else if (!contentInitializedRef.current) {
@@ -445,6 +474,7 @@ const EmailHTMLEditor = (props) => {
445
474
  setHtmlContent(extractedContent);
446
475
  setLoadedHtmlContent(extractedContent);
447
476
  setSubject(extractedSubject);
477
+ setPreheader(extractedPreheader);
448
478
  setExtractedTemplateName(extractedName);
449
479
  }
450
480
 
@@ -470,6 +500,7 @@ const EmailHTMLEditor = (props) => {
470
500
  setHtmlContent('');
471
501
  setLoadedHtmlContent(''); // Set stable loaded content
472
502
  setSubject('');
503
+ setPreheader('');
473
504
  setExtractedTemplateName('');
474
505
  setIsLoading(false);
475
506
  if (setIsLoadingContent) {
@@ -676,6 +707,53 @@ const EmailHTMLEditor = (props) => {
676
707
  }
677
708
  }, [subjectError]);
678
709
 
710
+ // Handle tag insertion into Pre-header field
711
+ const handlePreheaderTagSelect = useCallback((data) => {
712
+ if (data) {
713
+ const tagToInsert = `{{${data}}}`;
714
+ const input = document.getElementById('template-preheader') || document.querySelector('#template-preheader input');
715
+ let preheaderValue = preheader || '';
716
+ try {
717
+ if (input && (typeof input.selectionStart === 'number')) {
718
+ const startPos = input.selectionStart;
719
+ const endPos = input.selectionEnd;
720
+ preheaderValue = `${preheaderValue.substring(0, startPos)}${tagToInsert}${preheaderValue.substring(endPos)}`;
721
+ setPreheader(preheaderValue);
722
+ try {
723
+ input.focus();
724
+ const newPos = startPos + tagToInsert.length;
725
+ input.selectionStart = newPos;
726
+ input.selectionEnd = newPos;
727
+ } catch (e) {
728
+ // Ignore focus errors
729
+ }
730
+ } else {
731
+ preheaderValue = `${preheaderValue}${tagToInsert}`;
732
+ setPreheader(preheaderValue);
733
+ if (input) {
734
+ try {
735
+ input.value = preheaderValue;
736
+ } catch (e) {
737
+ // Ignore value setting errors
738
+ }
739
+ }
740
+ }
741
+ } catch (e) {
742
+ // Fallback: safe append
743
+ preheaderValue = `${preheaderValue}${tagToInsert}`;
744
+ setPreheader(preheaderValue);
745
+ }
746
+ }
747
+ }, [preheader]);
748
+
749
+ // Handle pre-header change
750
+ const handlePreheaderChange = useCallback((e) => {
751
+ setPreheader(e.target.value);
752
+ if (preheaderError) {
753
+ setPreheaderError('');
754
+ }
755
+ }, [preheaderError]);
756
+
679
757
  // Handle Save/Update with liquid validation
680
758
  const handleSave = useCallback(() => {
681
759
  // IMPORTANT: Clear API validation errors FIRST before checking for validation errors
@@ -704,6 +782,15 @@ const EmailHTMLEditor = (props) => {
704
782
  setSubjectError('');
705
783
  }
706
784
 
785
+ // 1.1. Validate Pre-header - BLOCKING: must never contain the unsubscribe tag
786
+ if (hasUnsubscribeTag(preheader)) {
787
+ setPreheaderError(formatMessage(messages.unsubscribeNotAllowedInPreheader));
788
+ if (onValidationFail) {
789
+ onValidationFail();
790
+ }
791
+ return;
792
+ }
793
+
707
794
  // 1.5. Check for validation errors (Errors = blocking, Warnings = non-blocking)
708
795
  // Get issue counts from ref or stored state
709
796
  let issueCounts = { errors: 0, warnings: 0, total: 0 };
@@ -835,6 +922,7 @@ const EmailHTMLEditor = (props) => {
835
922
  base: true,
836
923
  tabKey,
837
924
  subject: subject || '',
925
+ preheader: preheader || '',
838
926
  };
839
927
 
840
928
  const historyEntry = {
@@ -844,6 +932,7 @@ const EmailHTMLEditor = (props) => {
844
932
  base: true,
845
933
  tabKey,
846
934
  subject: subject || '',
935
+ preheader: preheader || '',
847
936
  };
848
937
 
849
938
  // Opened in edit mode: name from the loaded template; created in this session: the name entered for it
@@ -944,6 +1033,7 @@ const EmailHTMLEditor = (props) => {
944
1033
  secondary_templates: [{ template_data: tmpData }],
945
1034
  };
946
1035
  libraryPayload.base.subject = subject || '';
1036
+ libraryPayload.base.preheader = preheader || '';
947
1037
 
948
1038
  if (location?.query?.module === 'library' && isGetFormData && getFormdata) {
949
1039
  const response = {
@@ -1006,6 +1096,7 @@ const EmailHTMLEditor = (props) => {
1006
1096
  }
1007
1097
  }, [
1008
1098
  subject,
1099
+ preheader,
1009
1100
  htmlContent,
1010
1101
  tags,
1011
1102
  injectedTags,
@@ -1142,7 +1233,7 @@ const EmailHTMLEditor = (props) => {
1142
1233
  <CapRow>
1143
1234
  <CapColumn span={24}>
1144
1235
  {/* Subject Field */}
1145
- <CapColumn span={24} style={{ marginBottom: CAP_SPACE_16 }}>
1236
+ <CapColumn span={24} className="email-html-editor-field">
1146
1237
  <CapTagListWithInput
1147
1238
  inputId="template-subject"
1148
1239
  inputValue={subject}
@@ -1150,9 +1241,13 @@ const EmailHTMLEditor = (props) => {
1150
1241
  inputPlaceholder={formatMessage(messages.enterEmailSubject)}
1151
1242
  inputRequired
1152
1243
  inputErrorMessage={subjectError}
1153
- headingText={formatMessage(messages.subject)}
1154
- headingType="h4"
1155
- headingStyle={{ marginRight: '85%' }}
1244
+ inputProps={{
1245
+ prefix: (
1246
+ <CapLabelInline type="label2" className="email-html-editor-prefix email-html-editor-prefix-label">
1247
+ {formatMessage(messages.subject)}
1248
+ </CapLabelInline>
1249
+ ),
1250
+ }}
1156
1251
  onTagSelect={handleSubjectTagSelect}
1157
1252
  onContextChange={handleOnTagsContextChange}
1158
1253
  location={location}
@@ -1161,9 +1256,77 @@ const EmailHTMLEditor = (props) => {
1161
1256
  selectedOfferDetails={selectedOfferDetails}
1162
1257
  eventContextTags={eventContextTags}
1163
1258
  waitEventContextTags={waitEventContextTags}
1164
- showHeading
1259
+ showHeading={false}
1260
+ showTagList
1261
+ showInput
1262
+ singleLineLayout
1263
+ extraContent={!isPreheaderRevealed ? (
1264
+ <CapButton
1265
+ type="dashed"
1266
+ size="small"
1267
+ className="email-html-editor-add-preheader-btn"
1268
+ onClick={handleShowPreheaderClick}
1269
+ >
1270
+ {formatMessage(messages.addPreheader)}
1271
+ </CapButton>
1272
+ ) : null}
1273
+ containerStyle={{
1274
+ display: 'flex',
1275
+ flexDirection: 'column',
1276
+ }}
1277
+ popoverPlacement="bottomRight"
1278
+ />
1279
+ </CapColumn>
1280
+
1281
+ {/* Pre-header Field */}
1282
+ {isPreheaderRevealed && (
1283
+ <CapColumn span={24} className="email-html-editor-field">
1284
+ <CapTagListWithInput
1285
+ inputId="template-preheader"
1286
+ inputValue={preheader}
1287
+ inputOnChange={handlePreheaderChange}
1288
+ inputPlaceholder={formatMessage(messages.enterEmailPreheader)}
1289
+ inputMaxLength={85}
1290
+ inputErrorMessage={preheaderError}
1291
+ excludeTags={PREHEADER_EXCLUDED_TAGS}
1292
+ inputProps={{
1293
+ prefix: (
1294
+ <CapRow align="middle" type="flex" noWrap gap={4} className="email-html-editor-prefix">
1295
+ <CapLabelInline type="label2" className="email-html-editor-prefix-label">
1296
+ {formatMessage(messages.preheader)}
1297
+ </CapLabelInline>
1298
+ <CapTooltipWithInfo title={formatMessage(messages.preheaderInfoTooltip)} />
1299
+ </CapRow>
1300
+ ),
1301
+ suffix: (
1302
+ <CapRow align="middle" type="flex" noWrap gap={8}>
1303
+ <CapLabelInline type="label1" className="email-html-editor-counter">
1304
+ {`${(preheader || '').length} / 85`}
1305
+ </CapLabelInline>
1306
+ <CapLabelInline
1307
+ type="label1"
1308
+ role="button"
1309
+ tabIndex={0}
1310
+ className="email-html-editor-remove-link"
1311
+ onClick={handleRemovePreheaderClick}
1312
+ >
1313
+ {formatMessage(messages.removePreheader)}
1314
+ </CapLabelInline>
1315
+ </CapRow>
1316
+ ),
1317
+ }}
1318
+ onTagSelect={handlePreheaderTagSelect}
1319
+ onContextChange={handleOnTagsContextChange}
1320
+ location={location}
1321
+ tags={tags}
1322
+ injectedTags={injectedTags || {}}
1323
+ selectedOfferDetails={selectedOfferDetails}
1324
+ eventContextTags={eventContextTags}
1325
+ waitEventContextTags={waitEventContextTags}
1326
+ showHeading={false}
1165
1327
  showTagList
1166
1328
  showInput
1329
+ singleLineLayout
1167
1330
  containerStyle={{
1168
1331
  display: 'flex',
1169
1332
  flexDirection: 'column',
@@ -1171,6 +1334,7 @@ const EmailHTMLEditor = (props) => {
1171
1334
  popoverPlacement="bottomRight"
1172
1335
  />
1173
1336
  </CapColumn>
1337
+ )}
1174
1338
 
1175
1339
  <CapColumn span={24} className="html-editor-options-column">
1176
1340
  <CapDropdown