From 8f22b8baa751554a8e07b9a7159a777ab57b53c1 Mon Sep 17 00:00:00 2001 From: Jeff Emmett Date: Wed, 10 Dec 2025 10:27:44 -0800 Subject: [PATCH] feat: improve mobile touch/pen interactions across custom tools MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add onTouchStart/onTouchEnd handlers to all interactive elements - Add touchAction: 'manipulation' CSS to prevent 300ms click delay - Increase minimum touch target sizes to 44px for accessibility - Fix ImageGen: Generate button, Copy/Download/Delete, input field - Fix VideoGen: Upload, URL input, prompt, duration, Generate button - Fix Transcription: Start/Stop/Pause buttons, textarea, Save/Cancel - Fix Multmux: Create Session, Refresh, session list, input fields 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- src/shapes/ImageGenShapeUtil.tsx | 36 +++++++++++++++ src/shapes/MultmuxShapeUtil.tsx | 38 ++++++++++++++++ src/shapes/TranscriptionShapeUtil.tsx | 51 ++++++++++++++++++--- src/shapes/VideoGenShapeUtil.tsx | 65 ++++++++++++++++++++++----- 4 files changed, 173 insertions(+), 17 deletions(-) diff --git a/src/shapes/ImageGenShapeUtil.tsx b/src/shapes/ImageGenShapeUtil.tsx index a61acbf..01bf2b1 100644 --- a/src/shapes/ImageGenShapeUtil.tsx +++ b/src/shapes/ImageGenShapeUtil.tsx @@ -804,6 +804,8 @@ export class ImageGenShape extends BaseBoxShapeUtil { } }} onPointerDown={(e) => e.stopPropagation()} + onTouchStart={(e) => e.stopPropagation()} + onTouchEnd={(e) => e.stopPropagation()} style={{ flex: 1, padding: '6px 10px', @@ -819,6 +821,8 @@ export class ImageGenShape extends BaseBoxShapeUtil { justifyContent: 'center', gap: '4px', transition: 'background-color 0.15s', + touchAction: 'manipulation', + minHeight: '44px', }} onMouseEnter={(e) => (e.currentTarget.style.backgroundColor = '#f0f0f0')} onMouseLeave={(e) => (e.currentTarget.style.backgroundColor = '#fff')} @@ -850,6 +854,8 @@ export class ImageGenShape extends BaseBoxShapeUtil { console.log('✅ ImageGen: Image download initiated') }} onPointerDown={(e) => e.stopPropagation()} + onTouchStart={(e) => e.stopPropagation()} + onTouchEnd={(e) => e.stopPropagation()} style={{ flex: 1, padding: '6px 10px', @@ -865,6 +871,8 @@ export class ImageGenShape extends BaseBoxShapeUtil { justifyContent: 'center', gap: '4px', transition: 'opacity 0.15s', + touchAction: 'manipulation', + minHeight: '44px', }} onMouseEnter={(e) => (e.currentTarget.style.opacity = '0.9')} onMouseLeave={(e) => (e.currentTarget.style.opacity = '1')} @@ -883,6 +891,8 @@ export class ImageGenShape extends BaseBoxShapeUtil { }) }} onPointerDown={(e) => e.stopPropagation()} + onTouchStart={(e) => e.stopPropagation()} + onTouchEnd={(e) => e.stopPropagation()} style={{ padding: '6px 10px', backgroundColor: '#fff', @@ -896,6 +906,9 @@ export class ImageGenShape extends BaseBoxShapeUtil { alignItems: 'center', justifyContent: 'center', transition: 'background-color 0.15s, color 0.15s', + touchAction: 'manipulation', + minWidth: '44px', + minHeight: '44px', }} onMouseEnter={(e) => { e.currentTarget.style.backgroundColor = '#fee' @@ -952,6 +965,8 @@ export class ImageGenShape extends BaseBoxShapeUtil { borderRadius: "6px", fontSize: 13, padding: "0 10px", + touchAction: "manipulation", + minHeight: "44px", }} type="text" placeholder="Enter image prompt..." @@ -975,6 +990,9 @@ export class ImageGenShape extends BaseBoxShapeUtil { onPointerDown={(e) => { e.stopPropagation() }} + onTouchStart={(e) => { + e.stopPropagation() + }} onClick={(e) => { e.stopPropagation() }} @@ -993,6 +1011,9 @@ export class ImageGenShape extends BaseBoxShapeUtil { fontWeight: "500", fontSize: "13px", opacity: shape.props.prompt.trim() && !shape.props.isLoading ? 1 : 0.6, + touchAction: "manipulation", + minWidth: "44px", + minHeight: "44px", }} onPointerDown={(e) => { e.stopPropagation() @@ -1001,6 +1022,16 @@ export class ImageGenShape extends BaseBoxShapeUtil { handleGenerate() } }} + onTouchStart={(e) => { + e.stopPropagation() + }} + onTouchEnd={(e) => { + e.stopPropagation() + e.preventDefault() + if (shape.props.prompt.trim() && !shape.props.isLoading) { + handleGenerate() + } + }} onClick={(e) => { e.preventDefault() e.stopPropagation() @@ -1045,6 +1076,8 @@ export class ImageGenShape extends BaseBoxShapeUtil { }) }} onPointerDown={(e) => e.stopPropagation()} + onTouchStart={(e) => e.stopPropagation()} + onTouchEnd={(e) => e.stopPropagation()} style={{ padding: "2px 6px", backgroundColor: "#fcc", @@ -1053,6 +1086,9 @@ export class ImageGenShape extends BaseBoxShapeUtil { cursor: "pointer", fontSize: "10px", flexShrink: 0, + touchAction: "manipulation", + minWidth: "32px", + minHeight: "32px", }} > ✕ diff --git a/src/shapes/MultmuxShapeUtil.tsx b/src/shapes/MultmuxShapeUtil.tsx index b89cf14..14aed66 100644 --- a/src/shapes/MultmuxShapeUtil.tsx +++ b/src/shapes/MultmuxShapeUtil.tsx @@ -569,8 +569,11 @@ export class MultmuxShape extends BaseBoxShapeUtil { color: '#cdd6f4', fontFamily: 'monospace', fontSize: '14px', + touchAction: 'manipulation', + minHeight: '44px', }} onPointerDown={(e) => e.stopPropagation()} + onTouchStart={(e) => e.stopPropagation()} onMouseDown={(e) => e.stopPropagation()} /> @@ -672,6 +686,12 @@ export class TranscriptionShape extends BaseBoxShapeUtil { style={buttonStyle} onClick={handleCancelEdit} onPointerDown={(e) => e.stopPropagation()} + onTouchStart={(e) => e.stopPropagation()} + onTouchEnd={(e) => { + e.stopPropagation() + e.preventDefault() + handleCancelEdit() + }} > Cancel @@ -723,6 +743,7 @@ export class TranscriptionShape extends BaseBoxShapeUtil { style={textareaStyle} placeholder="" onPointerDown={(e) => e.stopPropagation()} + onTouchStart={(e) => e.stopPropagation()} onWheel={handleWheel} /> ) : ( @@ -753,13 +774,13 @@ export class TranscriptionShape extends BaseBoxShapeUtil {