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

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 +2 -2
  4. package/initialReducer.js +0 -2
  5. package/package.json +1 -1
  6. package/services/api.js +5 -10
  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 +6 -5
  12. package/utils/commonUtils.js +5 -28
  13. package/utils/imageUrlUpload.js +141 -0
  14. package/utils/tests/commonUtil.test.js +0 -224
  15. package/utils/tests/transformerUtils.test.js +297 -0
  16. package/utils/transformTemplateConfig.js +10 -0
  17. package/utils/transformerUtils.js +40 -0
  18. package/v2Components/CapDeviceContent/index.js +56 -61
  19. package/v2Components/CapImageUpload/constants.js +2 -0
  20. package/v2Components/CapImageUpload/index.js +65 -16
  21. package/v2Components/CapImageUpload/index.scss +4 -1
  22. package/v2Components/CapImageUpload/messages.js +5 -1
  23. package/v2Components/CapImageUrlUpload/constants.js +26 -0
  24. package/v2Components/CapImageUrlUpload/index.js +365 -0
  25. package/v2Components/CapImageUrlUpload/index.scss +35 -0
  26. package/v2Components/CapImageUrlUpload/messages.js +47 -0
  27. package/v2Components/CapTagList/index.js +1 -6
  28. package/v2Components/CapTagListWithInput/index.js +1 -5
  29. package/v2Components/CapTagListWithInput/messages.js +1 -1
  30. package/v2Components/CapWhatsappCTA/tests/index.test.js +0 -5
  31. package/v2Components/ErrorInfoNote/index.js +72 -402
  32. package/v2Components/ErrorInfoNote/messages.js +6 -32
  33. package/v2Components/ErrorInfoNote/style.scss +6 -278
  34. package/v2Components/FormBuilder/tests/index.test.js +4 -13
  35. package/v2Components/HtmlEditor/HTMLEditor.js +99 -418
  36. package/v2Components/HtmlEditor/__tests__/HTMLEditor.test.js +133 -1882
  37. package/v2Components/HtmlEditor/__tests__/index.lazy.test.js +16 -27
  38. package/v2Components/HtmlEditor/_htmlEditor.scss +45 -108
  39. package/v2Components/HtmlEditor/_index.lazy.scss +1 -0
  40. package/v2Components/HtmlEditor/components/CodeEditorPane/_codeEditorPane.scss +102 -23
  41. package/v2Components/HtmlEditor/components/CodeEditorPane/index.js +140 -148
  42. package/v2Components/HtmlEditor/components/DeviceToggle/_deviceToggle.scss +1 -2
  43. package/v2Components/HtmlEditor/components/DeviceToggle/index.js +3 -3
  44. package/v2Components/HtmlEditor/components/EditorToolbar/_editorToolbar.scss +1 -9
  45. package/v2Components/HtmlEditor/components/EditorToolbar/index.js +6 -31
  46. package/v2Components/HtmlEditor/components/FullscreenModal/_fullscreenModal.scss +0 -22
  47. package/v2Components/HtmlEditor/components/InAppPreviewPane/DeviceFrame.js +7 -4
  48. package/v2Components/HtmlEditor/components/InAppPreviewPane/__tests__/DeviceFrame.test.js +45 -35
  49. package/v2Components/HtmlEditor/components/InAppPreviewPane/_inAppPreviewPane.scss +3 -1
  50. package/v2Components/HtmlEditor/components/InAppPreviewPane/constants.js +33 -33
  51. package/v2Components/HtmlEditor/components/InAppPreviewPane/index.js +6 -7
  52. package/v2Components/HtmlEditor/components/PreviewPane/_previewPane.scss +10 -7
  53. package/v2Components/HtmlEditor/components/PreviewPane/index.js +43 -22
  54. package/v2Components/HtmlEditor/components/SplitContainer/_splitContainer.scss +1 -1
  55. package/v2Components/HtmlEditor/components/ValidationErrorDisplay/__tests__/index.test.js +152 -0
  56. package/v2Components/HtmlEditor/components/ValidationErrorDisplay/_validationErrorDisplay.scss +0 -18
  57. package/v2Components/HtmlEditor/components/ValidationErrorDisplay/index.js +31 -36
  58. package/v2Components/HtmlEditor/components/ValidationPanel/_validationPanel.scss +34 -46
  59. package/v2Components/HtmlEditor/components/ValidationPanel/index.js +46 -52
  60. package/v2Components/HtmlEditor/constants.js +20 -45
  61. package/v2Components/HtmlEditor/hooks/__tests__/useInAppContent.test.js +16 -373
  62. package/v2Components/HtmlEditor/hooks/__tests__/useValidation.test.js +16 -351
  63. package/v2Components/HtmlEditor/hooks/useEditorContent.js +2 -5
  64. package/v2Components/HtmlEditor/hooks/useInAppContent.js +146 -88
  65. package/v2Components/HtmlEditor/hooks/useValidation.js +56 -213
  66. package/v2Components/HtmlEditor/index.js +1 -1
  67. package/v2Components/HtmlEditor/messages.js +94 -102
  68. package/v2Components/HtmlEditor/utils/__tests__/htmlValidator.enhanced.test.js +45 -214
  69. package/v2Components/HtmlEditor/utils/__tests__/validationAdapter.test.js +0 -134
  70. package/v2Components/HtmlEditor/utils/contentSanitizer.js +41 -40
  71. package/v2Components/HtmlEditor/utils/htmlValidator.js +72 -71
  72. package/v2Components/HtmlEditor/utils/liquidTemplateSupport.js +124 -158
  73. package/v2Components/HtmlEditor/utils/properSyntaxHighlighting.js +25 -23
  74. package/v2Components/HtmlEditor/utils/validationAdapter.js +41 -66
  75. package/v2Components/MobilePushPreviewV2/index.js +7 -33
  76. package/v2Components/TemplatePreview/_templatePreview.scss +24 -55
  77. package/v2Components/TemplatePreview/index.js +32 -47
  78. package/v2Components/TemplatePreview/messages.js +0 -4
  79. package/v2Components/TestAndPreviewSlidebox/_testAndPreviewSlidebox.scss +0 -1
  80. package/v2Containers/App/constants.js +5 -0
  81. package/v2Containers/BeeEditor/index.js +90 -172
  82. package/v2Containers/CreativesContainer/SlideBoxContent.js +108 -129
  83. package/v2Containers/CreativesContainer/SlideBoxFooter.js +13 -163
  84. package/v2Containers/CreativesContainer/SlideBoxHeader.js +2 -2
  85. package/v2Containers/CreativesContainer/constants.js +3 -1
  86. package/v2Containers/CreativesContainer/index.js +214 -240
  87. package/v2Containers/CreativesContainer/messages.js +4 -8
  88. package/v2Containers/CreativesContainer/tests/SlideBoxContent.test.js +210 -0
  89. package/v2Containers/CreativesContainer/tests/SlideBoxFooter.test.js +2 -11
  90. package/v2Containers/CreativesContainer/tests/__snapshots__/SlideBoxContent.test.js.snap +354 -38
  91. package/v2Containers/CreativesContainer/tests/__snapshots__/index.test.js.snap +0 -103
  92. package/v2Containers/Email/actions.js +0 -7
  93. package/v2Containers/Email/constants.js +1 -5
  94. package/v2Containers/Email/index.js +29 -234
  95. package/v2Containers/Email/messages.js +0 -32
  96. package/v2Containers/Email/reducer.js +1 -12
  97. package/v2Containers/Email/sagas.js +7 -61
  98. package/v2Containers/Email/tests/__snapshots__/reducer.test.js.snap +0 -2
  99. package/v2Containers/Email/tests/reducer.test.js +0 -46
  100. package/v2Containers/Email/tests/sagas.test.js +29 -320
  101. package/v2Containers/EmailWrapper/components/EmailWrapperView.js +21 -211
  102. package/v2Containers/EmailWrapper/components/HTMLEditorTesting.js +74 -40
  103. package/v2Containers/EmailWrapper/components/__tests__/HTMLEditorTesting.test.js +67 -2
  104. package/v2Containers/EmailWrapper/constants.js +0 -2
  105. package/v2Containers/EmailWrapper/hooks/useEmailWrapper.js +77 -629
  106. package/v2Containers/EmailWrapper/index.js +23 -103
  107. package/v2Containers/EmailWrapper/messages.js +1 -65
  108. package/v2Containers/EmailWrapper/tests/EmailWrapperView.test.js +214 -0
  109. package/v2Containers/EmailWrapper/tests/useEmailWrapper.test.js +77 -594
  110. package/v2Containers/InApp/actions.js +0 -7
  111. package/v2Containers/InApp/constants.js +4 -20
  112. package/v2Containers/InApp/index.js +359 -802
  113. package/v2Containers/InApp/index.scss +3 -4
  114. package/v2Containers/InApp/messages.js +3 -7
  115. package/v2Containers/InApp/reducer.js +3 -21
  116. package/v2Containers/InApp/sagas.js +9 -29
  117. package/v2Containers/InApp/selectors.js +5 -25
  118. package/v2Containers/InApp/tests/index.test.js +50 -154
  119. package/v2Containers/InApp/tests/reducer.test.js +0 -34
  120. package/v2Containers/InApp/tests/sagas.test.js +9 -61
  121. package/v2Containers/Line/Container/ImageCarousel/tests/__snapshots__/content.test.js.snap +0 -3
  122. package/v2Containers/Line/Container/ImageCarousel/tests/__snapshots__/index.test.js.snap +0 -2
  123. package/v2Containers/Line/Container/Wrapper/tests/__snapshots__/index.test.js.snap +0 -2
  124. package/v2Containers/Line/Container/tests/__snapshots__/index.test.js.snap +0 -9
  125. package/v2Containers/Rcs/tests/__snapshots__/index.test.js.snap +0 -12
  126. package/v2Containers/SmsTrai/Edit/tests/__snapshots__/index.test.js.snap +0 -4
  127. package/v2Containers/TagList/index.js +19 -62
  128. package/v2Containers/Templates/ChannelTypeIllustration.js +13 -1
  129. package/v2Containers/Templates/_templates.scss +202 -56
  130. package/v2Containers/Templates/actions.js +2 -1
  131. package/v2Containers/Templates/constants.js +1 -0
  132. package/v2Containers/Templates/index.js +278 -123
  133. package/v2Containers/Templates/messages.js +24 -4
  134. package/v2Containers/Templates/reducer.js +2 -0
  135. package/v2Containers/Templates/tests/index.test.js +10 -0
  136. package/v2Containers/TemplatesV2/TemplatesV2.style.js +2 -4
  137. package/v2Containers/TemplatesV2/index.js +15 -7
  138. package/v2Containers/TemplatesV2/messages.js +4 -0
  139. package/v2Containers/WebPush/Create/components/BrandIconSection.js +108 -0
  140. package/v2Containers/WebPush/Create/components/ButtonForm.js +172 -0
  141. package/v2Containers/WebPush/Create/components/ButtonItem.js +101 -0
  142. package/v2Containers/WebPush/Create/components/ButtonList.js +145 -0
  143. package/v2Containers/WebPush/Create/components/ButtonsLinksSection.js +164 -0
  144. package/v2Containers/WebPush/Create/components/ButtonsLinksSection.test.js +463 -0
  145. package/v2Containers/WebPush/Create/components/FormActions.js +54 -0
  146. package/v2Containers/WebPush/Create/components/FormActions.test.js +163 -0
  147. package/v2Containers/WebPush/Create/components/MediaSection.js +142 -0
  148. package/v2Containers/WebPush/Create/components/MediaSection.test.js +341 -0
  149. package/v2Containers/WebPush/Create/components/MessageSection.js +103 -0
  150. package/v2Containers/WebPush/Create/components/MessageSection.test.js +268 -0
  151. package/v2Containers/WebPush/Create/components/NotificationTitleSection.js +87 -0
  152. package/v2Containers/WebPush/Create/components/NotificationTitleSection.test.js +210 -0
  153. package/v2Containers/WebPush/Create/components/TemplateNameSection.js +54 -0
  154. package/v2Containers/WebPush/Create/components/TemplateNameSection.test.js +143 -0
  155. package/v2Containers/WebPush/Create/components/__snapshots__/ButtonsLinksSection.test.js.snap +86 -0
  156. package/v2Containers/WebPush/Create/components/__snapshots__/FormActions.test.js.snap +16 -0
  157. package/v2Containers/WebPush/Create/components/__snapshots__/MediaSection.test.js.snap +41 -0
  158. package/v2Containers/WebPush/Create/components/__snapshots__/MessageSection.test.js.snap +54 -0
  159. package/v2Containers/WebPush/Create/components/__snapshots__/NotificationTitleSection.test.js.snap +37 -0
  160. package/v2Containers/WebPush/Create/components/__snapshots__/TemplateNameSection.test.js.snap +21 -0
  161. package/v2Containers/WebPush/Create/components/_buttons.scss +246 -0
  162. package/v2Containers/WebPush/Create/components/tests/ButtonForm.test.js +554 -0
  163. package/v2Containers/WebPush/Create/components/tests/ButtonItem.test.js +607 -0
  164. package/v2Containers/WebPush/Create/components/tests/ButtonList.test.js +633 -0
  165. package/v2Containers/WebPush/Create/components/tests/__snapshots__/ButtonForm.test.js.snap +666 -0
  166. package/v2Containers/WebPush/Create/components/tests/__snapshots__/ButtonItem.test.js.snap +74 -0
  167. package/v2Containers/WebPush/Create/components/tests/__snapshots__/ButtonList.test.js.snap +78 -0
  168. package/v2Containers/WebPush/Create/hooks/useButtonManagement.js +138 -0
  169. package/v2Containers/WebPush/Create/hooks/useButtonManagement.test.js +406 -0
  170. package/v2Containers/WebPush/Create/hooks/useCharacterCount.js +30 -0
  171. package/v2Containers/WebPush/Create/hooks/useCharacterCount.test.js +151 -0
  172. package/v2Containers/WebPush/Create/hooks/useImageUpload.js +104 -0
  173. package/v2Containers/WebPush/Create/hooks/useImageUpload.test.js +538 -0
  174. package/v2Containers/WebPush/Create/hooks/useTagManagement.js +122 -0
  175. package/v2Containers/WebPush/Create/hooks/useTagManagement.test.js +633 -0
  176. package/v2Containers/WebPush/Create/index.js +1148 -0
  177. package/v2Containers/WebPush/Create/index.scss +134 -0
  178. package/v2Containers/WebPush/Create/messages.js +211 -0
  179. package/v2Containers/WebPush/Create/preview/DevicePreviewContent.js +228 -0
  180. package/v2Containers/WebPush/Create/preview/NotificationContainer.js +294 -0
  181. package/v2Containers/WebPush/Create/preview/PreviewContent.js +90 -0
  182. package/v2Containers/WebPush/Create/preview/PreviewControls.js +305 -0
  183. package/v2Containers/WebPush/Create/preview/PreviewDisclaimer.js +25 -0
  184. package/v2Containers/WebPush/Create/preview/WebPushPreview.js +156 -0
  185. package/v2Containers/WebPush/Create/preview/assets/Light.svg +53 -0
  186. package/v2Containers/WebPush/Create/preview/assets/Top.svg +5 -0
  187. package/v2Containers/WebPush/Create/preview/assets/android-arrow-down.svg +9 -0
  188. package/v2Containers/WebPush/Create/preview/assets/android-arrow-up.svg +9 -0
  189. package/v2Containers/WebPush/Create/preview/assets/chrome-icon.png +0 -0
  190. package/v2Containers/WebPush/Create/preview/assets/edge-icon.png +0 -0
  191. package/v2Containers/WebPush/Create/preview/assets/firefox-icon.svg +106 -0
  192. package/v2Containers/WebPush/Create/preview/assets/iOS.svg +26 -0
  193. package/v2Containers/WebPush/Create/preview/assets/macos-arrow-down-icon.svg +9 -0
  194. package/v2Containers/WebPush/Create/preview/assets/macos-triple-dot-icon.svg +9 -0
  195. package/v2Containers/WebPush/Create/preview/assets/opera-icon.svg +18 -0
  196. package/v2Containers/WebPush/Create/preview/assets/safari-icon.svg +29 -0
  197. package/v2Containers/WebPush/Create/preview/assets/windows-close-icon.svg +9 -0
  198. package/v2Containers/WebPush/Create/preview/assets/windows-triple-dot-icon.svg +9 -0
  199. package/v2Containers/WebPush/Create/preview/components/AndroidMobileChromeHeader.js +51 -0
  200. package/v2Containers/WebPush/Create/preview/components/AndroidMobileExpanded.js +145 -0
  201. package/v2Containers/WebPush/Create/preview/components/IOSHeader.js +45 -0
  202. package/v2Containers/WebPush/Create/preview/components/NotificationExpandedContent.js +68 -0
  203. package/v2Containers/WebPush/Create/preview/components/NotificationHeader.js +61 -0
  204. package/v2Containers/WebPush/Create/preview/components/WindowsChromeExpanded.js +99 -0
  205. package/v2Containers/WebPush/Create/preview/components/tests/AndroidMobileExpanded.test.js +733 -0
  206. package/v2Containers/WebPush/Create/preview/components/tests/WindowsChromeExpanded.test.js +571 -0
  207. package/v2Containers/WebPush/Create/preview/components/tests/__snapshots__/AndroidMobileExpanded.test.js.snap +85 -0
  208. package/v2Containers/WebPush/Create/preview/components/tests/__snapshots__/WindowsChromeExpanded.test.js.snap +81 -0
  209. package/v2Containers/WebPush/Create/preview/config/notificationMappings.js +50 -0
  210. package/v2Containers/WebPush/Create/preview/constants.js +637 -0
  211. package/v2Containers/WebPush/Create/preview/notification-container.scss +79 -0
  212. package/v2Containers/WebPush/Create/preview/preview.scss +358 -0
  213. package/v2Containers/WebPush/Create/preview/styles/_android-mobile-chrome.scss +370 -0
  214. package/v2Containers/WebPush/Create/preview/styles/_android-mobile-edge.scss +12 -0
  215. package/v2Containers/WebPush/Create/preview/styles/_android-mobile-firefox.scss +12 -0
  216. package/v2Containers/WebPush/Create/preview/styles/_android-mobile-opera.scss +12 -0
  217. package/v2Containers/WebPush/Create/preview/styles/_android-tablet-chrome.scss +47 -0
  218. package/v2Containers/WebPush/Create/preview/styles/_android-tablet-edge.scss +11 -0
  219. package/v2Containers/WebPush/Create/preview/styles/_android-tablet-firefox.scss +11 -0
  220. package/v2Containers/WebPush/Create/preview/styles/_android-tablet-opera.scss +11 -0
  221. package/v2Containers/WebPush/Create/preview/styles/_base.scss +207 -0
  222. package/v2Containers/WebPush/Create/preview/styles/_ios.scss +153 -0
  223. package/v2Containers/WebPush/Create/preview/styles/_ipados.scss +107 -0
  224. package/v2Containers/WebPush/Create/preview/styles/_macos-chrome.scss +101 -0
  225. package/v2Containers/WebPush/Create/preview/styles/_windows-chrome.scss +229 -0
  226. package/v2Containers/WebPush/Create/preview/tests/DevicePreviewContent.test.js +906 -0
  227. package/v2Containers/WebPush/Create/preview/tests/NotificationContainer.test.js +1081 -0
  228. package/v2Containers/WebPush/Create/preview/tests/PreviewControls.test.js +723 -0
  229. package/v2Containers/WebPush/Create/preview/tests/WebPushPreview.test.js +1327 -0
  230. package/v2Containers/WebPush/Create/preview/tests/__snapshots__/DevicePreviewContent.test.js.snap +131 -0
  231. package/v2Containers/WebPush/Create/preview/tests/__snapshots__/NotificationContainer.test.js.snap +112 -0
  232. package/v2Containers/WebPush/Create/preview/tests/__snapshots__/PreviewControls.test.js.snap +144 -0
  233. package/v2Containers/WebPush/Create/preview/tests/__snapshots__/WebPushPreview.test.js.snap +129 -0
  234. package/v2Containers/WebPush/Create/utils/payloadBuilder.js +96 -0
  235. package/v2Containers/WebPush/Create/utils/payloadBuilder.test.js +396 -0
  236. package/v2Containers/WebPush/Create/utils/previewUtils.js +89 -0
  237. package/v2Containers/WebPush/Create/utils/urlValidation.js +115 -0
  238. package/v2Containers/WebPush/Create/utils/urlValidation.test.js +449 -0
  239. package/v2Containers/WebPush/Create/utils/validation.js +75 -0
  240. package/v2Containers/WebPush/Create/utils/validation.test.js +283 -0
  241. package/v2Containers/WebPush/actions.js +60 -0
  242. package/v2Containers/WebPush/constants.js +132 -0
  243. package/v2Containers/WebPush/index.js +2 -0
  244. package/v2Containers/WebPush/reducer.js +104 -0
  245. package/v2Containers/WebPush/sagas.js +119 -0
  246. package/v2Containers/WebPush/selectors.js +65 -0
  247. package/v2Containers/WebPush/tests/reducer.test.js +863 -0
  248. package/v2Containers/WebPush/tests/sagas.test.js +566 -0
  249. package/v2Containers/WebPush/tests/selectors.test.js +960 -0
  250. package/v2Containers/Whatsapp/tests/__snapshots__/index.test.js.snap +0 -34
  251. package/v2Components/ErrorInfoNote/constants.js +0 -1
  252. package/v2Components/HtmlEditor/__tests__/HTMLEditor.apiErrors.test.js +0 -870
  253. package/v2Components/HtmlEditor/components/ValidationPanel/constants.js +0 -6
  254. package/v2Components/HtmlEditor/components/ValidationTabs/_validationTabs.scss +0 -277
  255. package/v2Components/HtmlEditor/components/ValidationTabs/index.js +0 -295
  256. package/v2Components/HtmlEditor/components/ValidationTabs/messages.js +0 -51
  257. package/v2Components/HtmlEditor/utils/validationConstants.js +0 -38
  258. package/v2Components/MobilePushPreviewV2/constants.js +0 -6
  259. package/v2Containers/BeePopupEditor/_beePopupEditor.scss +0 -14
  260. package/v2Containers/BeePopupEditor/constants.js +0 -10
  261. package/v2Containers/BeePopupEditor/index.js +0 -194
  262. package/v2Containers/BeePopupEditor/tests/index.test.js +0 -627
  263. package/v2Containers/EmailWrapper/components/EmailHTMLEditor.js +0 -1246
  264. package/v2Containers/EmailWrapper/components/__tests__/EmailHTMLEditor.test.js +0 -2472
  265. package/v2Containers/EmailWrapper/components/__tests__/EmailWrapperView.test.js +0 -520
  266. package/v2Containers/EmailWrapper/tests/useEmailWrapper.edgeCases.test.js +0 -956
  267. package/v2Containers/InApp/__tests__/InAppHTMLEditor.test.js +0 -376
  268. package/v2Containers/InApp/__tests__/sagas.test.js +0 -363
  269. package/v2Containers/InApp/tests/selectors.test.js +0 -612
  270. package/v2Containers/InAppWrapper/components/InAppWrapperView.js +0 -151
  271. package/v2Containers/InAppWrapper/components/__tests__/InAppWrapperView.test.js +0 -267
  272. package/v2Containers/InAppWrapper/components/inAppWrapperView.scss +0 -23
  273. package/v2Containers/InAppWrapper/constants.js +0 -16
  274. package/v2Containers/InAppWrapper/hooks/__tests__/useInAppWrapper.test.js +0 -473
  275. package/v2Containers/InAppWrapper/hooks/useInAppWrapper.js +0 -198
  276. package/v2Containers/InAppWrapper/index.js +0 -148
  277. package/v2Containers/InAppWrapper/messages.js +0 -49
  278. package/v2Containers/InappAdvance/index.js +0 -1099
  279. package/v2Containers/InappAdvance/index.scss +0 -10
  280. package/v2Containers/InappAdvance/tests/index.test.js +0 -448
@@ -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
  }