@capillarytech/creatives-library 8.0.208 → 8.0.210

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 (76) hide show
  1. package/assets/Android.png +0 -0
  2. package/assets/iOS.png +0 -0
  3. package/package.json +16 -2
  4. package/v2Components/HtmlEditor/HTMLEditor.js +508 -0
  5. package/v2Components/HtmlEditor/__tests__/HTMLEditor.test.js +1809 -0
  6. package/v2Components/HtmlEditor/__tests__/index.lazy.test.js +532 -0
  7. package/v2Components/HtmlEditor/_htmlEditor.scss +304 -0
  8. package/v2Components/HtmlEditor/_index.lazy.scss +26 -0
  9. package/v2Components/HtmlEditor/components/CodeEditorPane/_codeEditorPane.scss +376 -0
  10. package/v2Components/HtmlEditor/components/CodeEditorPane/index.js +331 -0
  11. package/v2Components/HtmlEditor/components/DeviceToggle/__tests__/index.test.js +314 -0
  12. package/v2Components/HtmlEditor/components/DeviceToggle/_deviceToggle.scss +244 -0
  13. package/v2Components/HtmlEditor/components/DeviceToggle/index.js +111 -0
  14. package/v2Components/HtmlEditor/components/EditorToolbar/PreviewModeGroup.js +72 -0
  15. package/v2Components/HtmlEditor/components/EditorToolbar/__tests__/PreviewModeGroup.test.js +1594 -0
  16. package/v2Components/HtmlEditor/components/EditorToolbar/_editorToolbar.scss +113 -0
  17. package/v2Components/HtmlEditor/components/EditorToolbar/_previewModeGroup.scss +82 -0
  18. package/v2Components/HtmlEditor/components/EditorToolbar/index.js +115 -0
  19. package/v2Components/HtmlEditor/components/FullscreenModal/_fullscreenModal.scss +57 -0
  20. package/v2Components/HtmlEditor/components/InAppPreviewPane/ContentOverlay.js +90 -0
  21. package/v2Components/HtmlEditor/components/InAppPreviewPane/DeviceFrame.js +60 -0
  22. package/v2Components/HtmlEditor/components/InAppPreviewPane/LayoutSelector.js +58 -0
  23. package/v2Components/HtmlEditor/components/InAppPreviewPane/__tests__/ContentOverlay.test.js +403 -0
  24. package/v2Components/HtmlEditor/components/InAppPreviewPane/__tests__/DeviceFrame.test.js +424 -0
  25. package/v2Components/HtmlEditor/components/InAppPreviewPane/__tests__/LayoutSelector.test.js +248 -0
  26. package/v2Components/HtmlEditor/components/InAppPreviewPane/_inAppPreviewPane.scss +253 -0
  27. package/v2Components/HtmlEditor/components/InAppPreviewPane/constants.js +104 -0
  28. package/v2Components/HtmlEditor/components/InAppPreviewPane/index.js +179 -0
  29. package/v2Components/HtmlEditor/components/PreviewPane/_previewPane.scss +220 -0
  30. package/v2Components/HtmlEditor/components/PreviewPane/index.js +229 -0
  31. package/v2Components/HtmlEditor/components/SplitContainer/SplitContainer.js +276 -0
  32. package/v2Components/HtmlEditor/components/SplitContainer/__tests__/SplitContainer.test.js +295 -0
  33. package/v2Components/HtmlEditor/components/SplitContainer/_splitContainer.scss +257 -0
  34. package/v2Components/HtmlEditor/components/SplitContainer/index.js +7 -0
  35. package/v2Components/HtmlEditor/components/ValidationErrorDisplay/__tests__/index.test.js +152 -0
  36. package/v2Components/HtmlEditor/components/ValidationErrorDisplay/_validationErrorDisplay.scss +31 -0
  37. package/v2Components/HtmlEditor/components/ValidationErrorDisplay/index.js +70 -0
  38. package/v2Components/HtmlEditor/components/ValidationPanel/__tests__/index.test.js +98 -0
  39. package/v2Components/HtmlEditor/components/ValidationPanel/_validationPanel.scss +311 -0
  40. package/v2Components/HtmlEditor/components/ValidationPanel/index.js +297 -0
  41. package/v2Components/HtmlEditor/components/ValidationPanel/messages.js +57 -0
  42. package/v2Components/HtmlEditor/components/common/EditorContext.js +84 -0
  43. package/v2Components/HtmlEditor/components/common/__tests__/EditorContext.test.js +660 -0
  44. package/v2Components/HtmlEditor/constants.js +241 -0
  45. package/v2Components/HtmlEditor/hooks/__tests__/useEditorContent.test.js +450 -0
  46. package/v2Components/HtmlEditor/hooks/__tests__/useInAppContent.test.js +785 -0
  47. package/v2Components/HtmlEditor/hooks/__tests__/useLayoutState.test.js +580 -0
  48. package/v2Components/HtmlEditor/hooks/__tests__/useValidation.enhanced.test.js +768 -0
  49. package/v2Components/HtmlEditor/hooks/__tests__/useValidation.test.js +590 -0
  50. package/v2Components/HtmlEditor/hooks/useEditorContent.js +274 -0
  51. package/v2Components/HtmlEditor/hooks/useInAppContent.js +407 -0
  52. package/v2Components/HtmlEditor/hooks/useLayoutState.js +247 -0
  53. package/v2Components/HtmlEditor/hooks/useValidation.js +325 -0
  54. package/v2Components/HtmlEditor/index.js +29 -0
  55. package/v2Components/HtmlEditor/index.lazy.js +114 -0
  56. package/v2Components/HtmlEditor/messages.js +389 -0
  57. package/v2Components/HtmlEditor/utils/__tests__/contentSanitizer.test.js +741 -0
  58. package/v2Components/HtmlEditor/utils/__tests__/htmlValidator.enhanced.test.js +1042 -0
  59. package/v2Components/HtmlEditor/utils/__tests__/liquidTemplateSupport.test.js +515 -0
  60. package/v2Components/HtmlEditor/utils/__tests__/properSyntaxHighlighting.test.js +473 -0
  61. package/v2Components/HtmlEditor/utils/__tests__/simplePerformance.test.js +1109 -0
  62. package/v2Components/HtmlEditor/utils/__tests__/validationAdapter.test.js +240 -0
  63. package/v2Components/HtmlEditor/utils/contentSanitizer.js +433 -0
  64. package/v2Components/HtmlEditor/utils/htmlValidator.js +508 -0
  65. package/v2Components/HtmlEditor/utils/liquidTemplateSupport.js +524 -0
  66. package/v2Components/HtmlEditor/utils/properSyntaxHighlighting.js +163 -0
  67. package/v2Components/HtmlEditor/utils/simplePerformance.js +145 -0
  68. package/v2Components/HtmlEditor/utils/validationAdapter.js +130 -0
  69. package/v2Containers/EmailWrapper/components/HTMLEditorTesting.js +200 -0
  70. package/v2Containers/EmailWrapper/components/__tests__/HTMLEditorTesting.test.js +545 -0
  71. package/v2Containers/EmailWrapper/index.js +8 -1
  72. package/v2Containers/Rcs/index.js +2 -0
  73. package/v2Containers/Templates/constants.js +8 -0
  74. package/v2Containers/Templates/index.js +56 -28
  75. package/v2Containers/Templates/tests/__snapshots__/index.test.js.snap +5 -14
  76. package/v2Containers/Whatsapp/index.js +1 -0
