[_]: feat/add inline image handling and styling for email content#75
[_]: feat/add inline image handling and styling for email content#75jzunigax2 wants to merge 1 commit into
Conversation
jzunigax2
commented
Jul 16, 2026
- Introduced a new constant for maximum inline image size.
- Enhanced the email composition editor to handle image drops with size validation.
- Updated CSS styles for rendered email content to ensure proper formatting of headings, lists, and links.
- Added localization support for inline image size error messages in multiple languages.
- Introduced a new constant for maximum inline image size. - Enhanced the email composition editor to handle image drops with size validation. - Updated CSS styles for rendered email content to ensure proper formatting of headings, lists, and links. - Added localization support for inline image size error messages in multiple languages.
|
📝 WalkthroughWalkthroughAdds size-limited inline image drag-and-drop handling with localized warnings, and updates rendered mail previews with dedicated typography and responsive image styling. ChangesInline image drop handling
Mail preview styling
Estimated code review effort: 3 (Moderate) | ~20 minutes Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 Biome (2.5.3)src/index.cssFile contains syntax errors that prevent linting: Line 4: Tailwind-specific syntax is disabled.; Line 5: Tailwind-specific syntax is disabled.; Line 6: Tailwind-specific syntax is disabled.; Line 14: Tailwind-specific syntax is disabled. 🔧 ESLint
ESLint install timed out. The project may have too many dependencies for the sandbox. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Warning
CodeRabbit couldn't request changes on this pull request because it doesn't have sufficient GitHub permissions.
Please grant CodeRabbit Pull requests: Read and write permission and re-run the review.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/components/compose-message/config.ts`:
- Around line 115-124: Update the image insertion flow around the images.forEach
FileReader callbacks to await all image reads before dispatching. Preserve the
original image order, create all image nodes, then insert them in one
transaction at a position clamped to the current document’s valid limits instead
of reusing the stale pos for separate dispatches.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: 480e0bf2-4c16-4c79-9497-068b5ed9e107
📒 Files selected for processing (8)
src/components/compose-message/config.tssrc/constants.tssrc/features/mail/components/mail-preview/preview/index.tsxsrc/i18n/locales/en.jsonsrc/i18n/locales/es.jsonsrc/i18n/locales/fr.jsonsrc/i18n/locales/it.jsonsrc/index.css
| images.forEach((file) => { | ||
| const reader = new FileReader(); | ||
| reader.onload = () => { | ||
| if (typeof reader.result !== 'string') return; | ||
| const node = view.state.schema.nodes.image.create({ src: reader.result }); | ||
| view.dispatch(view.state.tr.insert(pos, node)); | ||
| }; | ||
| reader.readAsDataURL(file); | ||
| }); | ||
| return true; |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Group image insertions to prevent out-of-order rendering and out-of-bounds crashes.
When multiple images are dropped, reading them asynchronously and inserting them at the exact same static pos causes them to be rendered in reverse order (each insertion pushes the previous one to the right). Furthermore, if the user modifies the document during the async read, pos may become invalid, leading to a ProseMirror RangeError.
Wait for all images to be read, and insert them in a single transaction while clamping the position to the current document limits.
🐛 Proposed fix to handle async insertion
- images.forEach((file) => {
- const reader = new FileReader();
- reader.onload = () => {
- if (typeof reader.result !== 'string') return;
- const node = view.state.schema.nodes.image.create({ src: reader.result });
- view.dispatch(view.state.tr.insert(pos, node));
- };
- reader.readAsDataURL(file);
- });
+ if (images.length > 0) {
+ Promise.all(
+ images.map(
+ (file) =>
+ new Promise<string>((resolve) => {
+ const reader = new FileReader();
+ reader.onload = () => resolve(reader.result as string);
+ reader.readAsDataURL(file);
+ })
+ )
+ ).then((results) => {
+ const nodes = results.map((src) =>
+ view.state.schema.nodes.image.create({ src })
+ );
+
+ // Protect against document mutations invalidating the original pos
+ const maxPos = view.state.doc.content.size;
+ const validPos = pos > maxPos ? maxPos : pos;
+
+ view.dispatch(view.state.tr.insert(validPos, nodes));
+ });
+ }📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| images.forEach((file) => { | |
| const reader = new FileReader(); | |
| reader.onload = () => { | |
| if (typeof reader.result !== 'string') return; | |
| const node = view.state.schema.nodes.image.create({ src: reader.result }); | |
| view.dispatch(view.state.tr.insert(pos, node)); | |
| }; | |
| reader.readAsDataURL(file); | |
| }); | |
| return true; | |
| if (images.length > 0) { | |
| Promise.all( | |
| images.map( | |
| (file) => | |
| new Promise<string>((resolve) => { | |
| const reader = new FileReader(); | |
| reader.onload = () => resolve(reader.result as string); | |
| reader.readAsDataURL(file); | |
| }) | |
| ) | |
| ).then((results) => { | |
| const nodes = results.map((src) => | |
| view.state.schema.nodes.image.create({ src }) | |
| ); | |
| // Protect against document mutations invalidating the original pos | |
| const maxPos = view.state.doc.content.size; | |
| const validPos = pos > maxPos ? maxPos : pos; | |
| view.dispatch(view.state.tr.insert(validPos, nodes)); | |
| }); | |
| } | |
| return true; |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/components/compose-message/config.ts` around lines 115 - 124, Update the
image insertion flow around the images.forEach FileReader callbacks to await all
image reads before dispatching. Preserve the original image order, create all
image nodes, then insert them in one transaction at a position clamped to the
current document’s valid limits instead of reusing the stale pos for separate
dispatches.

