feat: add ImagePasteAddon for clipboard image handling#143
Conversation
Image paste handling was baked into Terminal and InputHandler as a custom onImagePaste event, which doesn't exist in the xterm.js API. Extract it into an opt-in addon following the ITerminalAddon pattern (same as FitAddon) to keep the core Terminal API xterm.js-conformant. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
Heya, really cool project! I was building a VSCode extension with ghostty-web and ran into the issue where I needed to paste images. I created this plugin with Claude Opus to handle such a case. Not sure if you're accepting submissions coauthored by AI, but if so, I've found this helpful and wanted to contribute. |
Adds ImagePasteAddon, a new addon following the ITerminalAddon pattern
(same as FitAddon), that detects image data in clipboard paste events
and emits them as base64-encoded payloads via an onImagePaste event.
Also updates InputHandler.handlePaste to only claim paste events that
contain text. Paste events without text (e.g. image-only) are no longer
consumed by the default handler, allowing them to bubble through to
addons like ImagePasteAddon.
The core Terminal API stays strictly xterm.js-conformant — no custom
events on the Terminal class.
Public API additions in lib/index.ts:
- ImagePasteAddon class
- IImagePasteData type
Usage:
import { Terminal, ImagePasteAddon } from 'ghostty-web';
const term = new Terminal();
const addon = new ImagePasteAddon();
term.loadAddon(addon);
addon.onImagePaste((data) => { /* data.name, data.dataBase64 */ });
Adapts the import order to satisfy our Biome organizeImports rule
(value imports before type-only imports).
Co-authored-by: Brian Egan <brian.egan@verygood.ventures>
Inspired-by: coder#143
Adds ImagePasteAddon, a new addon following the ITerminalAddon pattern
(same as FitAddon), that detects image data in clipboard paste events
and emits them as base64-encoded payloads via an onImagePaste event.
Also updates InputHandler.handlePaste to only claim paste events that
contain text. Paste events without text (e.g. image-only) are no longer
consumed by the default handler, allowing them to bubble through to
addons like ImagePasteAddon.
The core Terminal API stays strictly xterm.js-conformant — no custom
events on the Terminal class.
Public API additions in lib/index.ts:
- ImagePasteAddon class
- IImagePasteData type
Usage:
import { Terminal, ImagePasteAddon } from 'ghostty-web';
const term = new Terminal();
const addon = new ImagePasteAddon();
term.loadAddon(addon);
addon.onImagePaste((data) => { /* data.name, data.dataBase64 */ });
Adapts the import order to satisfy our Biome organizeImports rule
(value imports before type-only imports).
Inspired-by: coder#143
Co-authored-by: Brian Egan <brian.egan@verygood.ventures>
|
Hi @brianegan! 👋 Your work on this PR inspired a commit in my fork diegosouzapw/ghostty-web. I'm working on OmniRoute, a project that provides free access to LLM models, and I'm planning to use ghostty-web as the terminal component there. Your work is part of what makes that possible. 🙏 Feel free to check it out — contributions and feedback are very welcome! |
Summary
ImagePasteAddon, a new addon following theITerminalAddonpattern (same asFitAddon), that detects image data in clipboard paste events and emits them as base64-encoded payloads via anonImagePasteeventInputHandler.handlePasteto only claim paste events that contain text, allowing image-only pastes to bubble through to addonsTerminalAPI strictly xterm.js-conformant — no custom events on the Terminal classUsage
Design decisions
onImagePastedoesn't exist in xterm.js. Implementing it as an addon keeps the drop-in replacement promise intact — code written against the core API remains portable between xterm.js and ghostty-web.InputHandlerno longer callspreventDefault()/stopPropagation()at the top of paste handling. It only claims the event when there is text to process, letting image-only pastes reach addon listeners.ImagePasteAddonandIImagePasteDataare exported from the package entry point.Test plan
image-paste.test.tscovers activation, disposal, lifecycle, event subscription, image paste firing, non-image paste ignoring, and post-dispose cleanuponImagePastefiresonDatabehavior is unaffected🤖 Generated with Claude Code