@capillarytech/creatives-library 8.0.263 → 8.0.265

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 (280) hide show
  1. package/assets/Android.png +0 -0
  2. package/assets/iOS.png +0 -0
  3. package/constants/unified.js +1 -3
  4. package/initialReducer.js +0 -2
  5. package/package.json +1 -1
  6. package/services/api.js +0 -15
  7. package/services/tests/api.test.js +0 -34
  8. package/tests/integration/TemplateCreation/TemplateCreation.integration.test.js +35 -17
  9. package/tests/integration/TemplateCreation/api-response.js +1 -31
  10. package/tests/integration/TemplateCreation/msw-handler.js +0 -2
  11. package/utils/common.js +0 -11
  12. package/utils/commonUtils.js +5 -28
  13. package/utils/tests/commonUtil.test.js +0 -224
  14. package/utils/tests/transformerUtils.test.js +0 -297
  15. package/utils/transformTemplateConfig.js +10 -0
  16. package/utils/transformerUtils.js +0 -40
  17. package/v2Components/CapDeviceContent/index.js +56 -61
  18. package/v2Components/CapImageUpload/constants.js +0 -2
  19. package/v2Components/CapImageUpload/index.js +16 -65
  20. package/v2Components/CapImageUpload/index.scss +1 -4
  21. package/v2Components/CapImageUpload/messages.js +1 -5
  22. package/v2Components/CapTagList/index.js +1 -6
  23. package/v2Components/CapTagListWithInput/index.js +1 -5
  24. package/v2Components/CapTagListWithInput/messages.js +1 -1
  25. package/v2Components/CapWhatsappCTA/tests/index.test.js +0 -5
  26. package/v2Components/ErrorInfoNote/index.js +72 -402
  27. package/v2Components/ErrorInfoNote/messages.js +6 -32
  28. package/v2Components/ErrorInfoNote/style.scss +6 -278
  29. package/v2Components/FormBuilder/tests/index.test.js +4 -13
  30. package/v2Components/HtmlEditor/HTMLEditor.js +99 -418
  31. package/v2Components/HtmlEditor/__tests__/HTMLEditor.test.js +133 -1882
  32. package/v2Components/HtmlEditor/__tests__/index.lazy.test.js +16 -27
  33. package/v2Components/HtmlEditor/_htmlEditor.scss +45 -108
  34. package/v2Components/HtmlEditor/_index.lazy.scss +1 -0
  35. package/v2Components/HtmlEditor/components/CodeEditorPane/_codeEditorPane.scss +102 -23
  36. package/v2Components/HtmlEditor/components/CodeEditorPane/index.js +140 -148
  37. package/v2Components/HtmlEditor/components/DeviceToggle/_deviceToggle.scss +1 -2
  38. package/v2Components/HtmlEditor/components/DeviceToggle/index.js +3 -3
  39. package/v2Components/HtmlEditor/components/EditorToolbar/_editorToolbar.scss +1 -9
  40. package/v2Components/HtmlEditor/components/EditorToolbar/index.js +6 -31
  41. package/v2Components/HtmlEditor/components/FullscreenModal/_fullscreenModal.scss +0 -22
  42. package/v2Components/HtmlEditor/components/InAppPreviewPane/DeviceFrame.js +7 -4
  43. package/v2Components/HtmlEditor/components/InAppPreviewPane/__tests__/DeviceFrame.test.js +45 -35
  44. package/v2Components/HtmlEditor/components/InAppPreviewPane/_inAppPreviewPane.scss +3 -1
  45. package/v2Components/HtmlEditor/components/InAppPreviewPane/constants.js +33 -33
  46. package/v2Components/HtmlEditor/components/InAppPreviewPane/index.js +6 -7
  47. package/v2Components/HtmlEditor/components/PreviewPane/_previewPane.scss +10 -7
  48. package/v2Components/HtmlEditor/components/PreviewPane/index.js +43 -22
  49. package/v2Components/HtmlEditor/components/SplitContainer/_splitContainer.scss +1 -1
  50. package/v2Components/HtmlEditor/components/ValidationErrorDisplay/__tests__/index.test.js +152 -0
  51. package/v2Components/HtmlEditor/components/ValidationErrorDisplay/_validationErrorDisplay.scss +0 -18
  52. package/v2Components/HtmlEditor/components/ValidationErrorDisplay/index.js +31 -36
  53. package/v2Components/HtmlEditor/components/ValidationPanel/_validationPanel.scss +34 -46
  54. package/v2Components/HtmlEditor/components/ValidationPanel/index.js +46 -52
  55. package/v2Components/HtmlEditor/constants.js +20 -45
  56. package/v2Components/HtmlEditor/hooks/__tests__/useInAppContent.test.js +16 -373
  57. package/v2Components/HtmlEditor/hooks/__tests__/useValidation.test.js +16 -351
  58. package/v2Components/HtmlEditor/hooks/useEditorContent.js +2 -5
  59. package/v2Components/HtmlEditor/hooks/useInAppContent.js +146 -88
  60. package/v2Components/HtmlEditor/hooks/useValidation.js +56 -213
  61. package/v2Components/HtmlEditor/index.js +1 -1
  62. package/v2Components/HtmlEditor/messages.js +94 -102
  63. package/v2Components/HtmlEditor/utils/__tests__/htmlValidator.enhanced.test.js +45 -214
  64. package/v2Components/HtmlEditor/utils/__tests__/validationAdapter.test.js +0 -134
  65. package/v2Components/HtmlEditor/utils/contentSanitizer.js +41 -40
  66. package/v2Components/HtmlEditor/utils/htmlValidator.js +72 -71
  67. package/v2Components/HtmlEditor/utils/liquidTemplateSupport.js +124 -158
  68. package/v2Components/HtmlEditor/utils/properSyntaxHighlighting.js +25 -23
  69. package/v2Components/HtmlEditor/utils/validationAdapter.js +41 -66
  70. package/v2Components/MobilePushPreviewV2/index.js +7 -33
  71. package/v2Components/TemplatePreview/_templatePreview.scss +24 -55
  72. package/v2Components/TemplatePreview/index.js +32 -47
  73. package/v2Components/TemplatePreview/messages.js +0 -4
  74. package/v2Components/TestAndPreviewSlidebox/_testAndPreviewSlidebox.scss +0 -1
  75. package/v2Containers/App/constants.js +0 -5
  76. package/v2Containers/BeeEditor/index.js +90 -172
  77. package/v2Containers/CreativesContainer/SlideBoxContent.js +53 -184
  78. package/v2Containers/CreativesContainer/SlideBoxFooter.js +13 -163
  79. package/v2Containers/CreativesContainer/SlideBoxHeader.js +1 -3
  80. package/v2Containers/CreativesContainer/constants.js +0 -4
  81. package/v2Containers/CreativesContainer/index.js +46 -408
  82. package/v2Containers/CreativesContainer/messages.js +0 -12
  83. package/v2Containers/CreativesContainer/tests/SlideBoxContent.test.js +0 -210
  84. package/v2Containers/CreativesContainer/tests/SlideBoxFooter.test.js +2 -11
  85. package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxContent.test.js.snap +50 -342
  86. package/v2Containers/CreativesContainer/tests/__snapshots__/index.test.js.snap +0 -103
  87. package/v2Containers/Email/actions.js +0 -7
  88. package/v2Containers/Email/constants.js +1 -5
  89. package/v2Containers/Email/index.js +36 -237
  90. package/v2Containers/Email/messages.js +0 -32
  91. package/v2Containers/Email/reducer.js +1 -12
  92. package/v2Containers/Email/sagas.js +7 -61
  93. package/v2Containers/Email/tests/__snapshots__/reducer.test.js.snap +0 -2
  94. package/v2Containers/Email/tests/reducer.test.js +0 -46
  95. package/v2Containers/Email/tests/sagas.test.js +29 -320
  96. package/v2Containers/EmailWrapper/components/EmailWrapperView.js +21 -211
  97. package/v2Containers/EmailWrapper/components/HTMLEditorTesting.js +74 -40
  98. package/v2Containers/EmailWrapper/components/__tests__/HTMLEditorTesting.test.js +67 -2
  99. package/v2Containers/EmailWrapper/constants.js +0 -2
  100. package/v2Containers/EmailWrapper/hooks/useEmailWrapper.js +77 -629
  101. package/v2Containers/EmailWrapper/index.js +23 -103
  102. package/v2Containers/EmailWrapper/messages.js +1 -65
  103. package/v2Containers/EmailWrapper/tests/EmailWrapperView.test.js +214 -0
  104. package/v2Containers/EmailWrapper/tests/useEmailWrapper.test.js +77 -594
  105. package/v2Containers/InApp/actions.js +0 -7
  106. package/v2Containers/InApp/constants.js +4 -20
  107. package/v2Containers/InApp/index.js +359 -802
  108. package/v2Containers/InApp/index.scss +3 -4
  109. package/v2Containers/InApp/messages.js +3 -7
  110. package/v2Containers/InApp/reducer.js +3 -21
  111. package/v2Containers/InApp/sagas.js +9 -29
  112. package/v2Containers/InApp/selectors.js +5 -25
  113. package/v2Containers/InApp/tests/index.test.js +50 -154
  114. package/v2Containers/InApp/tests/reducer.test.js +0 -34
  115. package/v2Containers/InApp/tests/sagas.test.js +9 -61
  116. package/v2Containers/Line/Container/ImageCarousel/tests/__snapshots__/content.test.js.snap +0 -3
  117. package/v2Containers/Line/Container/ImageCarousel/tests/__snapshots__/index.test.js.snap +0 -2
  118. package/v2Containers/Line/Container/Wrapper/tests/__snapshots__/index.test.js.snap +0 -2
  119. package/v2Containers/Line/Container/tests/__snapshots__/index.test.js.snap +0 -9
  120. package/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +0 -12
  121. package/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +0 -4
  122. package/v2Containers/TagList/index.js +19 -62
  123. package/v2Containers/Templates/ChannelTypeIllustration.js +1 -13
  124. package/v2Containers/Templates/_templates.scss +1 -265
  125. package/v2Containers/Templates/actions.js +1 -2
  126. package/v2Containers/Templates/constants.js +0 -1
  127. package/v2Containers/Templates/index.js +38 -363
  128. package/v2Containers/Templates/messages.js +0 -28
  129. package/v2Containers/Templates/reducer.js +0 -2
  130. package/v2Containers/Templates/tests/index.test.js +0 -10
  131. package/v2Containers/TemplatesV2/TemplatesV2.style.js +2 -4
  132. package/v2Containers/TemplatesV2/index.js +7 -15
  133. package/v2Containers/TemplatesV2/messages.js +0 -4
  134. package/v2Containers/Whatsapp/tests/__snapshots__/index.test.js.snap +0 -34
  135. package/utils/imageUrlUpload.js +0 -141
  136. package/v2Components/CapImageUrlUpload/constants.js +0 -26
  137. package/v2Components/CapImageUrlUpload/index.js +0 -365
  138. package/v2Components/CapImageUrlUpload/index.scss +0 -35
  139. package/v2Components/CapImageUrlUpload/messages.js +0 -47
  140. package/v2Components/ErrorInfoNote/constants.js +0 -1
  141. package/v2Components/HtmlEditor/__tests__/HTMLEditor.apiErrors.test.js +0 -870
  142. package/v2Components/HtmlEditor/components/ValidationPanel/constants.js +0 -6
  143. package/v2Components/HtmlEditor/components/ValidationTabs/_validationTabs.scss +0 -281
  144. package/v2Components/HtmlEditor/components/ValidationTabs/index.js +0 -295
  145. package/v2Components/HtmlEditor/components/ValidationTabs/messages.js +0 -51
  146. package/v2Components/HtmlEditor/utils/validationConstants.js +0 -38
  147. package/v2Components/MobilePushPreviewV2/constants.js +0 -6
  148. package/v2Containers/BeePopupEditor/_beePopupEditor.scss +0 -14
  149. package/v2Containers/BeePopupEditor/constants.js +0 -10
  150. package/v2Containers/BeePopupEditor/index.js +0 -194
  151. package/v2Containers/BeePopupEditor/tests/index.test.js +0 -627
  152. package/v2Containers/EmailWrapper/components/EmailHTMLEditor.js +0 -1246
  153. package/v2Containers/EmailWrapper/components/__tests__/EmailHTMLEditor.test.js +0 -2472
  154. package/v2Containers/EmailWrapper/components/__tests__/EmailWrapperView.test.js +0 -520
  155. package/v2Containers/EmailWrapper/tests/useEmailWrapper.edgeCases.test.js +0 -956
  156. package/v2Containers/InApp/__tests__/InAppHTMLEditor.test.js +0 -376
  157. package/v2Containers/InApp/__tests__/sagas.test.js +0 -363
  158. package/v2Containers/InApp/tests/selectors.test.js +0 -612
  159. package/v2Containers/InAppWrapper/components/InAppWrapperView.js +0 -151
  160. package/v2Containers/InAppWrapper/components/__tests__/InAppWrapperView.test.js +0 -267
  161. package/v2Containers/InAppWrapper/components/inAppWrapperView.scss +0 -23
  162. package/v2Containers/InAppWrapper/constants.js +0 -16
  163. package/v2Containers/InAppWrapper/hooks/__tests__/useInAppWrapper.test.js +0 -473
  164. package/v2Containers/InAppWrapper/hooks/useInAppWrapper.js +0 -198
  165. package/v2Containers/InAppWrapper/index.js +0 -148
  166. package/v2Containers/InAppWrapper/messages.js +0 -49
  167. package/v2Containers/InappAdvance/index.js +0 -1099
  168. package/v2Containers/InappAdvance/index.scss +0 -10
  169. package/v2Containers/InappAdvance/tests/index.test.js +0 -448
  170. package/v2Containers/WebPush/Create/components/BrandIconSection.js +0 -108
  171. package/v2Containers/WebPush/Create/components/ButtonForm.js +0 -172
  172. package/v2Containers/WebPush/Create/components/ButtonItem.js +0 -101
  173. package/v2Containers/WebPush/Create/components/ButtonList.js +0 -145
  174. package/v2Containers/WebPush/Create/components/ButtonsLinksSection.js +0 -164
  175. package/v2Containers/WebPush/Create/components/ButtonsLinksSection.test.js +0 -463
  176. package/v2Containers/WebPush/Create/components/FormActions.js +0 -54
  177. package/v2Containers/WebPush/Create/components/FormActions.test.js +0 -163
  178. package/v2Containers/WebPush/Create/components/MediaSection.js +0 -142
  179. package/v2Containers/WebPush/Create/components/MediaSection.test.js +0 -341
  180. package/v2Containers/WebPush/Create/components/MessageSection.js +0 -103
  181. package/v2Containers/WebPush/Create/components/MessageSection.test.js +0 -268
  182. package/v2Containers/WebPush/Create/components/NotificationTitleSection.js +0 -87
  183. package/v2Containers/WebPush/Create/components/NotificationTitleSection.test.js +0 -210
  184. package/v2Containers/WebPush/Create/components/TemplateNameSection.js +0 -54
  185. package/v2Containers/WebPush/Create/components/TemplateNameSection.test.js +0 -143
  186. package/v2Containers/WebPush/Create/components/__snapshots__/ButtonsLinksSection.test.js.snap +0 -86
  187. package/v2Containers/WebPush/Create/components/__snapshots__/FormActions.test.js.snap +0 -16
  188. package/v2Containers/WebPush/Create/components/__snapshots__/MediaSection.test.js.snap +0 -41
  189. package/v2Containers/WebPush/Create/components/__snapshots__/MessageSection.test.js.snap +0 -54
  190. package/v2Containers/WebPush/Create/components/__snapshots__/NotificationTitleSection.test.js.snap +0 -37
  191. package/v2Containers/WebPush/Create/components/__snapshots__/TemplateNameSection.test.js.snap +0 -21
  192. package/v2Containers/WebPush/Create/components/_buttons.scss +0 -246
  193. package/v2Containers/WebPush/Create/components/tests/ButtonForm.test.js +0 -554
  194. package/v2Containers/WebPush/Create/components/tests/ButtonItem.test.js +0 -607
  195. package/v2Containers/WebPush/Create/components/tests/ButtonList.test.js +0 -633
  196. package/v2Containers/WebPush/Create/components/tests/__snapshots__/ButtonForm.test.js.snap +0 -666
  197. package/v2Containers/WebPush/Create/components/tests/__snapshots__/ButtonItem.test.js.snap +0 -74
  198. package/v2Containers/WebPush/Create/components/tests/__snapshots__/ButtonList.test.js.snap +0 -78
  199. package/v2Containers/WebPush/Create/hooks/useButtonManagement.js +0 -138
  200. package/v2Containers/WebPush/Create/hooks/useButtonManagement.test.js +0 -406
  201. package/v2Containers/WebPush/Create/hooks/useCharacterCount.js +0 -30
  202. package/v2Containers/WebPush/Create/hooks/useCharacterCount.test.js +0 -151
  203. package/v2Containers/WebPush/Create/hooks/useImageUpload.js +0 -104
  204. package/v2Containers/WebPush/Create/hooks/useImageUpload.test.js +0 -538
  205. package/v2Containers/WebPush/Create/hooks/useTagManagement.js +0 -122
  206. package/v2Containers/WebPush/Create/hooks/useTagManagement.test.js +0 -633
  207. package/v2Containers/WebPush/Create/index.js +0 -1148
  208. package/v2Containers/WebPush/Create/index.scss +0 -134
  209. package/v2Containers/WebPush/Create/messages.js +0 -211
  210. package/v2Containers/WebPush/Create/preview/DevicePreviewContent.js +0 -228
  211. package/v2Containers/WebPush/Create/preview/NotificationContainer.js +0 -294
  212. package/v2Containers/WebPush/Create/preview/PreviewContent.js +0 -90
  213. package/v2Containers/WebPush/Create/preview/PreviewControls.js +0 -305
  214. package/v2Containers/WebPush/Create/preview/PreviewDisclaimer.js +0 -25
  215. package/v2Containers/WebPush/Create/preview/WebPushPreview.js +0 -155
  216. package/v2Containers/WebPush/Create/preview/assets/Light.svg +0 -53
  217. package/v2Containers/WebPush/Create/preview/assets/Top.svg +0 -5
  218. package/v2Containers/WebPush/Create/preview/assets/android-arrow-down.svg +0 -9
  219. package/v2Containers/WebPush/Create/preview/assets/android-arrow-up.svg +0 -9
  220. package/v2Containers/WebPush/Create/preview/assets/chrome-icon.png +0 -0
  221. package/v2Containers/WebPush/Create/preview/assets/edge-icon.png +0 -0
  222. package/v2Containers/WebPush/Create/preview/assets/firefox-icon.svg +0 -106
  223. package/v2Containers/WebPush/Create/preview/assets/iOS.svg +0 -26
  224. package/v2Containers/WebPush/Create/preview/assets/macos-arrow-down-icon.svg +0 -9
  225. package/v2Containers/WebPush/Create/preview/assets/macos-triple-dot-icon.svg +0 -9
  226. package/v2Containers/WebPush/Create/preview/assets/opera-icon.svg +0 -18
  227. package/v2Containers/WebPush/Create/preview/assets/safari-icon.svg +0 -29
  228. package/v2Containers/WebPush/Create/preview/assets/windows-close-icon.svg +0 -9
  229. package/v2Containers/WebPush/Create/preview/assets/windows-triple-dot-icon.svg +0 -9
  230. package/v2Containers/WebPush/Create/preview/components/AndroidMobileChromeHeader.js +0 -51
  231. package/v2Containers/WebPush/Create/preview/components/AndroidMobileExpanded.js +0 -145
  232. package/v2Containers/WebPush/Create/preview/components/IOSHeader.js +0 -45
  233. package/v2Containers/WebPush/Create/preview/components/NotificationExpandedContent.js +0 -68
  234. package/v2Containers/WebPush/Create/preview/components/NotificationHeader.js +0 -61
  235. package/v2Containers/WebPush/Create/preview/components/WindowsChromeExpanded.js +0 -99
  236. package/v2Containers/WebPush/Create/preview/components/tests/AndroidMobileExpanded.test.js +0 -733
  237. package/v2Containers/WebPush/Create/preview/components/tests/WindowsChromeExpanded.test.js +0 -571
  238. package/v2Containers/WebPush/Create/preview/components/tests/__snapshots__/AndroidMobileExpanded.test.js.snap +0 -85
  239. package/v2Containers/WebPush/Create/preview/components/tests/__snapshots__/WindowsChromeExpanded.test.js.snap +0 -81
  240. package/v2Containers/WebPush/Create/preview/config/notificationMappings.js +0 -50
  241. package/v2Containers/WebPush/Create/preview/constants.js +0 -637
  242. package/v2Containers/WebPush/Create/preview/notification-container.scss +0 -79
  243. package/v2Containers/WebPush/Create/preview/preview.scss +0 -358
  244. package/v2Containers/WebPush/Create/preview/styles/_android-mobile-chrome.scss +0 -370
  245. package/v2Containers/WebPush/Create/preview/styles/_android-mobile-edge.scss +0 -12
  246. package/v2Containers/WebPush/Create/preview/styles/_android-mobile-firefox.scss +0 -12
  247. package/v2Containers/WebPush/Create/preview/styles/_android-mobile-opera.scss +0 -12
  248. package/v2Containers/WebPush/Create/preview/styles/_android-tablet-chrome.scss +0 -47
  249. package/v2Containers/WebPush/Create/preview/styles/_android-tablet-edge.scss +0 -11
  250. package/v2Containers/WebPush/Create/preview/styles/_android-tablet-firefox.scss +0 -11
  251. package/v2Containers/WebPush/Create/preview/styles/_android-tablet-opera.scss +0 -11
  252. package/v2Containers/WebPush/Create/preview/styles/_base.scss +0 -207
  253. package/v2Containers/WebPush/Create/preview/styles/_ios.scss +0 -153
  254. package/v2Containers/WebPush/Create/preview/styles/_ipados.scss +0 -107
  255. package/v2Containers/WebPush/Create/preview/styles/_macos-chrome.scss +0 -101
  256. package/v2Containers/WebPush/Create/preview/styles/_windows-chrome.scss +0 -229
  257. package/v2Containers/WebPush/Create/preview/tests/DevicePreviewContent.test.js +0 -909
  258. package/v2Containers/WebPush/Create/preview/tests/NotificationContainer.test.js +0 -1081
  259. package/v2Containers/WebPush/Create/preview/tests/PreviewControls.test.js +0 -723
  260. package/v2Containers/WebPush/Create/preview/tests/WebPushPreview.test.js +0 -1327
  261. package/v2Containers/WebPush/Create/preview/tests/__snapshots__/DevicePreviewContent.test.js.snap +0 -131
  262. package/v2Containers/WebPush/Create/preview/tests/__snapshots__/NotificationContainer.test.js.snap +0 -112
  263. package/v2Containers/WebPush/Create/preview/tests/__snapshots__/PreviewControls.test.js.snap +0 -144
  264. package/v2Containers/WebPush/Create/preview/tests/__snapshots__/WebPushPreview.test.js.snap +0 -129
  265. package/v2Containers/WebPush/Create/utils/payloadBuilder.js +0 -96
  266. package/v2Containers/WebPush/Create/utils/payloadBuilder.test.js +0 -396
  267. package/v2Containers/WebPush/Create/utils/previewUtils.js +0 -89
  268. package/v2Containers/WebPush/Create/utils/urlValidation.js +0 -115
  269. package/v2Containers/WebPush/Create/utils/urlValidation.test.js +0 -449
  270. package/v2Containers/WebPush/Create/utils/validation.js +0 -75
  271. package/v2Containers/WebPush/Create/utils/validation.test.js +0 -283
  272. package/v2Containers/WebPush/actions.js +0 -60
  273. package/v2Containers/WebPush/constants.js +0 -132
  274. package/v2Containers/WebPush/index.js +0 -2
  275. package/v2Containers/WebPush/reducer.js +0 -104
  276. package/v2Containers/WebPush/sagas.js +0 -119
  277. package/v2Containers/WebPush/selectors.js +0 -65
  278. package/v2Containers/WebPush/tests/reducer.test.js +0 -863
  279. package/v2Containers/WebPush/tests/sagas.test.js +0 -566
  280. package/v2Containers/WebPush/tests/selectors.test.js +0 -960