@@ -0,0 +1,145 @@
1
+ /**
2
+ * Simple Performance Optimizations for HTML Editor
3
+ *
4
+ * Practical optimizations that improve performance without complexity:
5
+ * - Memoization
6
+ * - Debouncing improvements
7
+ * - Memory cleanup
8
+ * - Bundle size optimizations
9
+ */
10
+
11
+ import React, { useCallback, useMemo, useRef, useEffect } from 'react';
12
+
13
+ /**
14
+ * Enhanced debounce with content-size awareness
15
+ * Automatically adjusts delays based on content size
16
+ */
17
+ export const useSmartDebounce = (callback, baseDelay = 300) => {
18
+ const timeoutRef = useRef(null);
19
+
20
+ // Cleanup timeout on unmount to prevent callbacks after component unmount
21
+ useEffect(() => {
22
+ return () => {
23
+ if (timeoutRef.current) {
24
+ clearTimeout(timeoutRef.current);
25
+ }
26
+ };
27
+ }, []);
28
+
29
+ return useCallback((value, contentSize = 0) => {
30
+ if (timeoutRef.current) {
31
+ clearTimeout(timeoutRef.current);
32
+ }
33
+
34
+ // Adjust delay based on content size, using baseDelay as starting point
35
+ let delay = baseDelay;
36
+ if (contentSize > PERFORMANCE_THRESHOLDS.LARGE_CONTENT_DEBOUNCE) {
37
+ delay = baseDelay * 2; // Large content: double the base delay
38
+ } else if (contentSize > PERFORMANCE_THRESHOLDS.MEDIUM_CONTENT_DEBOUNCE) {
39
+ delay = Math.round(baseDelay * 1.33); // Medium content: increase base delay by 33%
40
+ } else if (contentSize < PERFORMANCE_THRESHOLDS.SMALL_CONTENT_DEBOUNCE) {
41
+ delay = Math.max(Math.round(baseDelay * (2/3)), 100); // Small content: reduce to 2/3 of base delay, min 100ms
42
+ }
43
+ // For content between SMALL_CONTENT_DEBOUNCE and MEDIUM_CONTENT_DEBOUNCE, use baseDelay as-is
44
+
45
+ timeoutRef.current = setTimeout(() => {
46
+ callback(value);
47
+ }, delay);
48
+ }, [callback, baseDelay]);
49
+ };
50
+
51
+ /**
52
+ * Memory-optimized component wrapper
53
+ * Prevents unnecessary re-renders
54
+ */
55
+ export const withPerformanceOptimization = (Component) => {
56
+ return React.memo(Component, (prevProps, nextProps) => {
57
+ // Skip re-render if content hasn't actually changed
58
+ if (prevProps.content === nextProps.content &&
59
+ prevProps.variant === nextProps.variant &&
60
+ prevProps.readOnly === nextProps.readOnly) {
61
+ return true;
62
+ }
63
+ return false;
64
+ });
65
+ };
66
+
67
+ /**
68
+ * Cleanup utility for preventing memory leaks
69
+ * Uses ref-based stabilization so callers don't need to memoize the cleanup function
70
+ */
71
+ export const useCleanup = (cleanupFn) => {
72
+ const cleanupRef = useRef(cleanupFn);
73
+
74
+ // Update ref on every render to capture latest cleanup function
75
+ cleanupRef.current = cleanupFn;
76
+
77
+ useEffect(() => {
78
+ // Return a stable cleanup wrapper that reads the latest ref value
79
+ return () => {
80
+ if (cleanupRef.current && typeof cleanupRef.current === 'function') {
81
+ cleanupRef.current();
82
+ }
83
+ };
84
+ }, []); // Empty dependency array - effect only runs once
85
+ };
86
+
87
+ /**
88
+ * Content size analyzer for performance decisions
89
+ */
90
+ export const analyzeContentSize = (content) => {
91
+ const size = typeof content === 'string' ? content.length : 0;
92
+
93
+ return {
94
+ size,
95
+ isSmall: size < PERFORMANCE_THRESHOLDS.SMALL_CONTENT_ANALYSIS, // < 10KB
96
+ isMedium: size < PERFORMANCE_THRESHOLDS.LARGE_CONTENT_ANALYSIS, // < 50KB
97
+ isLarge: size >= PERFORMANCE_THRESHOLDS.LARGE_CONTENT_ANALYSIS, // >= 50KB
98
+ shouldOptimize: size > PERFORMANCE_THRESHOLDS.SMALL_CONTENT_ANALYSIS,
99
+ recommendedDebounce: size > PERFORMANCE_THRESHOLDS.LARGE_CONTENT_ANALYSIS ?
100
+ PERFORMANCE_THRESHOLDS.DEBOUNCE_SLOW :
101
+ size > PERFORMANCE_THRESHOLDS.SMALL_CONTENT_ANALYSIS ?
102
+ 400 :
103
+ PERFORMANCE_THRESHOLDS.DEBOUNCE_FAST
104
+ };
105
+ };
106
+
107
+ /**
108
+ * Simple virtualization for very large content
109
+ * Only renders visible portions
110
+ */
111
+ export const useVirtualization = (content, threshold = 100000) => {
112
+ return useMemo(() => {
113
+ // Handle non-string content gracefully
114
+ if (!content || typeof content !== 'string' || content.length < threshold) {
115
+ return { content, isVirtualized: false };
116
+ }
117
+
118
+ // For very large content, show first 50KB with indicator
119
+ const truncated = content.substring(0, 50000);
120
+ return {
121
+ content: truncated + '\n\n<!-- Content truncated for performance -->',
122
+ isVirtualized: true,
123
+ originalSize: content.length
124
+ };
125
+ }, [content, threshold]);
126
+ };
127
+
128
+ /**
129
+ * Performance constants
130
+ */
131
+ export const PERFORMANCE_THRESHOLDS = {
132
+ // Content size thresholds for debouncing (useSmartDebounce)
133
+ SMALL_CONTENT_DEBOUNCE: 1000, // 1KB - threshold for fast debouncing
134
+ MEDIUM_CONTENT_DEBOUNCE: 10000, // 10KB - threshold for medium debouncing
135
+ LARGE_CONTENT_DEBOUNCE: 50000, // 50KB - threshold for slow debouncing
136
+
137
+ // Content size thresholds for analysis (analyzeContentSize)
138
+ SMALL_CONTENT_ANALYSIS: 10000, // 10KB - for general content analysis
139
+ LARGE_CONTENT_ANALYSIS: 50000, // 50KB - for general content analysis
140
+ HUGE_CONTENT: 100000, // 100KB - for virtualization
141
+
142
+ DEBOUNCE_FAST: 200,
143
+ DEBOUNCE_NORMAL: 300,
144
+ DEBOUNCE_SLOW: 600
145
+ };
@@ -0,0 +1,130 @@
1
+ /**
2
+ * ValidationAdapter - Transforms HTML Editor validation data to ErrorInfoNote format
3
+ *
4
+ * This adapter converts validation results from the HTML Editor's validation system
5
+ * into the format expected by the existing ErrorInfoNote component.
6
+ */
7
+
8
+ // Validation source constants
9
+ const VALIDATION_SOURCES = {
10
+ LIQUID: 'liquid-validator',
11
+ HTMLHINT: 'htmlhint',
12
+ CSS_VALIDATOR: 'css-validator',
13
+ CUSTOM: 'custom',
14
+ SECURITY: 'security',
15
+ SANITIZER: 'sanitizer',
16
+ EMAIL_SPECIFIC: 'email-specific',
17
+ INAPP_SPECIFIC: 'inapp-specific',
18
+ EMAIL_COMPATIBILITY: 'email-compatibility',
19
+ MOBILE_OPTIMIZATION: 'mobile-optimization'
20
+ };
21
+
22
+ /**
23
+ * Transform validation results to ErrorInfoNote format
24
+ * @param {Object} validation - Validation results from useValidation hook
25
+ * @param {string} variant - Editor variant ('email' or 'inapp')
26
+ * @returns {Object} ErrorInfoNote compatible format
27
+ */
28
+ export const transformValidationToErrorInfo = (validation, variant = 'email') => {
29
+ if (!validation || validation.isValidating) {
30
+ return { errorMessages: { LIQUID_ERROR_MSG: [], STANDARD_ERROR_MSG: [] } };
31
+ }
32
+
33
+ const allIssues = validation.getAllIssues();
34
+
35
+ // Separate liquid and standard errors
36
+ const liquidErrors = allIssues.filter(issue =>
37
+ issue.source === VALIDATION_SOURCES.LIQUID ||
38
+ issue.rule?.includes('liquid') ||
39
+ issue.message?.toLowerCase().includes('liquid')
40
+ );
41
+
42
+ const standardErrors = allIssues.filter(issue =>
43
+ issue.source !== VALIDATION_SOURCES.LIQUID &&
44
+ !issue.rule?.includes('liquid') &&
45
+ !issue.message?.toLowerCase().includes('liquid')
46
+ );
47
+
48
+ // Format errors for ErrorInfoNote
49
+ const formatErrors = (errors) =>
50
+ errors.map(error => {
51
+ let message = error.message;
52
+
53
+ // Add line/column info if available
54
+ if (error.line) {
55
+ message += ` Line ${error.line}`;
56
+ if (error.column) {
57
+ message += `, Char ${error.column}`;
58
+ }
59
+ message += '.';
60
+ }
61
+
62
+ // Add rule info if available
63
+ if (error.rule) {
64
+ message += ` • ${error.rule}`;
65
+ }
66
+
67
+ return message;
68
+ });
69
+
70
+ // Handle InApp variant with platform-specific errors (if needed in future)
71
+ if (variant === 'inapp') {
72
+ // For now, treat as generic errors
73
+ // Could be extended to support Android/iOS specific validation
74
+ return {
75
+ errorMessages: {
76
+ LIQUID_ERROR_MSG: formatErrors(liquidErrors),
77
+ STANDARD_ERROR_MSG: formatErrors(standardErrors)
78
+ }
79
+ };
80
+ }
81
+
82
+ // Email variant - generic errors
83
+ return {
84
+ errorMessages: {
85
+ LIQUID_ERROR_MSG: formatErrors(liquidErrors),
86
+ STANDARD_ERROR_MSG: formatErrors(standardErrors)
87
+ }
88
+ };
89
+ };
90
+
91
+ /**
92
+ * Check if there are any validation errors to display
93
+ * @param {Object} validation - Validation results
94
+ * @returns {boolean} True if there are errors to show
95
+ */
96
+ export const hasValidationErrors = (validation) => {
97
+ if (!validation || validation.isValidating) {
98
+ return false;
99
+ }
100
+
101
+ const allIssues = validation.getAllIssues();
102
+ return allIssues.length > 0;
103
+ };
104
+
105
+ /**
106
+ * Get validation summary for display
107
+ * @param {Object} validation - Validation results
108
+ * @returns {Object} Summary with counts
109
+ */
110
+ export const getValidationSummary = (validation) => {
111
+ if (!validation) {
112
+ return { totalErrors: 0, totalWarnings: 0, hasLiquidErrors: false };
113
+ }
114
+
115
+ const allIssues = validation.getAllIssues();
116
+ const errors = allIssues.filter(issue => issue.severity === 'error');
117
+ const warnings = allIssues.filter(issue => issue.severity === 'warning');
118
+ const liquidErrors = allIssues.filter(issue =>
119
+ issue.source === VALIDATION_SOURCES.LIQUID ||
120
+ issue.rule?.includes('liquid') ||
121
+ issue.message?.toLowerCase().includes('liquid')
122
+ );
123
+
124
+ return {
125
+ totalErrors: errors.length,
126
+ totalWarnings: warnings.length,
127
+ hasLiquidErrors: liquidErrors.length > 0,
128
+ totalIssues: allIssues.length
129
+ };
130
+ };
@@ -0,0 +1,200 @@
1
+ /**
2
+ * HTMLEditor Testing Integration
3
+ *
4
+ * Console-controlled testing component for HTMLEditor integration
5
+ * Can be toggled on/off without affecting existing EmailWrapper functionality
6
+ */
7
+
8
+ import React, { useState, useEffect } from 'react';
9
+ import { IntlProvider } from 'react-intl';
10
+ import HTMLEditor from '../../../v2Components/HtmlEditor';
11
+ import { HTML_EDITOR_VARIANTS } from '../../../v2Components/HtmlEditor/constants';
12
+ import { LAYOUT_TYPES } from '../../../v2Components/HtmlEditor/components/InAppPreviewPane/constants';
13
+
14
+ const HTMLEditorTesting = () => {
15
+ const [isVisible, setIsVisible] = useState(false);
16
+ const [variant, setVariant] = useState(HTML_EDITOR_VARIANTS.EMAIL);
17
+ const [layoutType, setLayoutType] = useState(LAYOUT_TYPES.MODAL);
18
+ const [content, setContent] = useState('<h1>Test HTML Editor</h1><p>This is a test integration.</p>');
19
+
20
+ // Expose console methods
21
+ useEffect(() => {
22
+ // Create global testing interface
23
+ window.htmlEditorTest = {
24
+ // Show/Hide editor
25
+ show: () => {
26
+ setIsVisible(true);
27
+ console.log('✅ HTMLEditor test mode activated');
28
+ },
29
+
30
+ hide: () => {
31
+ setIsVisible(false);
32
+ console.log('✅ HTMLEditor test mode deactivated');
33
+ },
34
+
35
+ toggle: () => {
36
+ setIsVisible(prev => !prev);
37
+ console.log(`✅ HTMLEditor test mode ${!isVisible ? 'activated' : 'deactivated'}`);
38
+ },
39
+
40
+ // Variant control
41
+ setVariant: (newVariant) => {
42
+ if (['email', 'inapp'].includes(newVariant)) {
43
+ setVariant(newVariant);
44
+ console.log(`✅ Variant set to: ${newVariant}`);
45
+ } else {
46
+ console.error('❌ Invalid variant. Use: "email" or "inapp"');
47
+ }
48
+ },
49
+
50
+ // Layout control (for InApp variant)
51
+ setLayout: (layout) => {
52
+ const validLayouts = Object.values(LAYOUT_TYPES);
53
+ if (validLayouts.includes(layout)) {
54
+ setLayoutType(layout);
55
+ console.log(`✅ Layout set to: ${layout}`);
56
+ } else {
57
+ console.error(`❌ Invalid layout. Use: ${validLayouts.join(', ')}`);
58
+ }
59
+ },
60
+
61
+ // Content control
62
+ setContent: (newContent) => {
63
+ setContent(newContent);
64
+ console.log('✅ Content updated');
65
+ },
66
+
67
+ getContent: () => {
68
+ console.log('Current content:', content);
69
+ return content;
70
+ },
71
+
72
+ // Status
73
+ status: () => {
74
+ console.log('📊 HTMLEditor Test Status:');
75
+ console.log(` Visible: ${isVisible}`);
76
+ console.log(` Variant: ${variant}`);
77
+ console.log(` Layout: ${layoutType}`);
78
+ console.log(` Content size: ${content.length} chars`);
79
+ },
80
+
81
+ // Help
82
+ help: () => {
83
+ console.log(`
84
+ 🚀 HTMLEditor Testing Console Commands:
85
+
86
+ 📱 Basic Controls:
87
+ htmlEditorTest.show() - Show the editor
88
+ htmlEditorTest.hide() - Hide the editor
89
+ htmlEditorTest.toggle() - Toggle editor visibility
90
+
91
+ ⚙️ Configuration:
92
+ htmlEditorTest.setVariant('email') - Set to email variant
93
+ htmlEditorTest.setVariant('inapp') - Set to inapp variant
94
+ htmlEditorTest.setLayout('POPUP') - Set layout (inapp only)
95
+ - Valid: POPUP, HEADER, FOOTER, FULLSCREEN
96
+
97
+ 📝 Content:
98
+ htmlEditorTest.setContent('<h1>Test</h1>') - Set editor content
99
+ htmlEditorTest.getContent() - Get current content
100
+
101
+ 📊 Status:
102
+ htmlEditorTest.status() - Show current status
103
+ htmlEditorTest.help() - Show this help
104
+
105
+ 💡 Example Usage:
106
+ htmlEditorTest.show()
107
+ htmlEditorTest.setVariant('inapp')
108
+ htmlEditorTest.setLayout('HEADER') // Top banner
109
+ htmlEditorTest.setLayout('FOOTER') // Bottom banner
110
+ `);
111
+ }
112
+ };
113
+
114
+ // Show help on first load
115
+ console.log('🚀 HTMLEditor Testing Ready! Type htmlEditorTest.help() for commands');
116
+
117
+ // Cleanup on unmount
118
+ return () => {
119
+ if (window.htmlEditorTest) {
120
+ delete window.htmlEditorTest;
121
+ }
122
+ };
123
+ }, [isVisible, content, variant, layoutType]);
124
+
125
+ // Don't render anything if not visible
126
+ if (!isVisible) {
127
+ return null;
128
+ }
129
+
130
+ return (
131
+ <div style={{
132
+ position: 'fixed',
133
+ top: 0,
134
+ left: 0,
135
+ right: 0,
136
+ bottom: 0,
137
+ backgroundColor: 'rgba(0, 0, 0, 0.8)',
138
+ zIndex: 9999,
139
+ display: 'flex',
140
+ flexDirection: 'column',
141
+ padding: '20px'
142
+ }}>
143
+ {/* Header */}
144
+ <div style={{
145
+ backgroundColor: '#fff',
146
+ padding: '10px 20px',
147
+ borderRadius: '8px 8px 0 0',
148
+ display: 'flex',
149
+ justifyContent: 'space-between',
150
+ alignItems: 'center',
151
+ borderBottom: '1px solid #ddd'
152
+ }}>
153
+ <div>
154
+ <strong>HTMLEditor Testing Mode</strong>
155
+ <span style={{ marginLeft: '20px', color: '#666' }}>
156
+ Variant: {variant} | Layout: {layoutType}
157
+ </span>
158
+ </div>
159
+ <button
160
+ onClick={() => setIsVisible(false)}
161
+ style={{
162
+ background: '#ff4d4f',
163
+ color: 'white',
164
+ border: 'none',
165
+ padding: '5px 15px',
166
+ borderRadius: '4px',
167
+ cursor: 'pointer'
168
+ }}
169
+ >
170
+ Close
171
+ </button>
172
+ </div>
173
+
174
+ {/* Editor Container */}
175
+ <div style={{
176
+ flex: 1,
177
+ backgroundColor: '#fff',
178
+ borderRadius: '0 0 8px 8px',
179
+ overflow: 'hidden'
180
+ }}>
181
+ <IntlProvider locale="en" messages={{}}>
182
+ <HTMLEditor
183
+ variant={variant}
184
+ layoutType={layoutType}
185
+ initialContent={content}
186
+ onContentChange={(newContent) => {
187
+ setContent(newContent);
188
+ console.log('📝 Content changed:', newContent.substring(0, 100) + '...');
189
+ }}
190
+ onSave={(savedContent) => {
191
+ console.log('💾 Content saved:', savedContent);
192
+ }}
193
+ />
194
+ </IntlProvider>
195
+ </div>
196
+ </div>
197
+ );
198
+ };
199
+
200
+ export default HTMLEditorTesting;