Skip to content

Commit 1c5cf7a

Browse files
committed
Allow log message text selection
1 parent 9609e2b commit 1c5cf7a

1 file changed

Lines changed: 38 additions & 4 deletions

File tree

components/LoggerPanel.tsx

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -216,10 +216,35 @@ const LoggerPanel: React.FC<LoggerPanelProps> = ({ isVisible, onToggleVisibility
216216
}
217217
}, [formatLogForCopy, selectedCount, selectedLogs]);
218218

219+
const isTextSelectionTarget = useCallback((target: EventTarget | null) => {
220+
if (typeof window === 'undefined') {
221+
return false;
222+
}
223+
224+
const element = target as HTMLElement | null;
225+
return Boolean(element?.closest('[data-text-selectable="true"]'));
226+
}, []);
227+
228+
const hasActiveTextSelection = useCallback(() => {
229+
if (typeof window === 'undefined') {
230+
return false;
231+
}
232+
233+
const selection = window.getSelection();
234+
return Boolean(selection && selection.rangeCount > 0 && !selection.getRangeAt(0).collapsed);
235+
}, []);
236+
219237
const handleLogSelection = useCallback((event: React.MouseEvent<HTMLDivElement> | React.KeyboardEvent<HTMLDivElement>, logId: number, index: number) => {
220238
const { shiftKey, metaKey, ctrlKey } = event;
221239
const isMetaKey = metaKey || ctrlKey;
222240

241+
if ('nativeEvent' in event) {
242+
const target = event.nativeEvent.target as EventTarget | null;
243+
if (isTextSelectionTarget(target) && hasActiveTextSelection()) {
244+
return;
245+
}
246+
}
247+
223248
let nextSelection: Set<number>;
224249
if (shiftKey && selectionAnchor !== null) {
225250
const anchor = selectionAnchor ?? index;
@@ -244,7 +269,7 @@ const LoggerPanel: React.FC<LoggerPanelProps> = ({ isVisible, onToggleVisibility
244269
if (!shiftKey || selectionAnchor === null) {
245270
setSelectionAnchor(index);
246271
}
247-
}, [filteredLogs, selectedIds, selectionAnchor]);
272+
}, [filteredLogs, hasActiveTextSelection, isTextSelectionTarget, selectedIds, selectionAnchor]);
248273

249274
const handleLogKeyDown = useCallback((event: React.KeyboardEvent<HTMLDivElement>, logId: number, index: number) => {
250275
if (event.key === ' ' || event.key === 'Enter') {
@@ -276,14 +301,18 @@ const LoggerPanel: React.FC<LoggerPanelProps> = ({ isVisible, onToggleVisibility
276301

277302
const { shiftKey, metaKey, ctrlKey } = event;
278303

304+
if (isTextSelectionTarget(event.target)) {
305+
return;
306+
}
307+
279308
if (!(shiftKey || metaKey || ctrlKey)) {
280309
handleLogSelection(event, filteredLogs[index].id, index);
281310
event.preventDefault();
282311
setIsDragging(true);
283312
setDragStartIndex(index);
284313
setSelectionAnchor(index);
285314
}
286-
}, [filteredLogs, handleLogSelection]);
315+
}, [filteredLogs, handleLogSelection, isTextSelectionTarget]);
287316

288317
const handleLogMouseEnter = useCallback((index: number) => {
289318
if (!isDragging || dragStartIndex === null) {
@@ -434,11 +463,16 @@ const LoggerPanel: React.FC<LoggerPanelProps> = ({ isVisible, onToggleVisibility
434463
onKeyDown={(event) => handleLogKeyDown(event, log.id, index)}
435464
onMouseDown={(event) => handleLogMouseDown(event, index)}
436465
onMouseEnter={() => handleLogMouseEnter(index)}
437-
className={`flex items-start gap-2 rounded-md px-2 py-1.5 transition-colors cursor-pointer select-none border focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-primary ${isSelected ? 'bg-primary/15 border-primary/60 ring-1 ring-primary/50' : 'border-transparent hover:bg-border-color/40 focus-visible:bg-border-color/40'}`}
466+
className={`flex items-start gap-2 rounded-md px-2 py-1.5 transition-colors cursor-pointer border focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-primary ${isSelected ? 'bg-primary/15 border-primary/60 ring-1 ring-primary/50' : 'border-transparent hover:bg-border-color/40 focus-visible:bg-border-color/40'}`}
438467
>
439468
<span className={`${logLevelClasses[log.level].text} text-[10px] opacity-80`}>{renderHighlighted(log.timestamp)}</span>
440469
<span className={`px-1 py-0.5 rounded-full text-[10px] font-semibold border ${logLevelClasses[log.level].bg} ${logLevelClasses[log.level].border} ${logLevelClasses[log.level].text}`}>{log.level}</span>
441-
<span className={`flex-1 ${logLevelClasses[log.level].text} whitespace-pre-wrap break-words leading-relaxed`}>{renderHighlighted(log.message)}</span>
470+
<span
471+
data-text-selectable="true"
472+
className={`flex-1 ${logLevelClasses[log.level].text} whitespace-pre-wrap break-words leading-relaxed`}
473+
>
474+
{renderHighlighted(log.message)}
475+
</span>
442476
</div>
443477
);
444478
})}

0 commit comments

Comments
 (0)