@@ -15,13 +15,13 @@
15
15
  * - Filters dangerous protocols (javascript:, data:, vbscript:)
16
16
  * - Variant-aware sanitization (EMAIL vs INAPP with different security levels)
17
17
  * - Iframe sandbox uses "allow-scripts" only (no allow-same-origin for security)
18
- * - Content delivered via srcdoc attribute for CSP compliance (replaces blob URLs)
18
+ * - Content delivered via blob URLs to isolate iframe from parent origin
19
19
  *
20
20
  * Previous Security Issues (FIXED):
21
21
  * - Removed insecure manual sanitizeJavaScript function that only escaped </script> tags
22
22
  * - Replaced with robust DOMPurify-based sanitization for full XSS protection
23
23
  * - Removed "allow-same-origin" from iframe sandbox to prevent same-origin access
24
- * - Replaced blob URLs with srcdoc to comply with CSP frame-src directives
24
+ * - Implemented blob URL delivery to maintain isolation while allowing script execution
25
25
  */
26
26
 
27
27
  import React, { useMemo, useEffect, useRef } from 'react';
@@ -55,7 +55,7 @@ const PreviewPane = ({
55
55
  className = '',
56
56
  isFullscreenMode = false,
57
57
  isModalContext = false,
58
- layoutType = LAYOUT_TYPES.MODAL,
58
+ layoutType = LAYOUT_TYPES.MODAL
59
59
  }) => {
60
60
  const { content, layout, variant } = useEditorContext();
61
61
 
@@ -103,25 +103,36 @@ const PreviewPane = ({
103
103
  return sanitizationResult.sanitized;
104
104
  }, [contentValue, variant]);
105
105
 
106
- // Use srcdoc instead of blob URLs for CSP compliance
107
- // srcdoc allows embedding HTML directly in iframe without violating frame-src CSP directives
108
- // This is more secure and CSP-compliant than blob URLs
109
- const iframeContent = useMemo(() => {
110
- if (!combinedContent) {
111
- return null;
106
+ // Create blob URL for secure iframe content delivery
107
+ // This isolates the iframe content from the parent origin while allowing script execution
108
+ const blobUrlRef = useRef(null);
109
+ const blobUrl = useMemo(() => {
110
+ // Clean up previous blob URL to prevent memory leaks
111
+ if (blobUrlRef.current) {
112
+ URL.revokeObjectURL(blobUrlRef.current);
113
+ blobUrlRef.current = null;
112
114
  }
113
115
 
114
- // srcdoc has a size limit (~2MB in some browsers), but for HTML preview content this should be sufficient
115
- // If content is too large, we'll fall back to about:blank and log a warning
116
- const MAX_SRCDOC_SIZE = 2000000; // 2MB limit
117
- if (combinedContent.length > MAX_SRCDOC_SIZE) {
118
- console.warn('PreviewPane: Content too large for srcdoc, using about:blank');
119
- return null;
116
+ // Create new blob URL if we have content
117
+ if (combinedContent) {
118
+ const blob = new Blob([combinedContent], { type: 'text/html' });
119
+ blobUrlRef.current = URL.createObjectURL(blob);
120
+ return blobUrlRef.current;
120
121
  }
121
122
 
122
- return combinedContent;
123
+ return null;
123
124
  }, [combinedContent]);
124
125
 
126
+ // Cleanup blob URL on unmount
127
+ useEffect(() => {
128
+ return () => {
129
+ if (blobUrlRef.current) {
130
+ URL.revokeObjectURL(blobUrlRef.current);
131
+ blobUrlRef.current = null;
132
+ }
133
+ };
134
+ }, []);
135
+
125
136
  // Generate CSS classes based on view mode
126
137
  const getIframeClasses = () => {
127
138
  const baseClass = 'preview-pane__iframe';
@@ -143,15 +154,15 @@ const PreviewPane = ({
143
154
  // Use layout.mobileWidth or fallback to 375px
144
155
  const width = mobileWidth || 375;
145
156
  baseStyles.width = `${width}px`;
157
+ baseStyles.height = '100%'; // Fill container height
146
158
  }
147
- baseStyles.height = '100%'; // Fill container height
159
+
148
160
  return baseStyles;
149
161
  };
150
162
 
151
163
  const renderDeviceFrame = () => (
152
164
  <iframe
153
- src={iframeContent ? undefined : 'about:blank'}
154
- srcDoc={iframeContent || undefined}
165
+ src={blobUrl || 'about:blank'}
155
166
  title={intl.formatMessage(messages.htmlPreview)}
156
167
  className={getIframeClasses()}
157
168
  style={getPreviewStyles()}
@@ -162,7 +173,17 @@ const PreviewPane = ({
162
173
  const renderEmptyState = () => (
163
174
  <div className="preview-empty">
164
175
  <div className="empty-content">
165
- <p className="preview-mode-info"></p>
176
+ <div className="empty-icon">📝</div>
177
+ <p>{intl.formatMessage(messages.startTypingHtml)}</p>
178
+ <p className="preview-mode-info">
179
+ {intl.formatMessage(messages.previewMode)}: {
180
+ viewMode === PREVIEW_MODES.DESKTOP
181
+ ? intl.formatMessage(messages.desktop)
182
+ : viewMode === PREVIEW_MODES.MOBILE
183
+ ? intl.formatMessage(messages.mobile)
184
+ : intl.formatMessage(messages.mobileDevice)
185
+ }
186
+ </p>
166
187
  </div>
167
188
  </div>
168
189
  );
@@ -191,7 +212,7 @@ const PreviewPane = ({
191
212
  </CapRow>
192
213
 
193
214
  <CapRow className="preview-pane__content">
194
- {iframeContent ? renderDeviceFrame() : renderEmptyState()}
215
+ {blobUrl ? renderDeviceFrame() : renderEmptyState()}
195
216
  </CapRow>
196
217
  </div>
197
218
  );
@@ -202,7 +223,7 @@ PreviewPane.propTypes = {
202
223
  className: PropTypes.string,
203
224
  isFullscreenMode: PropTypes.bool,
204
225
  isModalContext: PropTypes.bool,
205
- layoutType: PropTypes.oneOf(Object.values(LAYOUT_TYPES)),
226
+ layoutType: PropTypes.oneOf(Object.values(LAYOUT_TYPES))
206
227
  };
207
228
 
208
229
  export default injectIntl(PreviewPane);
@@ -161,7 +161,7 @@
161
161
 
162
162
  // Dragging state styling
163
163
  &--dragging &__splitter {
164
- background-color: map-get($CAP_SECONDARY, base);
164
+ background-color: map-get($CAP_PRIMARY, base);
165
165
  }
166
166
 
167
167
  &--dragging &__splitter-line {
@@ -0,0 +1,152 @@
1
+ /**
2
+ * ValidationErrorDisplay Component Tests
3
+ *
4
+ * Tests for the ValidationErrorDisplay component that integrates with ErrorInfoNote.
5
+ */
6
+
7
+ import React from 'react';
8
+ import { render, screen } from '@testing-library/react';
9
+ import '@testing-library/jest-dom';
10
+ import ValidationErrorDisplay from '../index';
11
+
12
+ // Mock ErrorInfoNote component
13
+ jest.mock('../../../../ErrorInfoNote', () => {
14
+ return function MockErrorInfoNote({ errorMessages }) {
15
+ const liquidErrors = errorMessages?.LIQUID_ERROR_MSG || [];
16
+ const standardErrors = errorMessages?.STANDARD_ERROR_MSG || [];
17
+ const hasErrors = liquidErrors.length > 0 || standardErrors.length > 0;
18
+
19
+ if (!hasErrors) return null;
20
+
21
+ return (
22
+ <div data-testid="error-info-note">
23
+ {liquidErrors.map((msg, index) => (
24
+ <div key={`liquid-${index}`} data-testid="error-message">
25
+ {msg}
26
+ </div>
27
+ ))}
28
+ {standardErrors.map((msg, index) => (
29
+ <div key={`standard-${index}`} data-testid="error-message">
30
+ {msg}
31
+ </div>
32
+ ))}
33
+ </div>
34
+ );
35
+ };
36
+ });
37
+
38
+ describe('ValidationErrorDisplay', () => {
39
+ it('renders standard errors when validation has issues', () => {
40
+ const mockValidation = {
41
+ getAllIssues: () => [
42
+ { message: 'Missing closing tag', severity: 'error', line: 5, column: 10 },
43
+ { message: 'Invalid attribute', severity: 'error', line: 7 }
44
+ ],
45
+ isClean: () => false,
46
+ isValidating: false
47
+ };
48
+
49
+ render(<ValidationErrorDisplay validation={mockValidation} />);
50
+
51
+ expect(screen.getByTestId('error-info-note')).toBeInTheDocument();
52
+ const errorMessages = screen.getAllByTestId('error-message');
53
+ expect(errorMessages).toHaveLength(2);
54
+ expect(errorMessages[0]).toHaveTextContent('Missing closing tag Line 5, Char 10.');
55
+ expect(errorMessages[1]).toHaveTextContent('Invalid attribute Line 7.');
56
+ });
57
+
58
+ it('renders liquid errors separately', () => {
59
+ const mockValidation = {
60
+ getAllIssues: () => [
61
+ { message: 'Invalid liquid syntax', severity: 'error', source: 'liquid-validator', line: 3 },
62
+ { message: 'HTML error', severity: 'error', source: 'htmlhint', line: 10 }
63
+ ],
64
+ isClean: () => false,
65
+ isValidating: false
66
+ };
67
+
68
+ render(<ValidationErrorDisplay validation={mockValidation} />);
69
+
70
+ expect(screen.getByTestId('error-info-note')).toBeInTheDocument();
71
+ const errorMessages = screen.getAllByTestId('error-message');
72
+ expect(errorMessages).toHaveLength(2);
73
+ // First should be liquid error, second should be standard error
74
+ expect(errorMessages[0]).toHaveTextContent('Invalid liquid syntax Line 3.');
75
+ expect(errorMessages[1]).toHaveTextContent('HTML error Line 10.');
76
+ });
77
+
78
+ it('does not render when validation has no errors', () => {
79
+ const mockValidation = {
80
+ getAllIssues: () => [],
81
+ isClean: () => true,
82
+ isValidating: false
83
+ };
84
+
85
+ const { container } = render(<ValidationErrorDisplay validation={mockValidation} />);
86
+
87
+ expect(screen.queryByTestId('error-info-note')).not.toBeInTheDocument();
88
+ expect(container.firstChild).toBeNull();
89
+ });
90
+
91
+ it('does not render when validation is null', () => {
92
+ const { container } = render(<ValidationErrorDisplay validation={null} />);
93
+
94
+ expect(screen.queryByTestId('error-info-note')).not.toBeInTheDocument();
95
+ expect(container.firstChild).toBeNull();
96
+ });
97
+
98
+ it('does not render when validation is in progress', () => {
99
+ const mockValidation = {
100
+ getAllIssues: () => [],
101
+ isClean: () => false,
102
+ isValidating: true
103
+ };
104
+
105
+ const { container } = render(<ValidationErrorDisplay validation={mockValidation} />);
106
+
107
+ expect(screen.queryByTestId('error-info-note')).not.toBeInTheDocument();
108
+ expect(container.firstChild).toBeNull();
109
+ });
110
+
111
+ it('applies custom className', () => {
112
+ const mockValidation = {
113
+ getAllIssues: () => [{ message: 'Error', severity: 'error' }],
114
+ isClean: () => false,
115
+ isValidating: false
116
+ };
117
+
118
+ const { container } = render(
119
+ <ValidationErrorDisplay validation={mockValidation} className="custom-class" />
120
+ );
121
+
122
+ const wrapper = container.querySelector('.validation-error-display');
123
+ expect(wrapper).toHaveClass('custom-class');
124
+ });
125
+
126
+ it('handles inapp variant correctly', () => {
127
+ const mockValidation = {
128
+ getAllIssues: () => [{ message: 'Mobile error', severity: 'error' }],
129
+ isClean: () => false,
130
+ isValidating: false
131
+ };
132
+
133
+ render(<ValidationErrorDisplay validation={mockValidation} variant="inapp" />);
134
+
135
+ expect(screen.getByTestId('error-info-note')).toBeInTheDocument();
136
+ expect(screen.getByTestId('error-message')).toHaveTextContent('Mobile error');
137
+ });
138
+
139
+ it('includes rule information in error messages when available', () => {
140
+ const mockValidation = {
141
+ getAllIssues: () => [
142
+ { message: 'Alt attribute required', severity: 'error', rule: 'alt-require', line: 5 }
143
+ ],
144
+ isClean: () => false,
145
+ isValidating: false
146
+ };
147
+
148
+ render(<ValidationErrorDisplay validation={mockValidation} />);
149
+
150
+ expect(screen.getByTestId('error-message')).toHaveTextContent('Alt attribute required Line 5. • alt-require');
151
+ });
152
+ });
@@ -1,7 +1,5 @@
1
1
  /**
2
2
  * ValidationErrorDisplay Styles
3
- *
4
- * When collapsed, panel sticks to footer (header bar only visible).
5
3
  */
6
4
 
7
5
  @import '~@capillarytech/cap-ui-library/styles/_variables.scss';
@@ -11,18 +9,10 @@
11
9
  flex-direction: column;
12
10
  width: 100%;
13
11
  margin-bottom: 1rem;
14
- flex-shrink: 0;
15
12
 
16
13
  // Ensure proper spacing when used in different contexts
17
14
  &:last-child {
18
15
  margin-bottom: 0;
19
- padding-bottom: 0.25rem;
20
- }
21
-
22
- // Collapsed: panel stays in footer as a slim bar (tabs + expand arrow only)
23
- &--collapsed {
24
- margin-bottom: 0;
25
- padding-bottom: 0.25rem;
26
16
  }
27
17
 
28
18
  // Integration with ErrorInfoNote component
@@ -33,17 +23,9 @@
33
23
  // Responsive adjustments
34
24
  @media (max-width: 768px) {
35
25
  margin-bottom: 0.75rem;
36
-
37
- &.validation-error-display--collapsed {
38
- margin-bottom: 0;
39
- }
40
26
  }
41
27
 
42
28
  @media (max-width: 576px) {
43
29
  margin-bottom: 0.5rem;
44
-
45
- &.validation-error-display--collapsed {
46
- margin-bottom: 0;
47
- }
48
30
  }
49
31
  }
@@ -1,15 +1,18 @@
1
1
  /**
2
- * ValidationErrorDisplay - HTML Editor validation display
2
+ * ValidationErrorDisplay - HTML Editor validation using ErrorInfoNote
3
3
  *
4
- * Displays validation errors and warnings in two tabs (Errors, Warnings).
5
- * Panel can be collapsed to a sticky footer bar; it does not disappear.
4
+ * This component integrates the existing ErrorInfoNote component with the HTML Editor's
5
+ * validation system, providing a consistent error display that matches the Figma design.
6
6
  */
7
7
 
8
- import React, { useState } from 'react';
8
+ import React from 'react';
9
9
  import PropTypes from 'prop-types';
10
10
 
11
- import { hasValidationErrors } from '../../utils/validationAdapter';
12
- import ValidationTabs from '../ValidationTabs';
11
+ import CapRow from '@capillarytech/cap-ui-library/CapRow';
12
+ import ErrorInfoNote from '../../../ErrorInfoNote';
13
+
14
+ import { transformValidationToErrorInfo, hasValidationErrors } from '../../utils/validationAdapter';
15
+ import { HTML_EDITOR_VARIANTS } from '../../constants';
13
16
 
14
17
  // Styles
15
18
  import './_validationErrorDisplay.scss';
@@ -17,59 +20,51 @@ import './_validationErrorDisplay.scss';
17
20
  /**
18
21
  * ValidationErrorDisplay Component
19
22
  *
20
- * Displays validation issues in Errors and Warnings tabs; collapse toggles visibility but panel stays in footer.
23
+ * Displays validation errors using the existing ErrorInfoNote component
21
24
  */
22
25
  const ValidationErrorDisplay = ({
23
26
  validation,
27
+ variant = HTML_EDITOR_VARIANTS.EMAIL,
24
28
  onErrorClick,
25
- className = '',
29
+ className = ''
26
30
  }) => {
27
- const [isCollapsed, setIsCollapsed] = useState(false);
28
-
29
- const handleToggleCollapse = () => {
30
- setIsCollapsed((prev) => !prev);
31
- };
32
-
33
- // Expand panel when user clicks redirection (so panel does not stay stuck to footer)
34
- const handleExpand = () => {
35
- setIsCollapsed(false);
36
- };
37
-
31
+ // Don't render if no validation or no errors
38
32
  if (!hasValidationErrors(validation)) {
39
33
  return null;
40
34
  }
41
35
 
36
+ // Transform validation data to ErrorInfoNote format
37
+ const errorData = transformValidationToErrorInfo(validation, variant);
38
+ const { errorMessages } = errorData || {};
39
+
40
+ // Handle error click if provided
41
+ const handleErrorClick = (error) => {
42
+ onErrorClick?.(error);
43
+ };
44
+
42
45
  return (
43
- <div
44
- className={`validation-error-display ${isCollapsed ? 'validation-error-display--collapsed' : ''} ${className}`}
46
+ <CapRow
47
+ className={`validation-error-display ${className}`}
45
48
  role="alert"
46
49
  aria-live="polite"
47
50
  aria-label="Validation errors"
48
51
  >
49
- <ValidationTabs
50
- validation={validation}
51
- onErrorClick={onErrorClick}
52
- isCollapsed={isCollapsed}
53
- onToggleCollapse={handleToggleCollapse}
54
- onExpand={handleExpand}
52
+ <ErrorInfoNote
53
+ errorMessages={errorMessages}
54
+ onErrorClick={handleErrorClick}
55
55
  />
56
- </div>
56
+ </CapRow>
57
57
  );
58
58
  };
59
59
 
60
60
  ValidationErrorDisplay.propTypes = {
61
61
  validation: PropTypes.shape({
62
62
  isValidating: PropTypes.bool,
63
- getAllIssues: PropTypes.func,
63
+ getAllIssues: PropTypes.func
64
64
  }),
65
+ variant: PropTypes.oneOf(Object.values(HTML_EDITOR_VARIANTS)),
65
66
  onErrorClick: PropTypes.func,
66
- className: PropTypes.string,
67
- };
68
-
69
- ValidationErrorDisplay.defaultProps = {
70
- validation: null,
71
- onErrorClick: null,
72
- className: '',
67
+ className: PropTypes.string
73
68
  };
74
69
 
75
70
  export default ValidationErrorDisplay;
@@ -5,17 +5,17 @@
5
5
  @import '~@capillarytech/cap-ui-library/styles/_variables.scss';
6
6
 
7
7
  .validation-panel {
8
- border: 1px solid $CAP_COLOR_16;
9
- border-radius: $CAP_SPACE_06;
10
- background: $CAP_WHITE;
8
+ border: 1px solid #d9d9d9;
9
+ border-radius: 6px;
10
+ background: #fff;
11
11
 
12
12
  &--loading {
13
- padding: $CAP_SPACE_16;
13
+ padding: 16px;
14
14
  text-align: center;
15
15
  }
16
16
 
17
17
  &--clean {
18
- padding: $CAP_SPACE_16;
18
+ padding: 16px;
19
19
  text-align: center;
20
20
  background: #f6ffed;
21
21
  border-color: #b7eb8f;
@@ -25,7 +25,7 @@
25
25
  display: flex;
26
26
  align-items: center;
27
27
  justify-content: center;
28
- gap: $CAP_SPACE_08;
28
+ gap: 8px;
29
29
  color: #666;
30
30
  font-size: 14px;
31
31
  }
@@ -34,36 +34,36 @@
34
34
  display: flex;
35
35
  align-items: center;
36
36
  justify-content: center;
37
- gap: $CAP_SPACE_08;
37
+ gap: 8px;
38
38
  color: #52c41a;
39
39
  font-size: 14px;
40
- font-weight: $FONT_WEIGHT_MEDIUM;
40
+ font-weight: 500;
41
41
  }
42
42
 
43
43
  &__summary {
44
44
  display: flex;
45
- gap: $CAP_SPACE_16;
46
- padding: $CAP_SPACE_12 $CAP_SPACE_16;
47
- background: $CAP_G21;
48
- border-bottom: 1px solid $CAP_COLOR_16;
49
- border-radius: $CAP_SPACE_06 $CAP_SPACE_06 0 0;
45
+ gap: 16px;
46
+ padding: 12px 16px;
47
+ background: #fafafa;
48
+ border-bottom: 1px solid #d9d9d9;
49
+ border-radius: 6px 6px 0 0;
50
50
  }
51
51
 
52
52
  &__summary-item {
53
53
  display: flex;
54
54
  align-items: center;
55
- gap: $CAP_SPACE_04;
56
- font-size: $CAP_SPACE_12;
55
+ gap: 4px;
56
+ font-size: 12px;
57
57
  color: #666;
58
58
 
59
59
  &--security {
60
60
  color: #ff4d4f;
61
- font-weight: $FONT_WEIGHT_MEDIUM;
61
+ font-weight: 500;
62
62
  }
63
63
 
64
64
  span:first-of-type {
65
65
  font-weight: 600;
66
- margin-left: $CAP_SPACE_02;
66
+ margin-left: 2px;
67
67
  }
68
68
  }
69
69
 
@@ -72,7 +72,7 @@
72
72
  border: none;
73
73
 
74
74
  &:last-child {
75
- border-radius: 0 0 $CAP_SPACE_06 $CAP_SPACE_06;
75
+ border-radius: 0 0 6px 6px;
76
76
  }
77
77
  }
78
78
 
@@ -123,8 +123,8 @@
123
123
  &__title {
124
124
  display: flex;
125
125
  align-items: center;
126
- gap: $CAP_SPACE_08;
127
- font-weight: $FONT_WEIGHT_MEDIUM;
126
+ gap: 8px;
127
+ font-weight: 500;
128
128
  }
129
129
 
130
130
  &__issues {
@@ -133,41 +133,41 @@
133
133
  }
134
134
 
135
135
  &__sanitization {
136
- border-top: 1px solid $CAP_COLOR_16;
136
+ border-top: 1px solid #d9d9d9;
137
137
  background: #f9f9f9;
138
138
  }
139
139
 
140
140
  &__sanitization-header {
141
141
  display: flex;
142
142
  align-items: center;
143
- gap: $CAP_SPACE_08;
144
- padding: $CAP_SPACE_12 $CAP_SPACE_16;
145
- font-weight: $FONT_WEIGHT_MEDIUM;
143
+ gap: 8px;
144
+ padding: 12px 16px;
145
+ font-weight: 500;
146
146
  color: #666;
147
147
  font-size: 13px;
148
148
  }
149
149
 
150
150
  &__sanitization-list {
151
- padding: 0 $CAP_SPACE_16 $CAP_SPACE_12;
151
+ padding: 0 16px 12px;
152
152
  }
153
153
 
154
154
  &__sanitization-item {
155
- padding: $CAP_SPACE_04 0;
156
- font-size: $CAP_SPACE_12;
155
+ padding: 4px 0;
156
+ font-size: 12px;
157
157
  color: #8c8c8c;
158
158
  }
159
159
  }
160
160
 
161
161
  .validation-issue {
162
162
  display: flex;
163
- gap: $CAP_SPACE_12;
164
- padding: $CAP_SPACE_12 $CAP_SPACE_16;
163
+ gap: 12px;
164
+ padding: 12px 16px;
165
165
  border-bottom: 1px solid #f0f0f0;
166
166
  cursor: pointer;
167
167
  transition: background-color 0.2s;
168
168
 
169
169
  &:hover {
170
- background: $CAP_G21;
170
+ background: #fafafa;
171
171
  }
172
172
 
173
173
  &:last-child {
@@ -189,18 +189,6 @@
189
189
  &__icon {
190
190
  flex-shrink: 0;
191
191
  margin-top: 2px;
192
-
193
- &--error {
194
- color: #ff4d4f;
195
- }
196
-
197
- &--info {
198
- color: #1890ff;
199
- }
200
-
201
- &--security {
202
- color: #ff4d4f;
203
- }
204
192
  }
205
193
 
206
194
  &__content {
@@ -212,14 +200,14 @@
212
200
  font-size: 13px;
213
201
  line-height: 1.4;
214
202
  color: #262626;
215
- margin-bottom: $CAP_SPACE_04;
203
+ margin-bottom: 4px;
216
204
  word-break: break-word;
217
205
  }
218
206
 
219
207
  &__meta {
220
208
  display: flex;
221
209
  flex-wrap: wrap;
222
- gap: $CAP_SPACE_08;
210
+ gap: 8px;
223
211
  font-size: 11px;
224
212
  color: #8c8c8c;
225
213
  }
@@ -242,9 +230,9 @@
242
230
  &__source {
243
231
  display: flex;
244
232
  align-items: center;
245
- gap: $CAP_SPACE_04;
233
+ gap: 4px;
246
234
  background: #f0f0f0;
247
- padding: $CAP_SPACE_02 $CAP_SPACE_06;
235
+ padding: 2px 6px;
248
236
  border-radius: 3px;
249
237
  }
250
238
  }