Skip to content

Commit 4456669

Browse files
Copilotalexr00
andauthored
Restore focus to comment textarea when PR description page regains focus (#8226)
* Initial plan * Initial plan for restoring focus to comment textarea Co-authored-by: alexr00 <38270282+alexr00@users.noreply.github.com> * Restore focus to comment textarea when description page regains focus Co-authored-by: alexr00 <38270282+alexr00@users.noreply.github.com> * Address code review feedback - add constant for sessionStorage key and improve comments Co-authored-by: alexr00 <38270282+alexr00@users.noreply.github.com> * Move constant to shared constants file to avoid duplication Co-authored-by: alexr00 <38270282+alexr00@users.noreply.github.com> * Simplify focus restoration - use window focus event instead of view state Co-authored-by: alexr00 <38270282+alexr00@users.noreply.github.com> * Extract magic number to named constant Co-authored-by: alexr00 <38270282+alexr00@users.noreply.github.com> * Extract 'comment-textarea' string literal to a constant Co-authored-by: alexr00 <38270282+alexr00@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: alexr00 <38270282+alexr00@users.noreply.github.com>
1 parent f5ee15f commit 4456669

4 files changed

Lines changed: 34 additions & 3 deletions

File tree

webviews/common/constants.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License. See License.txt in the project root for license information.
4+
*--------------------------------------------------------------------------------------------*/
5+
6+
/**
7+
* ID for the main comment textarea element in the PR description page.
8+
*/
9+
export const COMMENT_TEXTAREA_ID = 'comment-textarea';

webviews/common/context.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
import { createContext } from 'react';
77
import { getState, setState, updateState } from './cache';
8+
import { COMMENT_TEXTAREA_ID } from './constants';
89
import { getMessageHandler, MessageHandler } from './message';
910
import { CloseResult, OpenCommitChangesArgs } from '../../common/views';
1011
import { IComment } from '../../src/common/comment';
@@ -404,7 +405,7 @@ export class PRContext {
404405
window.scrollTo(message.scrollPosition.x, message.scrollPosition.y);
405406
return;
406407
case 'pr.scrollToPendingReview':
407-
const pendingReview = document.getElementById('pending-review') ?? document.getElementById('comment-textarea');
408+
const pendingReview = document.getElementById('pending-review') ?? document.getElementById(COMMENT_TEXTAREA_ID);
408409
if (pendingReview) {
409410
pendingReview.scrollIntoView();
410411
pendingReview.focus();

webviews/components/comment.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import { CommentEvent, EventType, ReviewEvent } from '../../src/common/timelineE
1414
import { GithubItemStateEnum } from '../../src/github/interface';
1515
import { PullRequest, ReviewType } from '../../src/github/views';
1616
import { ariaAnnouncementForReview } from '../common/aria';
17+
import { COMMENT_TEXTAREA_ID } from '../common/constants';
1718
import PullRequestContext from '../common/context';
1819
import emitter from '../common/events';
1920
import { useStateProp } from '../common/hooks';
@@ -435,7 +436,7 @@ export function AddComment({
435436
return (
436437
<form id="comment-form" ref={form as React.MutableRefObject<HTMLFormElement>} className="comment-form main-comment-form" >
437438
<textarea
438-
id="comment-textarea"
439+
id={COMMENT_TEXTAREA_ID}
439440
name="body"
440441
ref={textareaRef as React.MutableRefObject<HTMLTextAreaElement>}
441442
onInput={({ target }) => updatePR({ pendingCommentText: (target as HTMLTextAreaElement).value })}
@@ -602,7 +603,7 @@ export const AddCommentSimple = (pr: PullRequest) => {
602603
return (
603604
<span className="comment-form">
604605
<textarea
605-
id="comment-textarea"
606+
id={COMMENT_TEXTAREA_ID}
606607
name="body"
607608
placeholder="Leave a comment"
608609
ref={textareaRef as React.MutableRefObject<HTMLTextAreaElement>}

webviews/editorWebview/app.tsx

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import React, { useContext, useEffect, useState } from 'react';
88
import { render } from 'react-dom';
99
import { Overview } from './overview';
1010
import { PullRequest } from '../../src/github/views';
11+
import { COMMENT_TEXTAREA_ID } from '../common/constants';
1112
import PullRequestContext from '../common/context';
1213

1314
export function main() {
@@ -21,6 +22,25 @@ export function Root({ children }) {
2122
ctx.onchange = setPR;
2223
setPR(ctx.pr);
2324
}, []);
25+
26+
// Restore focus to comment textarea when window regains focus if user was typing
27+
useEffect(() => {
28+
const handleWindowFocus = () => {
29+
// Delay to let the focus event settle before checking focus state
30+
const FOCUS_SETTLE_DELAY_MS = 100;
31+
setTimeout(() => {
32+
const commentTextarea = document.getElementById(COMMENT_TEXTAREA_ID) as HTMLTextAreaElement;
33+
// Only restore focus if there's content and nothing else has focus
34+
if (commentTextarea && commentTextarea.value && document.activeElement === document.body) {
35+
commentTextarea.focus();
36+
}
37+
}, FOCUS_SETTLE_DELAY_MS);
38+
};
39+
40+
window.addEventListener('focus', handleWindowFocus);
41+
return () => window.removeEventListener('focus', handleWindowFocus);
42+
}, []);
43+
2444
window.onscroll = debounce(() => {
2545
ctx.postMessage({
2646
command: 'scroll',

0 commit comments

Comments
 (0)