Skip to content

Commit e5e59d0

Browse files
backnotpropclaude
andauthored
fix: preserve newlines in copy and add Cmd+C shortcut (#87)
* fix: use @plannotator/web-highlighter for proper newline handling - Switch from web-highlighter to @plannotator/web-highlighter@0.8.1 - Use source.text from highlighter (preserves newlines in cross-block selections) - Update dependency to ^0.8.1 which fixes exports field for bundlers Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * feat: add Cmd+C keyboard shortcut for copying selected text Closes #60 When text is selected and the annotation toolbar is visible, Cmd+C (Mac) or Ctrl+C (Windows/Linux) will copy the selected text with proper newlines preserved between block elements. This works because @plannotator/web-highlighter@0.8.1 now captures text using Selection.toString() which preserves newlines for cross-block selections. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: don't intercept Cmd+C in input/textarea fields Prevents the custom copy handler from intercepting Cmd+C when the user is focused in an input or textarea (e.g., annotation comment input). Previously, copying text from an input would copy the original plan selection instead. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 4ed4d15 commit e5e59d0

3 files changed

Lines changed: 36 additions & 9 deletions

File tree

bun.lock

Lines changed: 5 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/ui/components/Viewer.tsx

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import React, { useRef, useState, useEffect, forwardRef, useImperativeHandle, useCallback } from 'react';
2-
import Highlighter from 'web-highlighter';
2+
import Highlighter from '@plannotator/web-highlighter';
33
import hljs from 'highlight.js';
44
import 'highlight.js/styles/github-dark.css';
55
import { Block, Annotation, AnnotationType, EditorMode } from '../types';
@@ -137,6 +137,32 @@ export const Viewer = forwardRef<ViewerHandle, ViewerProps>(({
137137
onAddAnnotationRef.current = onAddAnnotation;
138138
}, [onAddAnnotation]);
139139

140+
// Cmd+C / Ctrl+C keyboard shortcut for copying selected text
141+
useEffect(() => {
142+
const handleKeyDown = async (e: KeyboardEvent) => {
143+
// Check for Cmd+C (Mac) or Ctrl+C (Windows/Linux)
144+
if ((e.metaKey || e.ctrlKey) && e.key === 'c') {
145+
// Don't intercept if typing in an input/textarea
146+
const tag = (e.target as HTMLElement)?.tagName;
147+
if (tag === 'INPUT' || tag === 'TEXTAREA') return;
148+
149+
// If we have an active selection with captured text, use that
150+
if (toolbarState?.selectionText) {
151+
e.preventDefault();
152+
try {
153+
await navigator.clipboard.writeText(toolbarState.selectionText);
154+
} catch (err) {
155+
console.error('Failed to copy:', err);
156+
}
157+
}
158+
// Otherwise let the browser handle default copy behavior
159+
}
160+
};
161+
162+
document.addEventListener('keydown', handleKeyDown);
163+
return () => document.removeEventListener('keydown', handleKeyDown);
164+
}, [toolbarState]);
165+
140166
// Helper to create annotation from highlighter source
141167
const createAnnotationFromSource = (
142168
highlighter: Highlighter,
@@ -433,8 +459,9 @@ export const Viewer = forwardRef<ViewerHandle, ViewerProps>(({
433459
window.getSelection()?.removeAllRanges();
434460
} else {
435461
// Show toolbar in selection mode
436-
// Capture selection text now (preserves line breaks between blocks)
437-
const selectionText = window.getSelection()?.toString() || source.text;
462+
// Use source.text from web-highlighter (complete text, captured before DOM modification)
463+
// Note: Selection.toString() would be truncated since web-highlighter already wrapped the selection
464+
const selectionText = source.text;
438465
pendingSourceRef.current = source;
439466
setToolbarState({ element: doms[0] as HTMLElement, source, selectionText });
440467
}

packages/ui/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,6 @@
1414
"react": "^19.2.3",
1515
"react-dom": "^19.2.3",
1616
"unique-username-generator": "^1.5.1",
17-
"web-highlighter": "^0.7.4"
17+
"@plannotator/web-highlighter": "^0.8.1"
1818
}
1919
}

0 commit comments

Comments
 (0)