diff --git a/components/email/ComposeEmail.tsx b/components/email/ComposeEmail.tsx
index 99fbe49f..12018b43 100644
--- a/components/email/ComposeEmail.tsx
+++ b/components/email/ComposeEmail.tsx
@@ -18,6 +18,19 @@ import {
sanitizeHtml
} from '@/lib/utils/email-formatter';
+/**
+ * CENTRAL EMAIL COMPOSER COMPONENT
+ *
+ * This is the unified, centralized email composer component used throughout the application.
+ * It handles new emails, replies, and forwards with proper text direction.
+ *
+ * All code that needs to compose emails should import this component from:
+ * @/components/email/ComposeEmail
+ *
+ * It uses the centralized email formatter from @/lib/utils/email-formatter.ts
+ * for consistent handling of email content and text direction.
+ */
+
// Define EmailMessage interface locally instead of importing from server-only file
interface EmailAddress {
name: string;
@@ -246,31 +259,33 @@ export default function ComposeEmail(props: ComposeEmailAllProps) {
// Handle editor input
const handleEditorInput = () => {
- if (editorRef.current) {
- // Store the current selection/cursor position
- const selection = window.getSelection();
- const range = selection?.getRangeAt(0);
- const offset = range?.startOffset || 0;
- const container = range?.startContainer;
+ if (!editorRef.current) return;
+
+ // Store the current selection/cursor position
+ const selection = window.getSelection();
+ const range = selection?.getRangeAt(0);
+ const offset = range?.startOffset || 0;
+ const container = range?.startContainer;
+
+ // Capture the content
+ setEmailContent(editorRef.current.innerHTML);
+
+ // Try to restore the cursor position after React updates
+ setTimeout(() => {
+ if (!selection || !range || !container || !editorRef.current) return;
- // Capture the content
- setEmailContent(editorRef.current.innerHTML);
-
- // Try to restore the cursor position after React updates
- setTimeout(() => {
- try {
- if (selection && range && container && editorRef.current && editorRef.current.contains(container)) {
- const newRange = document.createRange();
- newRange.setStart(container, offset);
- newRange.collapse(true);
- selection.removeAllRanges();
- selection.addRange(newRange);
- }
- } catch (e) {
- console.error('Error restoring cursor position:', e);
+ try {
+ if (editorRef.current.contains(container)) {
+ const newRange = document.createRange();
+ newRange.setStart(container, offset);
+ newRange.collapse(true);
+ selection.removeAllRanges();
+ selection.addRange(newRange);
}
- }, 0);
- }
+ } catch (e) {
+ console.error('Error restoring cursor position:', e);
+ }
+ }, 0);
};
// Send email
@@ -402,7 +417,7 @@ export default function ComposeEmail(props: ComposeEmailAllProps) {
- {/* Email editor - standard LTR for English content */}
+ {/* Email editor - uses auto direction to detect content language */}
diff --git a/lib/utils/email-formatter.ts b/lib/utils/email-formatter.ts
index f3c1b139..c00941d3 100644
--- a/lib/utils/email-formatter.ts
+++ b/lib/utils/email-formatter.ts
@@ -1,12 +1,11 @@
/**
- * CENTRAL EMAIL FORMATTER
+ * CENTRAL EMAIL FORMATTING UTILITY
*
- * This is the primary and only email formatting utility to be used.
- * All email formatting should go through here to ensure consistent
- * handling of text direction and HTML sanitization.
+ * This is the centralized email formatting utility used throughout the application.
+ * It provides consistent handling of email content, sanitization, and text direction.
*
- * IMPORTANT: This formatter is configured for English-only content
- * and enforces left-to-right text direction.
+ * All code that needs to format email content should import from this file.
+ * Text direction is standardized to LTR (left-to-right) for consistency.
*/
import DOMPurify from 'isomorphic-dompurify';
@@ -16,38 +15,29 @@ DOMPurify.removeAllHooks();
// Configure DOMPurify for English-only content (always LTR)
DOMPurify.addHook('afterSanitizeAttributes', function(node) {
- // Force LTR direction on all elements that can have a dir attribute
+ // We no longer force LTR direction on all elements
+ // This allows the natural text direction to be preserved
if (node instanceof HTMLElement) {
- node.setAttribute('dir', 'ltr');
-
- // Handle style attribute
- if (node.hasAttribute('style')) {
- let style = node.getAttribute('style') || '';
-
- // Remove any RTL-related styles
- style = style.replace(/direction\s*:\s*rtl\s*;?/gi, '');
- style = style.replace(/text-align\s*:\s*right\s*;?/gi, '');
- style = style.replace(/unicode-bidi\s*:[^;]*;?/gi, '');
-
- // Add explicit LTR styles
- style = style.trim();
- if (style && !style.endsWith(';')) style += ';';
- style += ' direction: ltr; text-align: left;';
-
- node.setAttribute('style', style);
- } else {
- // If no style exists, add default LTR styles
- node.setAttribute('style', 'direction: ltr; text-align: left;');
+ // Only set direction if not already specified
+ if (!node.hasAttribute('dir')) {
+ // Add dir attribute only if not present
+ node.setAttribute('dir', 'auto');
}
+
+ // Don't forcibly modify text alignment or direction in style attributes
+ // This allows the component to control text direction instead
}
});
-// Configure DOMPurify to add certain attributes and forbid others
+// Configure DOMPurify to preserve direction attributes
DOMPurify.setConfig({
ADD_ATTR: ['dir'],
- FORBID_ATTR: ['lang', 'bidi']
+ ALLOWED_ATTR: ['style', 'class', 'id', 'dir']
});
+// Note: We ensure LTR text direction is applied in the component level
+// when rendering email content
+
// Interface definitions
export interface EmailAddress {
name: string;
@@ -147,7 +137,7 @@ export function formatForwardedEmail(email: EmailMessage): {
const toString = formatEmailAddresses(email.to || []);
const dateString = formatEmailDate(email.date);
- // Get and sanitize original content (sanitization enforces LTR)
+ // Get and sanitize original content (sanitization preserves content direction)
const originalContent = sanitizeHtml(email.content || email.html || email.text || '');
// Check if the content already has a forwarded message header
@@ -177,7 +167,7 @@ export function formatForwardedEmail(email: EmailMessage): {