Pasting an image while the markdown editor was focused left it stuck on
ProseMirror's inline "uploading" placeholder instead of going to the
attachment strip. The capture-phase paste interceptor bailed before it
could redirect the file because:
pasted images usually surface only through clipboardData.items
(getAsFile), with clipboardData.files left empty, and
image pastes often advertise an emptytext/plain entry, which the
old types.includes('text/plain') check mistook for a text paste.
Read files from items (falling back to files), and gate on the actual
text payload rather than the advertised type, so real text pastes
(Excel/Word renditions) still paste as text while pure image pastes
become attachments.
Improved clipboard paste and drag-and-drop handling to more reliably distinguish text pastes from actual file drops, preventing incorrect attachment behavior.
UI Updates
Updated the markdown editor’s image behavior by disabling image upload controls.
Adjusted editor image rendering to respect width/height limits for more consistent display.
Pasting an image while the markdown editor was focused left it stuck on
ProseMirror's inline "uploading" placeholder instead of going to the
attachment strip. The capture-phase paste interceptor bailed before it
could redirect the file because:
- pasted images usually surface only through `clipboardData.items`
(`getAsFile`), with `clipboardData.files` left empty, and
- image pastes often advertise an *empty* `text/plain` entry, which the
old `types.includes('text/plain')` check mistook for a text paste.
Read files from `items` (falling back to `files`), and gate on the actual
text payload rather than the advertised type, so real text pastes
(Excel/Word renditions) still paste as text while pure image pastes
become attachments.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01QtNQeBpkDJPC9obiB25pV6
<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit
* **Bug Fixes**
* Improved clipboard paste and drag-and-drop handling to more reliably distinguish text pastes from actual file drops, preventing incorrect attachment behavior.
* **UI Updates**
* Updated the markdown editor’s image behavior by disabling image upload controls.
* Adjusted editor image rendering to respect width/height limits for more consistent display.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Reviewing files that changed from the base of the PR and between 372b12f339 and fa88a7c07b.
📒 Files selected for processing (1)
js/desktop/src/hooks/use-file-input.ts
🚧 Files skipped from review as they are similar to previous changes (1)
js/desktop/src/hooks/use-file-input.ts
📝 Walkthrough
Walkthrough
The PR introduces a shared transferFiles helper that robustly extracts file objects from DataTransfer by prioritizing items with fallback to files. The useFileInput hook's clipboard paste handler now distinguishes file payloads from text pastes using content-based text detection (getData('text/plain')), while both paste and drop handlers leverage transferFiles for file extraction. The markdown editor disables image file uploads by turning off Crepe.Feature.ImageBlock, adds an explicit drop handler to decline dropped files, and updates CSS to constrain rendered image height to 420px.
Changes
Compose Editor File and Image Handling
Layer / File(s)
Summary
Shared file transfer helper js/desktop/src/lib/data-transfer.ts
Exports transferFiles(data: DataTransfer): File[] that extracts file objects by filtering data.items entries of kind 'file' via getAsFile() with null filtering, falling back to Array.from(data.files) when no items are found.
File input paste and drop handlers js/desktop/src/hooks/use-file-input.ts
Updates paste handler to detect text pastes via getData('text/plain').trim().length instead of checking advertised types, uses transferFiles for file extraction, and only prevents default/propagation when files are found. Drop handler similarly refactored to use transferFiles instead of direct Array.from(dataTransfer.files).
Markdown editor image upload disabling and rendering js/desktop/src/features/compose/markdown-editor.tsx, js/desktop/src/features/compose/markdown-editor.css
Disables Crepe.Feature.ImageBlock feature flag to prevent image file uploads while allowing image links to render, adds explicit drop handler using transferFiles to decline dropped files, and replaces prior CSS that hid image uploader controls with a new rule constraining images in .llink-crepe .milkdown .ProseMirror img to max-height: 420px.
Estimated code review effort
🎯 3 (Moderate) | ⏱️ ~20 minutes
Poem
🐇 A helper now handles all files with great care,
Detecting true text when it's truly in there.
Images upload-free, yet still render with grace,
With height-bound constraints in their rightful place.
Drop handlers decline with composure and flair! ✨
Note
🎁 Summarized by CodeRabbit Free
Your organization is on the Free plan. CodeRabbit will generate a high-level summary and a walkthrough for each pull request. For a comprehensive line-by-line review, please upgrade your subscription to CodeRabbit Pro by visiting https://app.coderabbit.ai/login.
Comment @coderabbitai help to get the list of available commands and usage tips.
<!-- This is an auto-generated comment: summarize by coderabbit.ai -->
<!-- review_stack_entry_start -->
[](https://app.coderabbit.ai/change-stack/flowy-live/llink/pull/295?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack)
<!-- review_stack_entry_end -->
<details>
<summary>ℹ️ Recent review info</summary>
<details>
<summary>⚙️ Run configuration</summary>
**Configuration used**: defaults
**Review profile**: CHILL
**Plan**: Free
**Run ID**: `7a10ac15-13a3-4cbf-9414-713f26433f2e`
</details>
<details>
<summary>📥 Commits</summary>
Reviewing files that changed from the base of the PR and between 372b12f339d78737e13da26bb27a3be03c8270d0 and fa88a7c07b4650520c3800164c23d0cd31816b93.
</details>
<details>
<summary>📒 Files selected for processing (1)</summary>
* `js/desktop/src/hooks/use-file-input.ts`
</details>
<details>
<summary>🚧 Files skipped from review as they are similar to previous changes (1)</summary>
* js/desktop/src/hooks/use-file-input.ts
</details>
</details>
---
<!-- walkthrough_start -->
<details>
<summary>📝 Walkthrough</summary>
## Walkthrough
The PR introduces a shared `transferFiles` helper that robustly extracts file objects from `DataTransfer` by prioritizing `items` with fallback to `files`. The `useFileInput` hook's clipboard paste handler now distinguishes file payloads from text pastes using content-based text detection (`getData('text/plain')`), while both paste and drop handlers leverage `transferFiles` for file extraction. The markdown editor disables image file uploads by turning off `Crepe.Feature.ImageBlock`, adds an explicit drop handler to decline dropped files, and updates CSS to constrain rendered image height to 420px.
## Changes
**Compose Editor File and Image Handling**
| Layer / File(s) | Summary |
|---|---|
| **Shared file transfer helper** <br> `js/desktop/src/lib/data-transfer.ts` | Exports `transferFiles(data: DataTransfer): File[]` that extracts file objects by filtering `data.items` entries of kind `'file'` via `getAsFile()` with null filtering, falling back to `Array.from(data.files)` when no items are found. |
| **File input paste and drop handlers** <br> `js/desktop/src/hooks/use-file-input.ts` | Updates paste handler to detect text pastes via `getData('text/plain').trim().length` instead of checking advertised types, uses `transferFiles` for file extraction, and only prevents default/propagation when files are found. Drop handler similarly refactored to use `transferFiles` instead of direct `Array.from(dataTransfer.files)`. |
| **Markdown editor image upload disabling and rendering** <br> `js/desktop/src/features/compose/markdown-editor.tsx`, `js/desktop/src/features/compose/markdown-editor.css` | Disables `Crepe.Feature.ImageBlock` feature flag to prevent image file uploads while allowing image links to render, adds explicit drop handler using `transferFiles` to decline dropped files, and replaces prior CSS that hid image uploader controls with a new rule constraining images in `.llink-crepe .milkdown .ProseMirror img` to `max-height: 420px`. |
## Estimated code review effort
🎯 3 (Moderate) | ⏱️ ~20 minutes
## Poem
> 🐇 A helper now handles all files with great care,
> Detecting true text when it's truly in there.
> Images upload-free, yet still render with grace,
> With height-bound constraints in their rightful place.
> Drop handlers decline with composure and flair! ✨
</details>
<!-- walkthrough_end -->
<!-- tips_start -->
---
> [!NOTE]
> <details>
> <summary>🎁 Summarized by CodeRabbit Free</summary>
>
> Your organization is on the Free plan. CodeRabbit will generate a high-level summary and a walkthrough for each pull request. For a comprehensive line-by-line review, please upgrade your subscription to CodeRabbit Pro by visiting <https://app.coderabbit.ai/login>.
>
> </details>
<sub>Comment `@coderabbitai help` to get the list of available commands and usage tips.</sub>
<!-- tips_end -->
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Pasting an image while the markdown editor was focused left it stuck on
ProseMirror's inline "uploading" placeholder instead of going to the
attachment strip. The capture-phase paste interceptor bailed before it
could redirect the file because:
clipboardData.items(
getAsFile), withclipboardData.filesleft empty, andtext/plainentry, which theold
types.includes('text/plain')check mistook for a text paste.Read files from
items(falling back tofiles), and gate on the actualtext payload rather than the advertised type, so real text pastes
(Excel/Word renditions) still paste as text while pure image pastes
become attachments.
Co-Authored-By: Claude Opus 4.8 (1M context) [email protected]
Claude-Session: https://claude.ai/code/session_01QtNQeBpkDJPC9obiB25pV6
Summary by CodeRabbit
ℹ️ Recent review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Free
Run ID:
7a10ac15-13a3-4cbf-9414-713f26433f2e📥 Commits
Reviewing files that changed from the base of the PR and between
372b12f339andfa88a7c07b.📒 Files selected for processing (1)
js/desktop/src/hooks/use-file-input.ts🚧 Files skipped from review as they are similar to previous changes (1)
📝 Walkthrough
Walkthrough
The PR introduces a shared
transferFileshelper that robustly extracts file objects fromDataTransferby prioritizingitemswith fallback tofiles. TheuseFileInputhook's clipboard paste handler now distinguishes file payloads from text pastes using content-based text detection (getData('text/plain')), while both paste and drop handlers leveragetransferFilesfor file extraction. The markdown editor disables image file uploads by turning offCrepe.Feature.ImageBlock, adds an explicit drop handler to decline dropped files, and updates CSS to constrain rendered image height to 420px.Changes
Compose Editor File and Image Handling
js/desktop/src/lib/data-transfer.tstransferFiles(data: DataTransfer): File[]that extracts file objects by filteringdata.itemsentries of kind'file'viagetAsFile()with null filtering, falling back toArray.from(data.files)when no items are found.js/desktop/src/hooks/use-file-input.tsgetData('text/plain').trim().lengthinstead of checking advertised types, usestransferFilesfor file extraction, and only prevents default/propagation when files are found. Drop handler similarly refactored to usetransferFilesinstead of directArray.from(dataTransfer.files).js/desktop/src/features/compose/markdown-editor.tsx,js/desktop/src/features/compose/markdown-editor.cssCrepe.Feature.ImageBlockfeature flag to prevent image file uploads while allowing image links to render, adds explicit drop handler usingtransferFilesto decline dropped files, and replaces prior CSS that hid image uploader controls with a new rule constraining images in.llink-crepe .milkdown .ProseMirror imgtomax-height: 420px.Estimated code review effort
🎯 3 (Moderate) | ⏱️ ~20 minutes
Poem
Comment
@coderabbitai helpto get the list of available commands and usage tips.