@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.
- package/assets/Android.png +0 -0
- package/assets/iOS.png +0 -0
- package/package.json +16 -2
- package/v2Components/HtmlEditor/HTMLEditor.js +508 -0
- package/v2Components/HtmlEditor/__tests__/HTMLEditor.test.js +1809 -0
- package/v2Components/HtmlEditor/__tests__/index.lazy.test.js +532 -0
- package/v2Components/HtmlEditor/_htmlEditor.scss +304 -0
- package/v2Components/HtmlEditor/_index.lazy.scss +26 -0
- package/v2Components/HtmlEditor/components/CodeEditorPane/_codeEditorPane.scss +376 -0
- package/v2Components/HtmlEditor/components/CodeEditorPane/index.js +331 -0
- package/v2Components/HtmlEditor/components/DeviceToggle/__tests__/index.test.js +314 -0
- package/v2Components/HtmlEditor/components/DeviceToggle/_deviceToggle.scss +244 -0
- package/v2Components/HtmlEditor/components/DeviceToggle/index.js +111 -0
- package/v2Components/HtmlEditor/components/EditorToolbar/PreviewModeGroup.js +72 -0
- package/v2Components/HtmlEditor/components/EditorToolbar/__tests__/PreviewModeGroup.test.js +1594 -0
- package/v2Components/HtmlEditor/components/EditorToolbar/_editorToolbar.scss +113 -0
- package/v2Components/HtmlEditor/components/EditorToolbar/_previewModeGroup.scss +82 -0
- package/v2Components/HtmlEditor/components/EditorToolbar/index.js +115 -0
- package/v2Components/HtmlEditor/components/FullscreenModal/_fullscreenModal.scss +57 -0
- package/v2Components/HtmlEditor/components/InAppPreviewPane/ContentOverlay.js +90 -0
- package/v2Components/HtmlEditor/components/InAppPreviewPane/DeviceFrame.js +60 -0
- package/v2Components/HtmlEditor/components/InAppPreviewPane/LayoutSelector.js +58 -0
- package/v2Components/HtmlEditor/components/InAppPreviewPane/__tests__/ContentOverlay.test.js +403 -0
- package/v2Components/HtmlEditor/components/InAppPreviewPane/__tests__/DeviceFrame.test.js +424 -0
- package/v2Components/HtmlEditor/components/InAppPreviewPane/__tests__/LayoutSelector.test.js +248 -0
- package/v2Components/HtmlEditor/components/InAppPreviewPane/_inAppPreviewPane.scss +253 -0
- package/v2Components/HtmlEditor/components/InAppPreviewPane/constants.js +104 -0
- package/v2Components/HtmlEditor/components/InAppPreviewPane/index.js +179 -0
- package/v2Components/HtmlEditor/components/PreviewPane/_previewPane.scss +220 -0
- package/v2Components/HtmlEditor/components/PreviewPane/index.js +229 -0
- package/v2Components/HtmlEditor/components/SplitContainer/SplitContainer.js +276 -0
- package/v2Components/HtmlEditor/components/SplitContainer/__tests__/SplitContainer.test.js +295 -0
- package/v2Components/HtmlEditor/components/SplitContainer/_splitContainer.scss +257 -0
- package/v2Components/HtmlEditor/components/SplitContainer/index.js +7 -0
- package/v2Components/HtmlEditor/components/ValidationErrorDisplay/__tests__/index.test.js +152 -0
- package/v2Components/HtmlEditor/components/ValidationErrorDisplay/_validationErrorDisplay.scss +31 -0
- package/v2Components/HtmlEditor/components/ValidationErrorDisplay/index.js +70 -0
- package/v2Components/HtmlEditor/components/ValidationPanel/__tests__/index.test.js +98 -0
- package/v2Components/HtmlEditor/components/ValidationPanel/_validationPanel.scss +311 -0
- package/v2Components/HtmlEditor/components/ValidationPanel/index.js +297 -0
- package/v2Components/HtmlEditor/components/ValidationPanel/messages.js +57 -0
- package/v2Components/HtmlEditor/components/common/EditorContext.js +84 -0
- package/v2Components/HtmlEditor/components/common/__tests__/EditorContext.test.js +660 -0
- package/v2Components/HtmlEditor/constants.js +241 -0
- package/v2Components/HtmlEditor/hooks/__tests__/useEditorContent.test.js +450 -0
- package/v2Components/HtmlEditor/hooks/__tests__/useInAppContent.test.js +785 -0
- package/v2Components/HtmlEditor/hooks/__tests__/useLayoutState.test.js +580 -0
- package/v2Components/HtmlEditor/hooks/__tests__/useValidation.enhanced.test.js +768 -0
- package/v2Components/HtmlEditor/hooks/__tests__/useValidation.test.js +590 -0
- package/v2Components/HtmlEditor/hooks/useEditorContent.js +274 -0
- package/v2Components/HtmlEditor/hooks/useInAppContent.js +407 -0
- package/v2Components/HtmlEditor/hooks/useLayoutState.js +247 -0
- package/v2Components/HtmlEditor/hooks/useValidation.js +325 -0
- package/v2Components/HtmlEditor/index.js +29 -0
- package/v2Components/HtmlEditor/index.lazy.js +114 -0
- package/v2Components/HtmlEditor/messages.js +389 -0
- package/v2Components/HtmlEditor/utils/__tests__/contentSanitizer.test.js +741 -0
- package/v2Components/HtmlEditor/utils/__tests__/htmlValidator.enhanced.test.js +1042 -0
- package/v2Components/HtmlEditor/utils/__tests__/liquidTemplateSupport.test.js +515 -0
- package/v2Components/HtmlEditor/utils/__tests__/properSyntaxHighlighting.test.js +473 -0
- package/v2Components/HtmlEditor/utils/__tests__/simplePerformance.test.js +1109 -0
- package/v2Components/HtmlEditor/utils/__tests__/validationAdapter.test.js +240 -0
- package/v2Components/HtmlEditor/utils/contentSanitizer.js +433 -0
- package/v2Components/HtmlEditor/utils/htmlValidator.js +508 -0
- package/v2Components/HtmlEditor/utils/liquidTemplateSupport.js +524 -0
- package/v2Components/HtmlEditor/utils/properSyntaxHighlighting.js +163 -0
- package/v2Components/HtmlEditor/utils/simplePerformance.js +145 -0
- package/v2Components/HtmlEditor/utils/validationAdapter.js +130 -0
- package/v2Containers/EmailWrapper/components/HTMLEditorTesting.js +200 -0
- package/v2Containers/EmailWrapper/components/__tests__/HTMLEditorTesting.test.js +545 -0
- package/v2Containers/EmailWrapper/index.js +8 -1
- package/v2Containers/Rcs/index.js +2 -0
- package/v2Containers/Templates/constants.js +8 -0
- package/v2Containers/Templates/index.js +56 -28
- package/v2Containers/Templates/tests/__snapshots__/index.test.js.snap +5 -14
- 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;
|